@codingame/monaco-vscode-mcp-service-override 16.1.0 → 17.0.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.
Files changed (22) hide show
  1. package/package.json +5 -6
  2. package/vscode/src/vs/workbench/contrib/mcp/browser/mcp.contribution.js +6 -5
  3. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpDiscovery.js +1 -1
  4. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.js +24 -24
  5. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/configMcpDiscovery.js +3 -3
  6. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/extensionMcpDiscovery.js +4 -4
  7. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.d.ts +1 -1
  8. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.js +2 -2
  9. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.d.ts +1 -1
  10. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.js +2 -2
  11. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceMcpDiscoveryAdapter.js +1 -1
  12. package/vscode/src/vs/workbench/contrib/mcp/common/mcpConfigPathsService.js +3 -3
  13. package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.d.ts +4 -2
  14. package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.js +55 -17
  15. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.d.ts +17 -4
  16. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.js +127 -35
  17. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.js +14 -6
  18. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.d.ts +2 -1
  19. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.js +3 -0
  20. package/vscode/src/vs/workbench/contrib/mcp/common/mcpService.js +51 -32
  21. package/vscode/src/vs/workbench/contrib/mcp/common/modelContextProtocol.d.ts +36 -15
  22. package/vscode/src/vs/workbench/contrib/mcp/common/modelContextProtocol.js +1 -1
