@codingame/monaco-vscode-mcp-service-override 36.2.7 → 37.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/vscode/src/vs/base/common/jsonRpcProtocol.d.ts +2 -2
- package/vscode/src/vs/platform/mcp/common/allowedMcpServers.d.ts +52 -0
- package/vscode/src/vs/platform/mcp/common/allowedMcpServers.js +180 -0
- package/vscode/src/vs/platform/mcp/common/allowedMcpServersService.d.ts +4 -0
- package/vscode/src/vs/platform/mcp/common/allowedMcpServersService.js +68 -12
- package/vscode/src/vs/platform/mcp/common/mcpGalleryService.d.ts +5 -1
- package/vscode/src/vs/platform/mcp/common/mcpGalleryService.js +200 -92
- package/vscode/src/vs/platform/mcp/common/mcpResourceScannerService.js +3 -2
- package/vscode/src/vs/platform/mcp/common/nativeMcpDiscoveryHelper.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcp.contribution.js +3 -3
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpAddContextContribution.js +2 -2
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpCommands.d.ts +10 -3
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpCommands.js +357 -121
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpElicitationService.js +25 -25
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.d.ts +11 -1
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.js +409 -145
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpMigration.js +4 -4
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.js +8 -8
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditor.js +37 -37
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditorInput.js +2 -2
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerIcons.js +5 -5
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerWidgets.js +5 -5
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServersView.js +18 -18
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.d.ts +12 -0
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.js +279 -72
- package/vscode/src/vs/workbench/contrib/mcp/browser/media/mcpServersView.css +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/extensionMcpDiscovery.js +6 -5
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/installedMcpServersDiscovery.js +9 -16
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.d.ts +4 -4
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.js +7 -3
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.d.ts +14 -6
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.js +32 -9
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceDotMcpDiscovery.d.ts +2 -2
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceDotMcpDiscovery.js +20 -6
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceMcpDiscoveryAdapter.js +9 -5
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpContextKeys.js +4 -4
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpEditorAffordanceState.d.ts +13 -0
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpEditorAffordanceState.js +36 -0
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpLanguageModelToolContribution.js +6 -6
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.js +51 -19
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingLog.js +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingService.js +11 -11
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpSandboxService.d.ts +4 -0
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpSandboxService.js +42 -6
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.js +3 -3
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpService.js +6 -3
- package/vscode/src/vs/workbench/services/authentication/browser/authenticationMcpService.js +9 -9
|
@@ -5,6 +5,7 @@ import { MarkdownString, createCommandUri } from '@codingame/monaco-vscode-api/v
|
|
|
5
5
|
import { Disposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
|
|
6
6
|
import { Schemas } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
|
|
7
7
|
import { basename } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
|
|
8
|
+
import { isObject, isString, isBoolean, isStringArray, isNumber } from '@codingame/monaco-vscode-api/vscode/vs/base/common/types';
|
|
8
9
|
import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
|
|
9
10
|
import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
|
|
10
11
|
import { ConfigurationTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration';
|
|
@@ -14,7 +15,7 @@ import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/fi
|
|
|
14
15
|
import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
|
|
15
16
|
import { ILabelService } from '@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service';
|
|
16
17
|
import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
|
|
17
|
-
import { mcpAccessConfig, McpAccessValue } from '@codingame/monaco-vscode-api/vscode/vs/platform/mcp/common/mcpManagement';
|
|
18
|
+
import { mcpAccessConfig, McpGalleryResolveStatus, McpAccessValue } from '@codingame/monaco-vscode-api/vscode/vs/platform/mcp/common/mcpManagement';
|
|
18
19
|
import { IMcpGalleryService, IAllowedMcpServersService } from '@codingame/monaco-vscode-api/vscode/vs/platform/mcp/common/mcpManagement.service';
|
|
19
20
|
import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service';
|
|
20
21
|
import { McpServerType } from '@codingame/monaco-vscode-api/vscode/vs/platform/mcp/common/mcpPlatformTypes';
|
|
@@ -40,10 +41,153 @@ import { IMcpGalleryManifestService } from '@codingame/monaco-vscode-api/vscode/
|
|
|
40
41
|
import { IExtensionsWorkbenchService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/extensions/common/extensions.service';
|
|
41
42
|
import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
|
|
42
43
|
import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity';
|
|
43
|
-
import {
|
|
44
|
+
import { ThrottledDelayer } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
|
|
44
45
|
import { runOnChange } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/utils/runOnChange';
|
|
45
46
|
import { autorun } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/reactions/autorun';
|
|
46
47
|
|
|
48
|
+
function parseMcpInstallUriPayload(query) {
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(decodeURIComponent(query));
|
|
52
|
+
} catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
if (!isObject(parsed)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const payload = parsed;
|
|
59
|
+
if (!isString(payload.name) || !payload.name) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const config = sanitizeMcpServerConfiguration(payload);
|
|
63
|
+
if (!config) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
name: payload.name,
|
|
68
|
+
config,
|
|
69
|
+
inputs: Array.isArray(payload.inputs) ? payload.inputs : undefined
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function sanitizeMcpServerConfiguration(payload) {
|
|
73
|
+
const type = payload.type === McpServerType.LOCAL || payload.type === McpServerType.REMOTE ? payload.type : isString(payload.command) ? McpServerType.LOCAL : McpServerType.REMOTE;
|
|
74
|
+
const dev = sanitizeMcpDevModeConfig(payload.dev);
|
|
75
|
+
const common = {
|
|
76
|
+
...(isString(payload.version) ? {
|
|
77
|
+
version: payload.version
|
|
78
|
+
} : {}),
|
|
79
|
+
...(isBoolean(payload.gallery) || isString(payload.gallery) ? {
|
|
80
|
+
gallery: payload.gallery
|
|
81
|
+
} : {}),
|
|
82
|
+
...(dev ? {
|
|
83
|
+
dev
|
|
84
|
+
} : {})
|
|
85
|
+
};
|
|
86
|
+
if (type === McpServerType.LOCAL) {
|
|
87
|
+
if (!isString(payload.command)) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const env = sanitizeMcpEnvironment(payload.env);
|
|
91
|
+
return {
|
|
92
|
+
type,
|
|
93
|
+
command: payload.command,
|
|
94
|
+
...common,
|
|
95
|
+
...(isStringArray(payload.args) ? {
|
|
96
|
+
args: payload.args
|
|
97
|
+
} : {}),
|
|
98
|
+
...(env ? {
|
|
99
|
+
env
|
|
100
|
+
} : {}),
|
|
101
|
+
...(isString(payload.envFile) ? {
|
|
102
|
+
envFile: payload.envFile
|
|
103
|
+
} : {}),
|
|
104
|
+
...(isString(payload.cwd) ? {
|
|
105
|
+
cwd: payload.cwd
|
|
106
|
+
} : {}),
|
|
107
|
+
...(isBoolean(payload.sandboxEnabled) ? {
|
|
108
|
+
sandboxEnabled: payload.sandboxEnabled
|
|
109
|
+
} : {})
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (!isString(payload.url)) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const headers = sanitizeStringRecord(payload.headers);
|
|
116
|
+
const oauth = sanitizeMcpOAuthConfiguration(payload.oauth);
|
|
117
|
+
return {
|
|
118
|
+
type,
|
|
119
|
+
url: payload.url,
|
|
120
|
+
...common,
|
|
121
|
+
...(payload.transport === "http" || payload.transport === "sse" ? {
|
|
122
|
+
transport: payload.transport
|
|
123
|
+
} : {}),
|
|
124
|
+
...(headers ? {
|
|
125
|
+
headers
|
|
126
|
+
} : {}),
|
|
127
|
+
...(oauth ? {
|
|
128
|
+
oauth
|
|
129
|
+
} : {})
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function sanitizeMcpDevModeConfig(value) {
|
|
133
|
+
if (!isObject(value)) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const payload = value;
|
|
137
|
+
const debug = sanitizeMcpDevModeDebugConfiguration(payload.debug);
|
|
138
|
+
if (!isString(payload.watch) && !isStringArray(payload.watch) && !debug) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
...(isString(payload.watch) || isStringArray(payload.watch) ? {
|
|
143
|
+
watch: payload.watch
|
|
144
|
+
} : {}),
|
|
145
|
+
...(debug ? {
|
|
146
|
+
debug
|
|
147
|
+
} : {})
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function sanitizeMcpDevModeDebugConfiguration(value) {
|
|
151
|
+
if (!isObject(value)) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const payload = value;
|
|
155
|
+
if (payload.type === "node") {
|
|
156
|
+
return {
|
|
157
|
+
type: "node"
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (payload.type === "debugpy") {
|
|
161
|
+
return {
|
|
162
|
+
type: "debugpy",
|
|
163
|
+
...(isString(payload.debugpyPath) ? {
|
|
164
|
+
debugpyPath: payload.debugpyPath
|
|
165
|
+
} : {})
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
function sanitizeMcpEnvironment(value) {
|
|
171
|
+
return sanitizeRecord(value, entry => entry === null || isString(entry) || isNumber(entry));
|
|
172
|
+
}
|
|
173
|
+
function sanitizeStringRecord(value) {
|
|
174
|
+
return sanitizeRecord(value, isString);
|
|
175
|
+
}
|
|
176
|
+
function sanitizeRecord(value, isValidValue) {
|
|
177
|
+
if (!isObject(value)) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
return Object.fromEntries(Object.entries(value).filter(entry => isValidValue(entry[1])));
|
|
181
|
+
}
|
|
182
|
+
function sanitizeMcpOAuthConfiguration(value) {
|
|
183
|
+
if (!isObject(value)) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
const payload = value;
|
|
187
|
+
return isString(payload.clientId) ? {
|
|
188
|
+
clientId: payload.clientId
|
|
189
|
+
} : undefined;
|
|
190
|
+
}
|
|
47
191
|
let McpWorkbenchServer = class McpWorkbenchServer {
|
|
48
192
|
constructor(
|
|
49
193
|
installStateProvider,
|
|
@@ -178,6 +322,12 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
178
322
|
this.installing = [];
|
|
179
323
|
this.uninstalling = [];
|
|
180
324
|
this._local = [];
|
|
325
|
+
this.registrySyncGeneration = 0;
|
|
326
|
+
this.registryGeneration = 0;
|
|
327
|
+
this.localQueryGeneration = 0;
|
|
328
|
+
this.profileChangeGeneration = 0;
|
|
329
|
+
this.gallerySourceGenerations = ( new WeakMap());
|
|
330
|
+
this.registrySyncDelayer = this._register(( new ThrottledDelayer(0)));
|
|
181
331
|
this._onChange = this._register(( new Emitter()));
|
|
182
332
|
this.onChange = this._onChange.event;
|
|
183
333
|
this._onReset = this._register(( new Emitter()));
|
|
@@ -194,16 +344,16 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
194
344
|
this._register(
|
|
195
345
|
this.mcpManagementService.onDidChangeProfile(e => this.onDidChangeProfile())
|
|
196
346
|
);
|
|
197
|
-
this.queryLocal().then(() => {
|
|
347
|
+
this.whenInitialLocalMcpServersLoaded = this.queryLocal().then(() => {
|
|
198
348
|
if (this._store.isDisposed) {
|
|
199
349
|
return;
|
|
200
350
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
});
|
|
351
|
+
this._register(mcpGalleryManifestService.onDidChangeMcpGalleryManifest(() => {
|
|
352
|
+
this.invalidateRegistryVerification();
|
|
353
|
+
this.scheduleRegistrySync();
|
|
354
|
+
}));
|
|
355
|
+
this.scheduleRegistrySync();
|
|
356
|
+
}, error => this.logService.error(error));
|
|
207
357
|
urlService.registerHandler(this);
|
|
208
358
|
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
|
209
359
|
if (e.affectsConfiguration(mcpAccessConfig)) {
|
|
@@ -226,9 +376,23 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
226
376
|
}));
|
|
227
377
|
}
|
|
228
378
|
async onDidChangeProfile() {
|
|
229
|
-
|
|
230
|
-
this.
|
|
379
|
+
const profileChangeGeneration = ++this.profileChangeGeneration;
|
|
380
|
+
const generation = ++this.localQueryGeneration;
|
|
381
|
+
this.invalidateRegistryVerification();
|
|
382
|
+
await this.queryLocalForGeneration(generation);
|
|
383
|
+
if (profileChangeGeneration !== this.profileChangeGeneration) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
231
386
|
this._onReset.fire();
|
|
387
|
+
this.scheduleRegistrySync();
|
|
388
|
+
}
|
|
389
|
+
invalidateRegistryVerification() {
|
|
390
|
+
this.registryGeneration++;
|
|
391
|
+
this.registrySyncGeneration++;
|
|
392
|
+
for (const server of this._local) {
|
|
393
|
+
server.gallery = undefined;
|
|
394
|
+
}
|
|
395
|
+
this._onChange.fire(undefined);
|
|
232
396
|
}
|
|
233
397
|
areSameMcpServers(a, b) {
|
|
234
398
|
if (a === b) {
|
|
@@ -250,17 +414,18 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
250
414
|
}
|
|
251
415
|
}
|
|
252
416
|
onDidInstallMcpServers(e) {
|
|
253
|
-
|
|
417
|
+
let needsRegistrySync = false;
|
|
254
418
|
for (const {
|
|
255
419
|
local,
|
|
256
|
-
|
|
257
|
-
|
|
420
|
+
name,
|
|
421
|
+
source
|
|
258
422
|
} of e) {
|
|
259
423
|
let server = this.installing.find(
|
|
260
424
|
server => server.local && local ? this.areSameMcpServers(server.local, local) : server.name === name
|
|
261
425
|
);
|
|
262
426
|
this.installing = server ? this.installing.filter(e => e !== server) : this.installing;
|
|
263
427
|
if (local) {
|
|
428
|
+
const trustedGallery = this.getTrustedGallerySource(source) ?? this.getTrustedGallerySource(server?.gallery);
|
|
264
429
|
if (server) {
|
|
265
430
|
server.local = local;
|
|
266
431
|
} else {
|
|
@@ -269,23 +434,23 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
269
434
|
e => this.getInstallState(e),
|
|
270
435
|
e => this.getRuntimeStatus(e),
|
|
271
436
|
local,
|
|
272
|
-
|
|
437
|
+
undefined,
|
|
273
438
|
undefined
|
|
274
439
|
);
|
|
275
440
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
441
|
+
server.gallery = trustedGallery?.name === local.name ? trustedGallery : undefined;
|
|
442
|
+
needsRegistrySync = true;
|
|
279
443
|
this._local = this._local.filter(server => !this.areSameMcpServers(server.local, local));
|
|
280
444
|
this.addServer(server);
|
|
281
445
|
}
|
|
282
446
|
this._onChange.fire(server);
|
|
283
447
|
}
|
|
284
|
-
if (
|
|
285
|
-
this.
|
|
448
|
+
if (needsRegistrySync) {
|
|
449
|
+
this.scheduleRegistrySync();
|
|
286
450
|
}
|
|
287
451
|
}
|
|
288
452
|
onDidUpdateMcpServers(e) {
|
|
453
|
+
let needsRegistrySync = false;
|
|
289
454
|
for (const result of e) {
|
|
290
455
|
if (!result.local) {
|
|
291
456
|
continue;
|
|
@@ -301,61 +466,89 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
301
466
|
e => this.getInstallState(e),
|
|
302
467
|
e => this.getRuntimeStatus(e),
|
|
303
468
|
result.local,
|
|
304
|
-
|
|
469
|
+
undefined,
|
|
305
470
|
undefined
|
|
306
471
|
);
|
|
307
472
|
this.addServer(server);
|
|
308
473
|
}
|
|
474
|
+
const trustedGallery = this.getTrustedGallerySource(result.source) ?? this.getTrustedGallerySource(server.gallery);
|
|
475
|
+
server.gallery = trustedGallery?.name === result.local.name ? trustedGallery : undefined;
|
|
476
|
+
needsRegistrySync = true;
|
|
309
477
|
this._onChange.fire(server);
|
|
310
478
|
}
|
|
479
|
+
if (needsRegistrySync) {
|
|
480
|
+
this.scheduleRegistrySync();
|
|
481
|
+
}
|
|
311
482
|
}
|
|
312
|
-
fromGallery(gallery) {
|
|
483
|
+
fromGallery(gallery, registryGeneration) {
|
|
484
|
+
this.rememberGallerySource(gallery, registryGeneration);
|
|
313
485
|
for (const local of this._local) {
|
|
314
486
|
if (local.name === gallery.name) {
|
|
315
|
-
local.gallery = gallery;
|
|
316
487
|
return local;
|
|
317
488
|
}
|
|
318
489
|
}
|
|
319
490
|
return undefined;
|
|
320
491
|
}
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
492
|
+
scheduleRegistrySync() {
|
|
493
|
+
const generation = ++this.registrySyncGeneration;
|
|
494
|
+
void this.registrySyncDelayer.trigger(() => this.syncInstalledMcpServers(generation)).catch(error => this.logService.error(error));
|
|
495
|
+
}
|
|
496
|
+
async syncInstalledMcpServers(generation) {
|
|
497
|
+
if (!this.mcpGalleryService.isEnabled()) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const servers = this.local.flatMap(server => server.local ? [{
|
|
501
|
+
server,
|
|
502
|
+
local: server.local
|
|
503
|
+
}] : []);
|
|
504
|
+
const infosByName = ( new Map());
|
|
505
|
+
for (const {
|
|
506
|
+
local
|
|
507
|
+
} of servers) {
|
|
508
|
+
const existing = infosByName.get(local.name);
|
|
509
|
+
if (!existing || (!existing.id && local.galleryId)) {
|
|
510
|
+
infosByName.set(local.name, {
|
|
511
|
+
name: local.name,
|
|
512
|
+
id: local.galleryId
|
|
331
513
|
});
|
|
332
514
|
}
|
|
333
515
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
516
|
+
const infos = [...( infosByName.values())];
|
|
517
|
+
if (!infos.length) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const resolved = await this.mcpGalleryService.resolveMcpServersFromGallery(infos);
|
|
521
|
+
if (generation !== this.registrySyncGeneration) {
|
|
522
|
+
return;
|
|
337
523
|
}
|
|
524
|
+
this.syncInstalledMcpServersWithGallery(resolved, servers, generation);
|
|
338
525
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
526
|
+
syncInstalledMcpServersWithGallery(resolved, servers, generation) {
|
|
527
|
+
for (const {
|
|
528
|
+
server: mcpServer,
|
|
529
|
+
local
|
|
530
|
+
} of servers) {
|
|
531
|
+
if (generation !== this.registrySyncGeneration || !this._local.includes(mcpServer) || mcpServer.local !== local) {
|
|
343
532
|
continue;
|
|
344
533
|
}
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
534
|
+
const result = resolved.get(local.name);
|
|
535
|
+
if (!result || result.status === McpGalleryResolveStatus.Failed) {
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (result.status === McpGalleryResolveStatus.NotFound) {
|
|
348
539
|
if (mcpServer.gallery) {
|
|
349
540
|
mcpServer.gallery = undefined;
|
|
350
541
|
this._onChange.fire(mcpServer);
|
|
351
542
|
}
|
|
352
543
|
continue;
|
|
353
544
|
}
|
|
545
|
+
const gallery = result.server;
|
|
546
|
+
const changed = mcpServer.gallery !== gallery;
|
|
547
|
+
this.rememberGallerySource(gallery);
|
|
354
548
|
mcpServer.gallery = gallery;
|
|
355
|
-
if (
|
|
356
|
-
|
|
549
|
+
if (changed) {
|
|
550
|
+
this._onChange.fire(mcpServer);
|
|
357
551
|
}
|
|
358
|
-
this._onChange.fire(mcpServer);
|
|
359
552
|
}
|
|
360
553
|
}
|
|
361
554
|
async queryGallery(options, token) {
|
|
@@ -371,10 +564,11 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
371
564
|
})
|
|
372
565
|
};
|
|
373
566
|
}
|
|
567
|
+
const registryGeneration = this.registryGeneration;
|
|
374
568
|
const pager = await this.mcpGalleryService.query(options, token);
|
|
375
569
|
const mapPage = page => ({
|
|
376
570
|
items: ( page.items.map(
|
|
377
|
-
gallery => this.fromGallery(gallery) ?? this.instantiationService.createInstance(
|
|
571
|
+
gallery => this.fromGallery(gallery, registryGeneration) ?? this.instantiationService.createInstance(
|
|
378
572
|
McpWorkbenchServer,
|
|
379
573
|
e => this.getInstallState(e),
|
|
380
574
|
e => this.getRuntimeStatus(e),
|
|
@@ -394,7 +588,14 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
394
588
|
};
|
|
395
589
|
}
|
|
396
590
|
async queryLocal() {
|
|
591
|
+
await this.queryLocalForGeneration(++this.localQueryGeneration);
|
|
592
|
+
return [...this.local];
|
|
593
|
+
}
|
|
594
|
+
async queryLocalForGeneration(generation) {
|
|
397
595
|
const installed = await this.mcpManagementService.getInstalled();
|
|
596
|
+
if (generation !== this.localQueryGeneration) {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
398
599
|
this._local = this.sort(( installed.map(i => {
|
|
399
600
|
const existing = this._local.find(local => local.id === i.id);
|
|
400
601
|
const local = existing ?? this.instantiationService.createInstance(
|
|
@@ -409,7 +610,15 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
409
610
|
return local;
|
|
410
611
|
})));
|
|
411
612
|
this._onChange.fire(undefined);
|
|
412
|
-
return
|
|
613
|
+
return true;
|
|
614
|
+
}
|
|
615
|
+
rememberGallerySource(gallery, registryGeneration = this.registryGeneration) {
|
|
616
|
+
if (registryGeneration === this.registryGeneration) {
|
|
617
|
+
this.gallerySourceGenerations.set(gallery, registryGeneration);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
getTrustedGallerySource(gallery) {
|
|
621
|
+
return gallery && this.gallerySourceGenerations.get(gallery) === this.registryGeneration ? gallery : undefined;
|
|
413
622
|
}
|
|
414
623
|
addServer(server) {
|
|
415
624
|
this._local.push(server);
|
|
@@ -418,13 +627,12 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
418
627
|
sort(local) {
|
|
419
628
|
return local.sort((a, b) => {
|
|
420
629
|
if (a.name === b.name) {
|
|
421
|
-
|
|
422
|
-
|
|
630
|
+
const aEnabled = !a.runtimeStatus || a.runtimeStatus.state === McpServerEnablementState.Enabled;
|
|
631
|
+
const bEnabled = !b.runtimeStatus || b.runtimeStatus.state === McpServerEnablementState.Enabled;
|
|
632
|
+
if (aEnabled !== bEnabled) {
|
|
633
|
+
return aEnabled ? -1 : 1;
|
|
423
634
|
}
|
|
424
|
-
|
|
425
|
-
return 1;
|
|
426
|
-
}
|
|
427
|
-
return 0;
|
|
635
|
+
return a.id.localeCompare(b.id);
|
|
428
636
|
}
|
|
429
637
|
return a.name.localeCompare(b.name);
|
|
430
638
|
});
|
|
@@ -450,7 +658,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
450
658
|
const existing = result.get(server.name);
|
|
451
659
|
if (existing) {
|
|
452
660
|
this.logService.warn(( localize(
|
|
453
|
-
|
|
661
|
+
14052,
|
|
454
662
|
"Overwriting mcp server '{0}' from {1} with {2}.",
|
|
455
663
|
server.name,
|
|
456
664
|
server.mcpResource.path,
|
|
@@ -463,7 +671,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
463
671
|
const existing = result.get(server.name);
|
|
464
672
|
if (existing) {
|
|
465
673
|
this.logService.warn(( localize(
|
|
466
|
-
|
|
674
|
+
14052,
|
|
467
675
|
"Overwriting mcp server '{0}' from {1} with {2}.",
|
|
468
676
|
server.name,
|
|
469
677
|
server.mcpResource.path,
|
|
@@ -476,7 +684,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
476
684
|
}
|
|
477
685
|
canInstall(mcpServer) {
|
|
478
686
|
if (!(mcpServer instanceof McpWorkbenchServer)) {
|
|
479
|
-
return ( new MarkdownString()).appendText(( localize(
|
|
687
|
+
return ( new MarkdownString()).appendText(( localize(14053, "The provided object is not an mcp server.")));
|
|
480
688
|
}
|
|
481
689
|
if (mcpServer.gallery) {
|
|
482
690
|
const result = this.mcpManagementService.canInstall(mcpServer.gallery);
|
|
@@ -493,7 +701,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
493
701
|
return result;
|
|
494
702
|
}
|
|
495
703
|
return ( new MarkdownString()).appendText(( localize(
|
|
496
|
-
|
|
704
|
+
14054,
|
|
497
705
|
"Cannot install the '{0}' MCP Server because it is not available in this setup.",
|
|
498
706
|
mcpServer.label
|
|
499
707
|
)));
|
|
@@ -600,7 +808,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
600
808
|
id: USER_CONFIG_ID,
|
|
601
809
|
key: "userLocalValue",
|
|
602
810
|
target: ConfigurationTarget.USER_LOCAL,
|
|
603
|
-
label: ( localize(
|
|
811
|
+
label: ( localize(14055, "Global in {0}", this.productService.nameShort)),
|
|
604
812
|
scope: StorageScope.PROFILE,
|
|
605
813
|
order: McpCollectionSortOrder.User,
|
|
606
814
|
uri: mcpResource,
|
|
@@ -676,24 +884,24 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
676
884
|
return false;
|
|
677
885
|
}
|
|
678
886
|
async handleMcpInstallUri(uri) {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
parsed = JSON.parse(decodeURIComponent(uri.query));
|
|
682
|
-
} catch (e) {
|
|
887
|
+
const parsed = parseMcpInstallUriPayload(uri.query);
|
|
888
|
+
if (!parsed) {
|
|
683
889
|
return false;
|
|
684
890
|
}
|
|
685
891
|
try {
|
|
686
892
|
const {
|
|
687
893
|
name,
|
|
688
894
|
inputs,
|
|
689
|
-
|
|
895
|
+
config
|
|
690
896
|
} = parsed;
|
|
691
897
|
if (config.gallery && this.mcpGalleryService.isEnabled()) {
|
|
692
898
|
try {
|
|
899
|
+
const registryGeneration = this.registryGeneration;
|
|
693
900
|
const [galleryServer] = await this.mcpGalleryService.getMcpServersFromGallery([{
|
|
694
901
|
name
|
|
695
902
|
}]);
|
|
696
903
|
if (galleryServer) {
|
|
904
|
+
this.rememberGallerySource(galleryServer, registryGeneration);
|
|
697
905
|
const local = this.local.find(e => e.name === galleryServer.name) ?? this.instantiationService.createInstance(
|
|
698
906
|
McpWorkbenchServer,
|
|
699
907
|
e => this.getInstallState(e),
|
|
@@ -712,9 +920,6 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
712
920
|
);
|
|
713
921
|
}
|
|
714
922
|
}
|
|
715
|
-
if (config.type === undefined) {
|
|
716
|
-
config.type = parsed.command ? McpServerType.LOCAL : McpServerType.REMOTE;
|
|
717
|
-
}
|
|
718
923
|
this.open(this.instantiationService.createInstance(
|
|
719
924
|
McpWorkbenchServer,
|
|
720
925
|
e => this.getInstallState(e),
|
|
@@ -753,6 +958,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
753
958
|
}
|
|
754
959
|
async handleMcpServerByName(name) {
|
|
755
960
|
try {
|
|
961
|
+
const registryGeneration = this.registryGeneration;
|
|
756
962
|
const [gallery] = await this.mcpGalleryService.getMcpServersFromGallery([{
|
|
757
963
|
name
|
|
758
964
|
}]);
|
|
@@ -760,6 +966,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
760
966
|
this.logService.info(`MCP server '${name}' not found`);
|
|
761
967
|
return true;
|
|
762
968
|
}
|
|
969
|
+
this.rememberGallerySource(gallery, registryGeneration);
|
|
763
970
|
const local = this.local.find(e => e.name === gallery.name) ?? this.instantiationService.createInstance(
|
|
764
971
|
McpWorkbenchServer,
|
|
765
972
|
e => this.getInstallState(e),
|
|
@@ -812,7 +1019,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
812
1019
|
state: McpServerEnablementState.DisabledProfile,
|
|
813
1020
|
message: {
|
|
814
1021
|
severity: Severity.Info,
|
|
815
|
-
text: ( new MarkdownString(( localize(
|
|
1022
|
+
text: ( new MarkdownString(( localize(14056, "This MCP server is disabled."))))
|
|
816
1023
|
}
|
|
817
1024
|
};
|
|
818
1025
|
}
|
|
@@ -821,7 +1028,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
821
1028
|
state: McpServerEnablementState.DisabledWorkspace,
|
|
822
1029
|
message: {
|
|
823
1030
|
severity: Severity.Info,
|
|
824
|
-
text: ( new MarkdownString(( localize(
|
|
1031
|
+
text: ( new MarkdownString(( localize(14057, "This MCP server is disabled for this workspace."))))
|
|
825
1032
|
}
|
|
826
1033
|
};
|
|
827
1034
|
}
|
|
@@ -841,7 +1048,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
841
1048
|
message: {
|
|
842
1049
|
severity: Severity.Warning,
|
|
843
1050
|
text: ( new MarkdownString(( localize(
|
|
844
|
-
|
|
1051
|
+
14058,
|
|
845
1052
|
"This MCP Server is disabled because MCP servers are configured to be disabled in the Editor. Please check your [settings]({0}).",
|
|
846
1053
|
settingsCommandLink
|
|
847
1054
|
))))
|
|
@@ -855,7 +1062,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
855
1062
|
message: {
|
|
856
1063
|
severity: Severity.Warning,
|
|
857
1064
|
text: ( new MarkdownString(( localize(
|
|
858
|
-
|
|
1065
|
+
14059,
|
|
859
1066
|
"This MCP Server is disabled because it is configured to be disabled in the Editor. Please check your [settings]({0}).",
|
|
860
1067
|
settingsCommandLink
|
|
861
1068
|
))))
|
|
@@ -869,7 +1076,7 @@ let McpWorkbenchService = class McpWorkbenchService extends Disposable {
|
|
|
869
1076
|
message: {
|
|
870
1077
|
severity: Severity.Warning,
|
|
871
1078
|
text: ( new MarkdownString(( localize(
|
|
872
|
-
|
|
1079
|
+
14059,
|
|
873
1080
|
"This MCP Server is disabled because it is configured to be disabled in the Editor. Please check your [settings]({0}).",
|
|
874
1081
|
settingsCommandLink
|
|
875
1082
|
))))
|
|
@@ -13,7 +13,7 @@ import { IExtensionService } from '@codingame/monaco-vscode-api/vscode/vs/workbe
|
|
|
13
13
|
import { ExtensionsRegistry } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionsRegistry';
|
|
14
14
|
import { mcpContributionPoint, mcpActivationEvent } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpConfiguration';
|
|
15
15
|
import { IMcpRegistry } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpRegistryTypes.service';
|
|
16
|
-
import { McpServerDefinition, extensionPrefixedIdentifier, McpCollectionSortOrder, McpServerTrust } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
|
|
16
|
+
import { McpServerDefinition, extensionPrefixedIdentifier, McpCollectionSortOrder, McpServerTrust, McpCollectionProvenance } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
|
|
17
17
|
import { observableValue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/observableValue';
|
|
18
18
|
|
|
19
19
|
var ExtensionMcpDiscovery_1;
|
|
@@ -97,6 +97,7 @@ let ExtensionMcpDiscovery = ExtensionMcpDiscovery_1 = class ExtensionMcpDiscover
|
|
|
97
97
|
const serverDefs = this.cachedServers.hasOwnProperty(id) ? this.cachedServers[id].servers : undefined;
|
|
98
98
|
const dispo = this._mcpRegistry.registerCollection({
|
|
99
99
|
id,
|
|
100
|
+
provenance: McpCollectionProvenance.Extension,
|
|
100
101
|
label: coll.label,
|
|
101
102
|
remoteAuthority: null,
|
|
102
103
|
trustBehavior: McpServerTrust.Kind.Trusted,
|
|
@@ -142,20 +143,20 @@ let ExtensionMcpDiscovery = ExtensionMcpDiscovery_1 = class ExtensionMcpDiscover
|
|
|
142
143
|
}
|
|
143
144
|
static _validate(user) {
|
|
144
145
|
if (!Array.isArray(user.value)) {
|
|
145
|
-
user.collector.error(( localize(
|
|
146
|
+
user.collector.error(( localize(14060, "Expected an array of MCP collections")));
|
|
146
147
|
return false;
|
|
147
148
|
}
|
|
148
149
|
for (const contribution of user.value) {
|
|
149
150
|
if (typeof contribution.id !== "string" || isFalsyOrWhitespace(contribution.id)) {
|
|
150
|
-
user.collector.error(( localize(
|
|
151
|
+
user.collector.error(( localize(14061, "Expected 'id' to be a non-empty string.")));
|
|
151
152
|
return false;
|
|
152
153
|
}
|
|
153
154
|
if (typeof contribution.label !== "string" || isFalsyOrWhitespace(contribution.label)) {
|
|
154
|
-
user.collector.error(( localize(
|
|
155
|
+
user.collector.error(( localize(14062, "Expected 'label' to be a non-empty string.")));
|
|
155
156
|
return false;
|
|
156
157
|
}
|
|
157
158
|
if (contribution.when !== undefined && (typeof contribution.when !== "string" || isFalsyOrWhitespace(contribution.when))) {
|
|
158
|
-
user.collector.error(( localize(
|
|
159
|
+
user.collector.error(( localize(14063, "Expected 'when' to be a non-empty string.")));
|
|
159
160
|
return false;
|
|
160
161
|
}
|
|
161
162
|
}
|