Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/mcp/common/mcpConfiguration.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { MarkdownString } from '../../../../base/common/htmlContent.js';
7
import { IJSONSchema, IJSONSchemaMap } from '../../../../base/common/jsonSchema.js';
8
import { Disposable } from '../../../../base/common/lifecycle.js';
9
import { localize } from '../../../../nls.js';
10
import { IExtensionManifest, IMcpCollectionContribution } from '../../../../platform/extensions/common/extensions.js';
11
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
12
import { Registry } from '../../../../platform/registry/common/platform.js';
13
import { mcpSchemaId } from '../../../services/configuration/common/configuration.js';
14
import { inputsSchema } from '../../../services/configurationResolver/common/configurationResolverSchema.js';
15
import { Extensions, IExtensionFeaturesRegistry, IExtensionFeatureTableRenderer, IRenderedData, IRowData, ITableData } from '../../../services/extensionManagement/common/extensionFeatures.js';
16
import { IExtensionPointDescriptor } from '../../../services/extensions/common/extensionsRegistry.js';
17
18
const mcpActivationEventPrefix = 'onMcpCollection:';
19
20
/**
21
* note: `contributedCollectionId` is _not_ the collection ID. The collection
22
* ID is formed by passing the contributed ID through `extensionPrefixedIdentifier`
23
*/
24
export const mcpActivationEvent = (contributedCollectionId: string) =>
25
mcpActivationEventPrefix + contributedCollectionId;
26
27
export const enum DiscoverySource {
28
ClaudeDesktop = 'claude-desktop',
29
Windsurf = 'windsurf',
30
CursorGlobal = 'cursor-global',
31
CursorWorkspace = 'cursor-workspace',
32
}
33
34
export const allDiscoverySources = Object.keys({
35
[DiscoverySource.ClaudeDesktop]: true,
36
[DiscoverySource.Windsurf]: true,
37
[DiscoverySource.CursorGlobal]: true,
38
[DiscoverySource.CursorWorkspace]: true,
39
} satisfies Record<DiscoverySource, true>) as DiscoverySource[];
40
41
export const discoverySourceLabel: Record<DiscoverySource, string> = {
42
[DiscoverySource.ClaudeDesktop]: localize('mcp.discovery.source.claude-desktop', "Claude Desktop"),
43
[DiscoverySource.Windsurf]: localize('mcp.discovery.source.windsurf', "Windsurf"),
44
[DiscoverySource.CursorGlobal]: localize('mcp.discovery.source.cursor-global', "Cursor (Global)"),
45
[DiscoverySource.CursorWorkspace]: localize('mcp.discovery.source.cursor-workspace', "Cursor (Workspace)"),
46
};
47
export const discoverySourceSettingsLabel: Record<DiscoverySource, string> = {
48
[DiscoverySource.ClaudeDesktop]: localize('mcp.discovery.source.claude-desktop.config', "Claude Desktop configuration (`claude_desktop_config.json`)"),
49
[DiscoverySource.Windsurf]: localize('mcp.discovery.source.windsurf.config', "Windsurf configurations (`~/.codeium/windsurf/mcp_config.json`)"),
50
[DiscoverySource.CursorGlobal]: localize('mcp.discovery.source.cursor-global.config', "Cursor global configuration (`~/.cursor/mcp.json`)"),
51
[DiscoverySource.CursorWorkspace]: localize('mcp.discovery.source.cursor-workspace.config', "Cursor workspace configuration (`.cursor/mcp.json`)"),
52
};
53
54
export const mcpConfigurationSection = 'mcp';
55
export const mcpDiscoverySection = 'chat.mcp.discovery.enabled';
56
export const mcpServerSamplingSection = 'chat.mcp.serverSampling';
57
58
export interface IMcpServerSamplingConfiguration {
59
allowedDuringChat?: boolean;
60
allowedOutsideChat?: boolean;
61
allowedModels?: string[];
62
}
63
64
export const mcpSchemaExampleServers = {
65
'mcp-server-time': {
66
command: 'python',
67
args: ['-m', 'mcp_server_time', '--local-timezone=America/Los_Angeles'],
68
env: {},
69
}
70
};
71
72
const httpSchemaExamples = {
73
'my-mcp-server': {
74
url: 'http://localhost:3001/mcp',
75
headers: {},
76
}
77
};
78
79
const mcpDevModeProps = (stdio: boolean): IJSONSchemaMap => ({
80
dev: {
81
type: 'object',
82
markdownDescription: localize('app.mcp.dev', 'Enabled development mode for the server. When present, the server will be started eagerly and output will be included in its output. Properties inside the `dev` object can configure additional behavior.'),
83
examples: [{ watch: 'src/**/*.ts', debug: { type: 'node' } }],
84
properties: {
85
watch: {
86
description: localize('app.mcp.dev.watch', 'A glob pattern or list of glob patterns relative to the workspace folder to watch. The MCP server will be restarted when these files change.'),
87
examples: ['src/**/*.ts'],
88
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
89
},
90
...(stdio && {
91
debug: {
92
markdownDescription: localize('app.mcp.dev.debug', 'If set, debugs the MCP server using the given runtime as it\'s started.'),
93
oneOf: [
94
{
95
type: 'object',
96
required: ['type'],
97
properties: {
98
type: {
99
type: 'string',
100
enum: ['node'],
101
description: localize('app.mcp.dev.debug.type.node', "Debug the MCP server using Node.js.")
102
}
103
},
104
additionalProperties: false
105
},
106
{
107
type: 'object',
108
required: ['type'],
109
properties: {
110
type: {
111
type: 'string',
112
enum: ['debugpy'],
113
description: localize('app.mcp.dev.debug.type.python', "Debug the MCP server using Python and debugpy.")
114
},
115
debugpyPath: {
116
type: 'string',
117
description: localize('app.mcp.dev.debug.debugpyPath', "Path to the debugpy executable.")
118
},
119
},
120
additionalProperties: false
121
}
122
]
123
}
124
})
125
}
126
}
127
});
128
129
export const mcpStdioServerSchema: IJSONSchema = {
130
type: 'object',
131
additionalProperties: false,
132
examples: [mcpSchemaExampleServers['mcp-server-time']],
133
properties: {
134
type: {
135
type: 'string',
136
enum: ['stdio'],
137
description: localize('app.mcp.json.type', "The type of the server.")
138
},
139
command: {
140
type: 'string',
141
description: localize('app.mcp.json.command', "The command to run the server.")
142
},
143
cwd: {
144
type: 'string',
145
description: localize('app.mcp.json.cwd', "The working directory for the server command. Defaults to the workspace folder when run in a workspace."),
146
examples: ['${workspaceFolder}'],
147
},
148
args: {
149
type: 'array',
150
description: localize('app.mcp.args.command', "Arguments passed to the server."),
151
items: {
152
type: 'string'
153
},
154
},
155
envFile: {
156
type: 'string',
157
description: localize('app.mcp.envFile.command', "Path to a file containing environment variables for the server."),
158
examples: ['${workspaceFolder}/.env'],
159
},
160
env: {
161
description: localize('app.mcp.env.command', "Environment variables passed to the server."),
162
additionalProperties: {
163
anyOf: [
164
{ type: 'null' },
165
{ type: 'string' },
166
{ type: 'number' },
167
]
168
}
169
},
170
...mcpDevModeProps(true),
171
}
172
};
173
174
export const mcpServerSchema: IJSONSchema = {
175
id: mcpSchemaId,
176
type: 'object',
177
title: localize('app.mcp.json.title', "Model Context Protocol Servers"),
178
allowTrailingCommas: true,
179
allowComments: true,
180
additionalProperties: false,
181
properties: {
182
servers: {
183
examples: [
184
mcpSchemaExampleServers,
185
httpSchemaExamples,
186
],
187
additionalProperties: {
188
oneOf: [
189
mcpStdioServerSchema, {
190
type: 'object',
191
additionalProperties: false,
192
required: ['url'],
193
examples: [httpSchemaExamples['my-mcp-server']],
194
properties: {
195
type: {
196
type: 'string',
197
enum: ['http', 'sse'],
198
description: localize('app.mcp.json.type', "The type of the server.")
199
},
200
url: {
201
type: 'string',
202
format: 'uri',
203
pattern: '^https?:\\/\\/.+',
204
patternErrorMessage: localize('app.mcp.json.url.pattern', "The URL must start with 'http://' or 'https://'."),
205
description: localize('app.mcp.json.url', "The URL of the Streamable HTTP or SSE endpoint.")
206
},
207
headers: {
208
type: 'object',
209
description: localize('app.mcp.json.headers', "Additional headers sent to the server."),
210
additionalProperties: { type: 'string' },
211
},
212
...mcpDevModeProps(false),
213
}
214
},
215
]
216
}
217
},
218
inputs: inputsSchema.definitions!.inputs
219
}
220
};
221
222
export const mcpContributionPoint: IExtensionPointDescriptor<IMcpCollectionContribution[]> = {
223
extensionPoint: 'mcpServerDefinitionProviders',
224
activationEventsGenerator(contribs, result) {
225
for (const contrib of contribs) {
226
if (contrib.id) {
227
result.push(mcpActivationEvent(contrib.id));
228
}
229
}
230
},
231
jsonSchema: {
232
description: localize('vscode.extension.contributes.mcp', 'Contributes Model Context Protocol servers. Users of this should also use `vscode.lm.registerMcpServerDefinitionProvider`.'),
233
type: 'array',
234
defaultSnippets: [{ body: [{ id: '', label: '' }] }],
235
items: {
236
additionalProperties: false,
237
type: 'object',
238
defaultSnippets: [{ body: { id: '', label: '' } }],
239
properties: {
240
id: {
241
description: localize('vscode.extension.contributes.mcp.id', "Unique ID for the collection."),
242
type: 'string'
243
},
244
label: {
245
description: localize('vscode.extension.contributes.mcp.label', "Display name for the collection."),
246
type: 'string'
247
}
248
}
249
}
250
}
251
};
252
253
class McpServerDefinitionsProviderRenderer extends Disposable implements IExtensionFeatureTableRenderer {
254
255
readonly type = 'table';
256
257
shouldRender(manifest: IExtensionManifest): boolean {
258
return !!manifest.contributes?.mcpServerDefinitionProviders && Array.isArray(manifest.contributes.mcpServerDefinitionProviders) && manifest.contributes.mcpServerDefinitionProviders.length > 0;
259
}
260
261
render(manifest: IExtensionManifest): IRenderedData<ITableData> {
262
const mcpServerDefinitionProviders = manifest.contributes?.mcpServerDefinitionProviders ?? [];
263
const headers = [localize('id', "ID"), localize('name', "Name")];
264
const rows: IRowData[][] = mcpServerDefinitionProviders
265
.map(mcpServerDefinitionProvider => {
266
return [
267
new MarkdownString().appendMarkdown(`\`${mcpServerDefinitionProvider.id}\``),
268
mcpServerDefinitionProvider.label
269
];
270
});
271
272
return {
273
data: {
274
headers,
275
rows
276
},
277
dispose: () => { }
278
};
279
}
280
}
281
282
Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({
283
id: mcpConfigurationSection,
284
label: localize('mcpServerDefinitionProviders', "MCP Servers"),
285
access: {
286
canToggle: false
287
},
288
renderer: new SyncDescriptor(McpServerDefinitionsProviderRenderer),
289
});
290
291
292