@@ -3,18 +3,25 @@ import { Disposable, IDisposable } from "@codingame/monaco-vscode-api/vscode/vs/
3
3
  import { IObservable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/observable";
4
4
  import { URI } from "@codingame/monaco-vscode-api/vscode/vs/base/common/uri";
5
5
  import { ICommandService } from "@codingame/monaco-vscode-api/vscode/vs/platform/commands/common/commands.service";
6
+ import { IInstantiationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation";
6
7
  import { ILoggerService } from "@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service";
8
+ import { INotificationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service";
9
+ import { IOpenerService } from "@codingame/monaco-vscode-api/vscode/vs/platform/opener/common/opener.service";
7
10
  import { StorageScope } from "@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage";
8
11
  import { IStorageService } from "@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service";
9
12
  import { ITelemetryService } from "@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service";
10
13
  import { IWorkspaceContextService } from "@codingame/monaco-vscode-api/vscode/vs/platform/workspace/common/workspace.service";
11
14
  import { IExtensionService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions.service";
12
15
  import { IOutputService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/services/output/common/output.service";
16
+ import { ToolProgress } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModelToolsService";
13
17
  import { IMcpRegistry } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpRegistryTypes.service";
14
18
  import { McpServerRequestHandler } from "./mcpServerRequestHandler.js";
15
19
  import { IMcpServer, IMcpServerConnection, IMcpTool, McpCollectionReference, McpConnectionState, McpDefinitionReference, McpServerDefinition, McpServerToolsState } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes";
16
20
  import { MCP } from "./modelContextProtocol.js";
17
- import { IInstantiationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation";
21
+ interface IToolCacheEntry {
22
+ readonly nonce: string | undefined;
23
+ readonly tools: readonly IValidatedMcpTool[];
24
+ }
18
25
  interface IServerCacheEntry {
19
26
  readonly servers: readonly McpServerDefinition.Serialized[];
20
27
  }
@@ -24,8 +31,8 @@ export declare class McpServerMetadataCache extends Disposable {
24
31
  private readonly extensionServers;
25
32
  constructor(scope: StorageScope, storageService: IStorageService);
26
33
  reset(): void;
27
- getTools(definitionId: string): readonly IValidatedMcpTool[] | undefined;
28
- storeTools(definitionId: string, tools: readonly IValidatedMcpTool[]): void;
34
+ getTools(definitionId: string): IToolCacheEntry | undefined;
35
+ storeTools(definitionId: string, nonce: string | undefined, tools: readonly IValidatedMcpTool[]): void;
29
36
  getServers(collectionId: string): IServerCacheEntry | undefined;
30
37
  storeServers(collectionId: string, entry: IServerCacheEntry | undefined): void;
31
38
  }
@@ -44,6 +51,8 @@ export declare class McpServer extends Disposable implements IMcpServer {
44
51
  private readonly _telemetryService;
45
52
  private readonly _commandService;
46
53
  private readonly _instantiationService;
54
+ private readonly _notificationService;
55
+ private readonly _openerService;
47
56
  private readonly _connectionSequencer;
48
57
  private readonly _connection;
49
58
  readonly connection: import("@codingame/monaco-vscode-api/vscode/vs/base/common/observable").ISettableObservable<IMcpServerConnection | undefined, void> & IDisposable;
@@ -56,9 +65,10 @@ export declare class McpServer extends Disposable implements IMcpServer {
56
65
  private readonly _loggerId;
57
66
  private readonly _logger;
58
67
  get trusted(): IObservable<boolean | undefined>;
59
- constructor(collection: McpCollectionReference, definition: McpDefinitionReference, explicitRoots: URI[] | undefined, _requiresExtensionActivation: boolean | undefined, _toolCache: McpServerMetadataCache, _mcpRegistry: IMcpRegistry, workspacesService: IWorkspaceContextService, _extensionService: IExtensionService, _loggerService: ILoggerService, _outputService: IOutputService, _telemetryService: ITelemetryService, _commandService: ICommandService, _instantiationService: IInstantiationService);
68
+ constructor(collection: McpCollectionReference, definition: McpDefinitionReference, explicitRoots: URI[] | undefined, _requiresExtensionActivation: boolean | undefined, _toolCache: McpServerMetadataCache, _mcpRegistry: IMcpRegistry, workspacesService: IWorkspaceContextService, _extensionService: IExtensionService, _loggerService: ILoggerService, _outputService: IOutputService, _telemetryService: ITelemetryService, _commandService: ICommandService, _instantiationService: IInstantiationService, _notificationService: INotificationService, _openerService: IOpenerService);
60
69
  showOutput(): void;
61
70
  start(isFromInteraction?: boolean): Promise<McpConnectionState>;
71
+ private showInteractiveError;
62
72
  stop(): Promise<void>;
63
73
  private resetLiveData;
64
74
  private _normalizeTool;
@@ -73,5 +83,8 @@ export declare class McpTool implements IMcpTool {
73
83
  get definition(): MCP.Tool;
74
84
  constructor(_server: McpServer, idPrefix: string, _definition: IValidatedMcpTool);
75
85
  call(params: Record<string, unknown>, token?: CancellationToken): Promise<MCP.CallToolResult>;
86
+ callWithProgress(params: Record<string, unknown>, progress: ToolProgress, token?: CancellationToken): Promise<MCP.CallToolResult>;
87
+ _callWithProgress(params: Record<string, unknown>, progress: ToolProgress, token?: CancellationToken, allowRetry?: boolean): Promise<MCP.CallToolResult>;
88
+ compare(other: IMcpTool): number;
76
89
  }
77
90
  export {};
@@ -1,35 +1,37 @@
1
1
 
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
3
  import { Sequencer, raceCancellationError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
4
- import { parseTree, findNodeAtOffset, getNodePath } from '@codingame/monaco-vscode-api/vscode/vs/base/common/json';
5
4
  import { CancellationTokenSource, CancellationToken } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
5
+ import { parseTree, findNodeAtOffset, getNodePath } from '@codingame/monaco-vscode-api/vscode/vs/base/common/json';
6
6
  import { Disposable, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
7
7
  import { LRUCache } from '@codingame/monaco-vscode-api/vscode/vs/base/common/map';
8
8
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
9
9
  import { basename } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
10
10
  import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
11
+ import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
12
+ import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
11
13
  import { ICommandService } from '@codingame/monaco-vscode-api/vscode/vs/platform/commands/common/commands.service';
14
+ import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
12
15
  import { ILoggerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
16
+ import '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification';
17
+ import { INotificationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service';
18
+ import { IOpenerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/opener/common/opener.service';
13
19
  import { StorageTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage';
14
20
  import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service';
15
21
  import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service';
16
22
  import { IWorkspaceContextService } from '@codingame/monaco-vscode-api/vscode/vs/platform/workspace/common/workspace.service';
23
+ import { IEditorService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/editor/common/editorService.service';
17
24
  import { IExtensionService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions.service';
18
25
  import { IOutputService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/output/common/output.service';
19
- import { mcpActivationEvent } from '@codingame/monaco-vscode-ec21d4de-4d65-574c-8715-bb1a6bbad376-common/vscode/vs/workbench/contrib/mcp/common/mcpConfiguration';
26
+ import { mcpActivationEvent } from '@codingame/monaco-vscode-1cb11a73-359e-5a2f-9e95-6989cc9858ee-common/vscode/vs/workbench/contrib/mcp/common/mcpConfiguration';
20
27
  import { IMcpRegistry } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpRegistryTypes.service';
21
- import { McpConnectionState, McpServerToolsState, extensionMcpCollectionPrefix, McpConnectionFailedError } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
22
- import '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification';
23
- import { INotificationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service';
24
- import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
25
- import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
26
- import { IEditorService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/editor/common/editorService.service';
28
+ import { McpConnectionState, McpServerToolsState, extensionMcpCollectionPrefix, McpServerTransportType, McpConnectionFailedError } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
27
29
  import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity';
28
30
  import { disposableObservableValue, observableValue, transaction } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/base';
29
31
  import { derived } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/derived';
30
32
  import { observableFromEvent } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/utils';
31
33
  import { autorunWithStore, autorun } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/autorun';
32
- import { ObservablePromise } from '@codingame/monaco-vscode-ae8a8ca1-f243-508b-9c37-c88ebbd295fa-common/vscode/vs/base/common/observableInternal/promise';
34
+ import { ObservablePromise } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/promise';
33
35
 
34
36
  const toolInvalidCharRe = /[^a-z0-9_-]/gi;
35
37
  let McpServerMetadataCache = class McpServerMetadataCache extends Disposable {
@@ -62,10 +64,10 @@ let McpServerMetadataCache = class McpServerMetadataCache extends Disposable {
62
64
  this.didChange = true;
63
65
  }
64
66
  getTools(definitionId) {
65
- return this.cache.get(definitionId)?.tools;
67
+ return this.cache.get(definitionId);
66
68
  }
67
- storeTools(definitionId, tools) {
68
- this.cache.set(definitionId, { ...this.cache.get(definitionId), tools });
69
+ storeTools(definitionId, nonce, tools) {
70
+ this.cache.set(definitionId, { ...this.cache.get(definitionId), nonce, tools });
69
71
  this.didChange = true;
70
72
  }
71
73
  getServers(collectionId) {
@@ -91,7 +93,7 @@ let McpServer = class McpServer extends Disposable {
91
93
  get trusted() {
92
94
  return this._mcpRegistry.getTrust(this.collection);
93
95
  }
94
- constructor(collection, definition, explicitRoots, _requiresExtensionActivation, _toolCache, _mcpRegistry, workspacesService, _extensionService, _loggerService, _outputService, _telemetryService, _commandService, _instantiationService) {
96
+ constructor(collection, definition, explicitRoots, _requiresExtensionActivation, _toolCache, _mcpRegistry, workspacesService, _extensionService, _loggerService, _outputService, _telemetryService, _commandService, _instantiationService, _notificationService, _openerService) {
95
97
  super();
96
98
  this.collection = collection;
97
99
  this.definition = definition;
@@ -104,6 +106,8 @@ let McpServer = class McpServer extends Disposable {
104
106
  this._telemetryService = _telemetryService;
105
107
  this._commandService = _commandService;
106
108
  this._instantiationService = _instantiationService;
109
+ this._notificationService = _notificationService;
110
+ this._openerService = _openerService;
107
111
  this._connectionSequencer = ( new Sequencer());
108
112
  this._connection = this._register(disposableObservableValue(this, undefined));
109
113
  this.connection = this._connection;
@@ -111,17 +115,31 @@ let McpServer = class McpServer extends Disposable {
111
115
  this.toolsFromServerPromise = observableValue(this, undefined);
112
116
  this.toolsFromServer = derived(reader => this.toolsFromServerPromise.read(reader)?.promiseResult.read(reader)?.data);
113
117
  this.toolsState = derived(reader => {
118
+ const currentNonce = () => this._mcpRegistry.collections.read(reader)
119
+ .find(c => c.id === this.collection.id)
120
+ ?.serverDefinitions.read(reader)
121
+ .find(d => d.id === this.definition.id)
122
+ ?.cacheNonce;
123
+ const stateWhenServingFromCache = () => {
124
+ if (!this.toolsFromCache) {
125
+ return McpServerToolsState.Unknown;
126
+ }
127
+ return currentNonce() === this.toolsFromCache.nonce ? McpServerToolsState.Cached : McpServerToolsState.Outdated;
128
+ };
114
129
  const fromServer = this.toolsFromServerPromise.read(reader);
115
130
  const connectionState = this.connectionState.read(reader);
116
131
  const isIdle = McpConnectionState.canBeStarted(connectionState.state) && !fromServer;
117
132
  if (isIdle) {
118
- return this.toolsFromCache ? McpServerToolsState.Cached : McpServerToolsState.Unknown;
133
+ return stateWhenServingFromCache();
119
134
  }
120
135
  const fromServerResult = fromServer?.promiseResult.read(reader);
121
136
  if (!fromServerResult) {
122
137
  return this.toolsFromCache ? McpServerToolsState.RefreshingFromCached : McpServerToolsState.RefreshingFromUnknown;
123
138
  }
124
- return fromServerResult.error ? (this.toolsFromCache ? McpServerToolsState.Cached : McpServerToolsState.Unknown) : McpServerToolsState.Live;
139
+ if (fromServerResult.error) {
140
+ return stateWhenServingFromCache();
141
+ }
142
+ return fromServerResult.data?.nonce === currentNonce() ? McpServerToolsState.Live : McpServerToolsState.Outdated;
125
143
  });
126
144
  this._loggerId = `mcpServer.${definition.id}`;
127
145
  this._logger = this._register(_loggerService.createLogger(this._loggerId, { hidden: true, name: `MCP: ${definition.label}` }));
@@ -140,26 +158,21 @@ let McpServer = class McpServer extends Disposable {
140
158
  })));
141
159
  }));
142
160
  this._register(autorunWithStore((reader, store) => {
143
- const cnx = this._connection.read(reader)?.handler.read(reader);
144
- if (cnx) {
145
- this.populateLiveData(cnx, store);
161
+ const cnx = this._connection.read(reader);
162
+ const handler = cnx?.handler.read(reader);
163
+ if (handler) {
164
+ this.populateLiveData(handler, cnx?.definition.cacheNonce, store);
146
165
  }
147
166
  else {
148
167
  this.resetLiveData();
149
168
  }
150
169
  }));
151
- this._register(autorun(reader => {
152
- const tools = this.toolsFromServer.read(reader);
153
- if (tools) {
154
- this._toolCache.storeTools(definition.id, tools);
155
- }
156
- }));
157
170
  const toolPrefix = this._mcpRegistry.collectionToolPrefix(this.collection);
158
171
  this.tools = derived(reader => {
159
172
  const serverTools = this.toolsFromServer.read(reader);
160
- const definitions = serverTools ?? this.toolsFromCache ?? [];
173
+ const definitions = serverTools?.tools ?? this.toolsFromCache?.tools ?? [];
161
174
  const prefix = toolPrefix.read(reader);
162
- return ( definitions.map(def => ( new McpTool(this, prefix, def))));
175
+ return ( definitions.map(def => ( new McpTool(this, prefix, def)))).sort((a, b) => a.compare(b));
163
176
  });
164
177
  }
165
178
  showOutput() {
@@ -205,9 +218,49 @@ let McpServer = class McpServer extends Disposable {
205
218
  state: McpConnectionState.toKindString(state.state),
206
219
  time: Date.now() - start,
207
220
  });
221
+ if (state.state === McpConnectionState.Kind.Error && isFromInteraction) {
222
+ this.showInteractiveError(connection, state);
223
+ }
208
224
  return state;
209
225
  });
210
226
  }
227
+ showInteractiveError(cnx, error) {
228
+ if (error.code === 'ENOENT' && cnx.launchDefinition.type === McpServerTransportType.Stdio) {
229
+ let docsLink;
230
+ switch (cnx.launchDefinition.command) {
231
+ case 'uvx':
232
+ docsLink = `https://aka.ms/vscode-mcp-install/uvx`;
233
+ break;
234
+ case 'npx':
235
+ docsLink = `https://aka.ms/vscode-mcp-install/npx`;
236
+ break;
237
+ }
238
+ const options = [{
239
+ label: ( localize(7743, "Show Output")),
240
+ run: () => this.showOutput(),
241
+ }];
242
+ if (docsLink) {
243
+ options.push({
244
+ label: ( localize(7744, 'Install {0}', cnx.launchDefinition.command)),
245
+ run: () => this._openerService.open(( URI.parse(docsLink))),
246
+ });
247
+ }
248
+ this._notificationService.prompt(Severity.Error, ( localize(
249
+ 7745,
250
+ 'The command "{0}" needed to run {1} was not found.',
251
+ cnx.launchDefinition.command,
252
+ cnx.definition.label
253
+ )), options);
254
+ }
255
+ else {
256
+ this._notificationService.warn(( localize(
257
+ 7746,
258
+ 'The MCP server {0} could not be started: {1}',
259
+ cnx.definition.label,
260
+ error.message
261
+ )));
262
+ }
263
+ }
211
264
  stop() {
212
265
  return this._connection.get()?.stop() || Promise.resolve();
213
266
  }
@@ -251,7 +304,7 @@ let McpServer = class McpServer extends Disposable {
251
304
  const validated = [];
252
305
  for (const [i, result] of validations.entries()) {
253
306
  if ('error' in result) {
254
- error += ( localize(7661, 'Tool `{0}` has invalid JSON parameters:', tools[i].name)) + '\n';
307
+ error += ( localize(7747, 'Tool `{0}` has invalid JSON parameters:', tools[i].name)) + '\n';
255
308
  for (const message of result.error) {
256
309
  error += `\t- ${message}\n`;
257
310
  }
@@ -267,17 +320,17 @@ let McpServer = class McpServer extends Disposable {
267
320
  }
268
321
  return validated;
269
322
  }
270
- populateLiveData(handler, store) {
323
+ populateLiveData(handler, cacheNonce, store) {
271
324
  const cts = ( new CancellationTokenSource());
272
325
  store.add(toDisposable(() => cts.dispose(true)));
273
326
  const updateTools = (tx) => {
274
327
  const toolPromise = handler.capabilities.tools ? handler.listTools({}, cts.token) : Promise.resolve([]);
275
328
  const toolPromiseSafe = toolPromise.then(async (tools) => {
276
329
  handler.logger.info(`Discovered ${tools.length} tools`);
277
- return this._getValidatedTools(handler, tools);
330
+ return { tools: await this._getValidatedTools(handler, tools), nonce: cacheNonce };
278
331
  });
279
332
  this.toolsFromServerPromise.set(( new ObservablePromise(toolPromiseSafe)), tx);
280
- return [toolPromise];
333
+ return [toolPromiseSafe];
281
334
  };
282
335
  store.add(handler.onDidChangeToolList(() => {
283
336
  handler.logger.info('Tool list changed, refreshing tools...');
@@ -287,12 +340,15 @@ let McpServer = class McpServer extends Disposable {
287
340
  transaction(tx => {
288
341
  promises = updateTools(tx);
289
342
  });
290
- Promise.all(promises).then(([tools]) => {
343
+ Promise.all(promises).then(([{ tools }]) => {
344
+ this._toolCache.storeTools(this.definition.id, cacheNonce, tools);
291
345
  this._telemetryService.publicLog2('mcp/serverBoot', {
292
346
  supportsLogging: !!handler.capabilities.logging,
293
347
  supportsPrompts: !!handler.capabilities.prompts,
294
348
  supportsResources: !!handler.capabilities.resources,
295
349
  toolCount: tools.length,
350
+ serverName: handler.serverInfo.name,
351
+ serverVersion: handler.serverInfo.version,
296
352
  });
297
353
  });
298
354
  }
@@ -336,7 +392,9 @@ McpServer = ( __decorate([
336
392
  ( __param(9, IOutputService)),
337
393
  ( __param(10, ITelemetryService)),
338
394
  ( __param(11, ICommandService)),
339
- ( __param(12, IInstantiationService))
395
+ ( __param(12, IInstantiationService)),
396
+ ( __param(13, INotificationService)),
397
+ ( __param(14, IOpenerService))
340
398
  ], McpServer));
341
399
  class McpTool {
342
400
  get definition() { return this._definition; }
@@ -347,7 +405,41 @@ class McpTool {
347
405
  }
348
406
  call(params, token) {
349
407
  const name = this._definition.serverToolName ?? this._definition.name;
350
- return this._server.callOn(h => h.callTool({ name, arguments: params }), token);
408
+ return this._server.callOn(h => h.callTool({ name, arguments: params }, token), token);
409
+ }
410
+ callWithProgress(params, progress, token) {
411
+ return this._callWithProgress(params, progress, token);
412
+ }
413
+ _callWithProgress(params, progress, token, allowRetry = true) {
414
+ const name = this._definition.serverToolName ?? this._definition.name;
415
+ const progressToken = generateUuid();
416
+ return this._server.callOn(h => {
417
+ let lastProgressN = 0;
418
+ const listener = h.onDidReceiveProgressNotification((e) => {
419
+ if (e.params.progressToken === progressToken) {
420
+ progress.report({
421
+ message: e.params.message,
422
+ increment: e.params.progress - lastProgressN,
423
+ total: e.params.total,
424
+ });
425
+ lastProgressN = e.params.progress;
426
+ }
427
+ });
428
+ return h.callTool({ name, arguments: params, _meta: { progressToken } }, token)
429
+ .finally(() => listener.dispose())
430
+ .catch(err => {
431
+ const state = this._server.connectionState.get();
432
+ if (allowRetry && state.state === McpConnectionState.Kind.Error && state.shouldRetry) {
433
+ return this._callWithProgress(params, progress, token, false);
434
+ }
435
+ else {
436
+ throw err;
437
+ }
438
+ });
439
+ }, token);
440
+ }
441
+ compare(other) {
442
+ return this._definition.name.localeCompare(other.definition.name);
351
443
  }
352
444
  }
353
445
  function warnInvalidTools(instaService, serverName, errorText) {
@@ -357,7 +449,7 @@ function warnInvalidTools(instaService, serverName, errorText) {
357
449
  notificationService.notify({
358
450
  severity: Severity.Warning,
359
451
  message: ( localize(
360
- 7662,
452
+ 7748,
361
453
  'MCP server `{0}` has tools with invalid parameters which will be omitted.',
362
454
  serverName
363
455
  )),
@@ -367,7 +459,7 @@ function warnInvalidTools(instaService, serverName, errorText) {
367
459
  enabled: true,
368
460
  id: 'mcpBadSchema.show',
369
461
  tooltip: '',
370
- label: ( localize(7663, 'Show')),
462
+ label: ( localize(7749, 'Show')),
371
463
  run: () => {
372
464
  editorService.openEditor({
373
465
  resource: undefined,
@@ -1,6 +1,7 @@
1
1
 
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
3
  import { CancellationTokenSource } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
4
+ import { CancellationError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
4
5
  import { Disposable, MutableDisposable, DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
5
6
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
6
7
  import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
@@ -33,7 +34,7 @@ let McpServerConnection = class McpServerConnection extends Disposable {
33
34
  }
34
35
  this._launch.value = undefined;
35
36
  this._state.set({ state: McpConnectionState.Kind.Starting }, undefined);
36
- this._logger.info(( localize(7664, 'Starting server {0}', this.definition.label)));
37
+ this._logger.info(( localize(7750, 'Starting server {0}', this.definition.label)));
37
38
  try {
38
39
  const launch = this._delegate.start(this._collection, this.definition, this.launchDefinition);
39
40
  this._launch.value = this.adoptLaunch(launch);
@@ -60,7 +61,7 @@ let McpServerConnection = class McpServerConnection extends Disposable {
60
61
  store.add(autorun(reader => {
61
62
  const state = launch.state.read(reader);
62
63
  this._state.set(state, undefined);
63
- this._logger.info(( localize(7665, 'Connection state: {0}', (McpConnectionState.toString(state)))));
64
+ this._logger.info(( localize(7751, 'Connection state: {0}', (McpConnectionState.toString(state)))));
64
65
  if (state.state === McpConnectionState.Kind.Running && !didStart) {
65
66
  didStart = true;
66
67
  McpServerRequestHandler.create(this._instantiationService, launch, this._logger, cts.token).then(handler => {
@@ -71,18 +72,25 @@ let McpServerConnection = class McpServerConnection extends Disposable {
71
72
  handler.dispose();
72
73
  }
73
74
  }, err => {
74
- store.dispose();
75
75
  if (!store.isDisposed) {
76
- this._logger.error(err);
77
- this._state.set({ state: McpConnectionState.Kind.Error, message: `Could not initialize MCP server: ${err.message}` }, undefined);
76
+ let message = err.message;
77
+ if (err instanceof CancellationError) {
78
+ message = 'Server exited before responding to `initialize` request.';
79
+ this._logger.error(message);
80
+ }
81
+ else {
82
+ this._logger.error(err);
83
+ }
84
+ this._state.set({ state: McpConnectionState.Kind.Error, message }, undefined);
78
85
  }
86
+ store.dispose();
79
87
  });
80
88
  }
81
89
  }));
82
90
  return { dispose: () => store.dispose(), object: launch };
83
91
  }
84
92
  async stop() {
85
- this._logger.info(( localize(7666, 'Stopping server {0}', this.definition.label)));
93
+ this._logger.info(( localize(7752, 'Stopping server {0}', this.definition.label)));
86
94
  this._launch.value?.object.stop();
87
95
  await this._waitForState(McpConnectionState.Kind.Stopped, McpConnectionState.Kind.Error);
88
96
  }
@@ -18,6 +18,7 @@ export declare class McpServerRequestHandler extends Disposable {
18
18
  set roots(roots: MCP.Root[]);
19
19
  private _serverInit;
20
20
  get capabilities(): MCP.ServerCapabilities;
21
+ get serverInfo(): MCP.Implementation;
21
22
  private readonly _onDidReceiveCancelledNotification;
22
23
  readonly onDidReceiveCancelledNotification: import("@codingame/monaco-vscode-api/vscode/vs/base/common/event").Event<MCP.CancelledNotification>;
23
24
  private readonly _onDidReceiveProgressNotification;
@@ -57,7 +58,7 @@ export declare class McpServerRequestHandler extends Disposable {
57
58
  listPrompts(params?: MCP.ListPromptsRequest["params"], token?: CancellationToken): Promise<MCP.Prompt[]>;
58
59
  getPrompt(params: MCP.GetPromptRequest["params"], token?: CancellationToken): Promise<MCP.GetPromptResult>;
59
60
  listTools(params?: MCP.ListToolsRequest["params"], token?: CancellationToken): Promise<MCP.Tool[]>;
60
- callTool(params: MCP.CallToolRequest["params"], token?: CancellationToken): Promise<MCP.CallToolResult>;
61
+ callTool(params: MCP.CallToolRequest["params"] & MCP.Request["params"], token?: CancellationToken): Promise<MCP.CallToolResult>;
61
62
  setLevel(params: MCP.SetLevelRequest["params"], token?: CancellationToken): Promise<MCP.EmptyResult>;
62
63
  complete(params: MCP.CompleteRequest["params"], token?: CancellationToken): Promise<MCP.CompleteResult>;
63
64
  }
@@ -25,6 +25,9 @@ class McpServerRequestHandler extends Disposable {
25
25
  get capabilities() {
26
26
  return this._serverInit.capabilities;
27
27
  }
28
+ get serverInfo() {
29
+ return this._serverInit.serverInfo;
30
+ }
28
31
  static async create(instaService, launch, logger, token) {
29
32
  const mcp = ( new McpServerRequestHandler(launch, logger));
30
33
  const store = ( new DisposableStore());
@@ -1,9 +1,10 @@
1
1
 
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
3
  import { RunOnceScheduler } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
4
+ import { decodeBase64 } from '@codingame/monaco-vscode-api/vscode/vs/base/common/buffer';
4
5
  import { Codicon } from '@codingame/monaco-vscode-api/vscode/vs/base/common/codicons';
5
- import { MarkdownString } from '@codingame/monaco-vscode-api/vscode/vs/base/common/htmlContent';
6
- import { Disposable, toDisposable, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
6
+ import { MarkdownString, markdownCommandLink } from '@codingame/monaco-vscode-api/vscode/vs/base/common/htmlContent';
7
+ import { Disposable, DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
7
8
  import { equals } from '@codingame/monaco-vscode-api/vscode/vs/base/common/objects';
8
9
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
9
10
  import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
@@ -12,6 +13,7 @@ import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log
12
13
  import { IProductService } from '@codingame/monaco-vscode-api/vscode/vs/platform/product/common/productService.service';
13
14
  import { StorageScope } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage';
14
15
  import { ILanguageModelToolsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModelToolsService.service';
16
+ import { McpCommandIds } from '@codingame/monaco-vscode-1cb11a73-359e-5a2f-9e95-6989cc9858ee-common/vscode/vs/workbench/contrib/mcp/common/mcpCommandIds';
15
17
  import { IMcpRegistry } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpRegistryTypes.service';
16
18
  import { McpServerMetadataCache, McpServer } from './mcpServer.js';
17
19
  import { McpServerToolsState, McpServerDefinition } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
@@ -66,47 +68,48 @@ let McpService = class McpService extends Disposable {
66
68
  const collection = this._mcpRegistry.collections.get().find(c => c.id === server.collection.id);
67
69
  const toolData = {
68
70
  id: tool.id,
69
- source: { type: 'mcp', collectionId: server.collection.id, definitionId: server.definition.id },
71
+ source: { type: 'mcp', label: server.definition.label, collectionId: server.collection.id, definitionId: server.definition.id },
70
72
  icon: Codicon.tools,
71
- displayName: tool.definition.name,
73
+ displayName: tool.definition.annotations?.title || tool.definition.name,
72
74
  toolReferenceName: tool.definition.name,
73
75
  modelDescription: tool.definition.description ?? '',
74
76
  userDescription: tool.definition.description ?? '',
75
77
  inputSchema: tool.definition.inputSchema,
76
78
  canBeReferencedInPrompt: true,
77
79
  supportsToolPicker: true,
80
+ alwaysDisplayInputOutput: true,
78
81
  runsInWorkspace: collection?.scope === StorageScope.WORKSPACE || !!collection?.remoteAuthority,
79
82
  tags: ['mcp'],
80
83
  };
84
+ const registerTool = (store) => {
85
+ store.add(this._toolsService.registerToolData(toolData));
86
+ store.add(this._toolsService.registerToolImplementation(tool.id, this._instantiationService.createInstance(McpToolImplementation, tool, server)));
87
+ };
81
88
  if (existing) {
82
89
  if (!equals(existing.toolData, toolData)) {
83
90
  existing.toolData = toolData;
84
- existing.toolDispose.dispose();
85
- existing.toolDispose = this._toolsService.registerToolData(toolData);
91
+ existing.store.clear();
92
+ registerTool(store);
86
93
  }
87
94
  toDelete.delete(tool.id);
88
95
  }
89
96
  else {
90
- tools.set(tool.id, {
91
- toolData,
92
- toolDispose: this._toolsService.registerToolData(toolData),
93
- implDispose: this._toolsService.registerToolImplementation(tool.id, this._instantiationService.createInstance(McpToolImplementation, tool, server)),
94
- });
97
+ const store = ( new DisposableStore());
98
+ registerTool(store);
99
+ tools.set(tool.id, { toolData, store });
95
100
  }
96
101
  }
97
102
  for (const id of toDelete) {
98
103
  const tool = tools.get(id);
99
104
  if (tool) {
100
- tool.toolDispose.dispose();
101
- tool.implDispose.dispose();
105
+ tool.store.dispose();
102
106
  tools.delete(id);
103
107
  }
104
108
  }
105
109
  }));
106
110
  store.add(toDisposable(() => {
107
111
  for (const tool of ( tools.values())) {
108
- tool.toolDispose.dispose();
109
- tool.implDispose.dispose();
112
+ tool.store.dispose();
110
113
  }
111
114
  }));
112
115
  }
@@ -171,45 +174,61 @@ let McpToolImplementation = class McpToolImplementation {
171
174
  const tool = this._tool;
172
175
  const server = this._server;
173
176
  const mcpToolWarning = ( localize(
174
- 7667,
175
- "{0} This tool is from \'{1}\' (MCP Server). Note that MCP servers or malicious conversation content may attempt to misuse '{2}' through tools. Please carefully review any requested actions.",
177
+ 7753,
178
+ "{0} Note that MCP servers or malicious conversation content may attempt to misuse '{1}' through tools.",
176
179
  '$(info)',
177
- server.definition.label,
178
180
  this._productService.nameShort
179
181
  ));
182
+ const needsConfirmation = !tool.definition.annotations?.readOnlyHint;
183
+ const title = tool.definition.annotations?.title || ('`' + tool.definition.name + '`');
184
+ const subtitle = ( localize(7754, "{0} (MCP Server)", server.definition.label));
180
185
  return {
181
- confirmationMessages: {
182
- title: ( localize(7668, "Run `{0}`", tool.definition.name, server.definition.label)),
183
- message: ( new MarkdownString(( localize(7669, "{0}\n\n {1}", tool.definition.description, mcpToolWarning)), { supportThemeIcons: true })),
186
+ confirmationMessages: needsConfirmation ? {
187
+ title: ( localize(7755, "Run {0}", title)),
188
+ message: ( new MarkdownString(( localize(7756, "{0}\n\n {1}", tool.definition.description, mcpToolWarning)), { supportThemeIcons: true })),
184
189
  allowAutoConfirm: true,
185
- },
186
- invocationMessage: ( new MarkdownString(( localize(7670, "Running `{0}`", tool.definition.name, server.definition.label)))),
187
- pastTenseMessage: ( new MarkdownString(( localize(7671, "Ran `{0}` ", tool.definition.name, server.definition.label)))),
190
+ } : undefined,
191
+ invocationMessage: ( new MarkdownString(( localize(7757, "Running {0}", title)))),
192
+ pastTenseMessage: ( new MarkdownString(( localize(7758, "Ran {0} ", title)))),
193
+ originMessage: ( new MarkdownString(markdownCommandLink({
194
+ id: McpCommandIds.ShowConfiguration,
195
+ title: subtitle,
196
+ arguments: [server.collection.id, server.definition.id],
197
+ }), { isTrusted: true })),
188
198
  toolSpecificData: {
189
199
  kind: 'input',
190
200
  rawInput: parameters
191
201
  }
192
202
  };
193
203
  }
194
- async invoke(invocation, _countTokens, token) {
204
+ async invoke(invocation, _countTokens, progress, token) {
195
205
  const result = {
196
206
  content: []
197
207
  };
198
- const outputParts = [];
199
- const callResult = await this._tool.call(invocation.parameters, token);
208
+ const callResult = await this._tool.callWithProgress(invocation.parameters, progress, token);
209
+ const details = {
210
+ input: JSON.stringify(invocation.parameters, undefined, 2),
211
+ output: [],
212
+ isError: callResult.isError === true,
213
+ };
200
214
  for (const item of callResult.content) {
201
215
  if (item.type === 'text') {
216
+ details.output.push({ type: 'text', value: item.text });
202
217
  result.content.push({
203
218
  kind: 'text',
204
219
  value: item.text
205
220
  });
206
- outputParts.push(item.text);
207
221
  }
222
+ else if (item.type === 'image' || item.type === 'audio') {
223
+ details.output.push({ type: 'data', mimeType: item.mimeType, value64: item.data });
224
+ result.content.push({
225
+ kind: 'data',
226
+ value: { mimeType: item.mimeType, data: decodeBase64(item.data) }
227
+ });
228
+ }
229
+ else ;
208
230
  }
209
- result.toolResultDetails = {
210
- input: JSON.stringify(invocation.parameters, undefined, 2),
211
- output: outputParts.join('\n')
212
- };
231
+ result.toolResultDetails = details;
213
232
  return result;
214
233
  }
215
234
  };