@codingame/monaco-vscode-mcp-service-override 16.1.1 → 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.
- package/package.json +5 -6
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcp.contribution.js +6 -5
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpDiscovery.js +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.js +24 -24
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/configMcpDiscovery.js +3 -3
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/extensionMcpDiscovery.js +4 -4
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.d.ts +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.js +2 -2
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.d.ts +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.js +2 -2
- package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceMcpDiscoveryAdapter.js +1 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpConfigPathsService.js +3 -3
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.d.ts +4 -2
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.js +55 -17
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.d.ts +17 -4
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.js +127 -35
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.js +14 -6
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.js +3 -0
- package/vscode/src/vs/workbench/contrib/mcp/common/mcpService.js +51 -32
- package/vscode/src/vs/workbench/contrib/mcp/common/modelContextProtocol.d.ts +36 -15
- 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
|
-
|
|
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):
|
|
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-
|
|
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-
|
|
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)
|
|
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
|
|
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
|
-
|
|
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)
|
|
144
|
-
|
|
145
|
-
|
|
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(
|
|
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 [
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
77
|
-
|
|
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(
|
|
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,
|
|
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.
|
|
85
|
-
|
|
91
|
+
existing.store.clear();
|
|
92
|
+
registerTool(store);
|
|
86
93
|
}
|
|
87
94
|
toDelete.delete(tool.id);
|
|
88
95
|
}
|
|
89
96
|
else {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
175
|
-
"{0}
|
|
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(
|
|
183
|
-
message: ( new MarkdownString(( localize(
|
|
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(
|
|
187
|
-
pastTenseMessage: ( new MarkdownString(( localize(
|
|
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
|
|
199
|
-
const
|
|
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
|
};
|