mcpServerRequestHandler.ts ×42

Frontier kind: Code frontier

unlabeled · c_1b97d997d280

77 tests · 32933 LOC · 160 files · introduces 0 tests · 433 LOC · 5 files

Introduces — evidence that enters the hierarchy at this concept

Code
77 ranges433 lines · 5 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
3323 ranges32933 lines · 160 files · Browse complete extent
All tests (intent)
77 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

5 files ranked by introduced lines: 433 introduced LOC across 77 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts 275 introduced LOC · 42 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpServerRequestHandler.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { equals } from '../../../../base/common/arrays.js';
7 > import { assertNever, softAssertNever } from '../../../../base/common/assert.js';
8 > import { DeferredPromise, disposableTimeout, IntervalTimer, isThenable } from '../../../../base/common/async.js';
9 > import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
10 > import { CancellationError } from '../../../../base/common/errors.js';
11 > import { Emitter } from '../../../../base/common/event.js';
12 > import { Iterable } from '../../../../base/common/iterator.js';
13 > import { JsonRpcError, JsonRpcProtocol } from '../../../../base/common/jsonRpcProtocol.js';
14 > import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
15 > import { autorun, ISettableObservable, ObservablePromise, observableValue, transaction } from '../../../../base/common/observable.js';
16 > import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
17 > import { canLog, ILogger, log, LogLevel } from '../../../../platform/log/common/log.js';
18 > import { IProductService } from '../../../../platform/product/common/productService.js';
19 > import { IMcpMessageTransport } from './mcpRegistryTypes.js';
20 > import { IMcpTaskInternal, McpTaskManager } from './mcpTaskManager.js';
21 > import { IMcpClientMethods, McpConnectionState, McpError, MpcResponseError } from './mcpTypes.js';
22 > import { isTaskResult, translateMcpLogMessage } from './mcpTypesUtils.js';
23 > import { MCP } from './modelContextProtocol.js';
24 >
25 > export interface McpRoot {
26 > uri: string;
27 > name?: string;
28 > }
29 >
30 > export interface IMcpServerRequestHandlerOptions extends IMcpClientMethods {
31 > /** MCP message transport */
32 > launch: IMcpMessageTransport;
33 > /** Logger instance. */
34 > logger: ILogger;
35 > /** Log level MCP messages is logged at */
36 > requestLogLevel?: LogLevel;
37 > /** Task manager for server-side MCP tasks (shared across reconnections) */
38 > taskManager: McpTaskManager;
39 > }
40 >
41 > /**
42 > * Request handler for communicating with an MCP server.
43 > *
44 > * Handles sending requests and receiving responses, with automatic
45 > * handling of ping requests and typed client request methods.
46 > */
47 > export class McpServerRequestHandler extends Disposable {
48 > private readonly _rpc: JsonRpcProtocol;
49 >
50 > private _hasAnnouncedRoots = false;
51 > private _roots: MCP.Root[] = [];
52 >
53 > public set roots(roots: MCP.Root[]) {
54 > if (!equals(this._roots, roots)) {
55 > this._roots = roots;
56 > if (this._hasAnnouncedRoots) {
57 this.sendNotification({ method: 'notifications/roots/list_changed' });
58 this._hasAnnouncedRoots = false;
59 }
61 > }
62 >
63 > private _serverInit!: MCP.InitializeResult;
64 > public get capabilities(): MCP.ServerCapabilities {
65 return this._serverInit.capabilities;
66 }
68 > public get serverInfo(): MCP.Implementation {
69 return this._serverInit.serverInfo;
70 }
72 > public get serverInstructions(): string | undefined {
73 return this._serverInit.instructions;
74 }
76 > // Event emitters for server notifications
77 > private readonly _onDidReceiveCancelledNotification = this._register(new Emitter<MCP.CancelledNotification>());
78 > readonly onDidReceiveCancelledNotification = this._onDidReceiveCancelledNotification.event;
79 >
80 > private readonly _onDidReceiveProgressNotification = this._register(new Emitter<MCP.ProgressNotification>());
81 > readonly onDidReceiveProgressNotification = this._onDidReceiveProgressNotification.event;
82 >
83 > private readonly _onDidReceiveElicitationCompleteNotification = this._register(new Emitter<MCP.ElicitationCompleteNotification>());
84 > readonly onDidReceiveElicitationCompleteNotification = this._onDidReceiveElicitationCompleteNotification.event;
85 >
86 > private readonly _onDidChangeResourceList = this._register(new Emitter<void>());
87 > readonly onDidChangeResourceList = this._onDidChangeResourceList.event;
88 >
89 > private readonly _onDidUpdateResource = this._register(new Emitter<MCP.ResourceUpdatedNotification>());
90 > readonly onDidUpdateResource = this._onDidUpdateResource.event;
91 >
92 > private readonly _onDidChangeToolList = this._register(new Emitter<void>());
93 > readonly onDidChangeToolList = this._onDidChangeToolList.event;
94 >
95 > private readonly _onDidChangePromptList = this._register(new Emitter<void>());
96 > readonly onDidChangePromptList = this._onDidChangePromptList.event;
97 >
98 > /**
99 > * Connects to the MCP server and does the initialization handshake.
100 > * @throws MpcResponseError if the server fails to initialize.
101 > */
102 > public static async create(instaService: IInstantiationService, opts: IMcpServerRequestHandlerOptions, token?: CancellationToken) {
103 const mcp = new McpServerRequestHandler(opts);
104 const store = new DisposableStore();
155 }
156 }
158 > public readonly logger: ILogger;
159 > private readonly _launch: IMcpMessageTransport;
160 > private readonly _requestLogLevel: LogLevel;
161 > private readonly _createMessageRequestHandler: IMcpServerRequestHandlerOptions['createMessageRequestHandler'];
162 > private readonly _elicitationRequestHandler: IMcpServerRequestHandlerOptions['elicitationRequestHandler'];
163 > private readonly _taskManager: McpTaskManager;
164 >
165 > protected constructor({
166 launch,
167 logger,
218 }));
219 }
221 > /**
222 > * Send a client request to the server and return the response.
223 > *
224 > * @param request The request to send
225 > * @param token Cancellation token
226 > * @param timeoutMs Optional timeout in milliseconds
227 > * @returns A promise that resolves with the response
228 > */
229 > private async sendRequest<T extends MCP.ClientRequest, R extends MCP.ServerResult>(
230 request: Pick<T, 'params' | 'method'>,
231 token: CancellationToken = CancellationToken.None
246 });
247 }
249 > private send(mcp: MCP.JSONRPCMessage) {
250 if (canLog(this.logger.getLevel(), this._requestLogLevel)) { // avoid building the string if we don't need to
251 log(this.logger, this._requestLogLevel, `[editor -> server] ${JSON.stringify(mcp)}`);
254 this._launch.send(mcp);
255 }
257 > /**
258 > * Handles paginated requests by making multiple requests until all items are retrieved.
259 > *
260 > * @param method The method name to call
261 > * @param getItems Function to extract the array of items from a result
262 > * @param initialParams Initial parameters
263 > * @param token Cancellation token
264 > * @returns Promise with all items combined
265 > */
266 > private async *sendRequestPaginated<T extends MCP.PaginatedRequest & MCP.ClientRequest, R extends MCP.PaginatedResult, I>(method: T['method'], getItems: (result: R) => I[], initialParams?: Omit<T['params'], 'jsonrpc' | 'id'>, token: CancellationToken = CancellationToken.None): AsyncIterable<I[]> {
267 let nextCursor: MCP.Cursor | undefined = undefined;
268
278 } while (nextCursor !== undefined && !token.isCancellationRequested);
279 }
281 > private sendNotification<N extends MCP.ClientNotification>(notification: Omit<N, 'jsonrpc'>): void {
282 this.send({ ...notification, jsonrpc: MCP.JSONRPC_VERSION });
283 }
285 > /**
286 > * Handle incoming server requests
287 > */
288 > private handleServerRequest(request: MCP.JSONRPCRequest & MCP.ServerRequest, token: CancellationToken): MCP.Result | Promise<MCP.Result> {
289 const mapError = (error: unknown): JsonRpcError => {
290 if (error instanceof McpError) {
352 }
353 }
355 > * Handle incoming server notifications
356 > */
357 > private handleServerNotification(request: MCP.JSONRPCNotification & MCP.ServerNotification): void {
358 try {
359 switch (request.method) {
391 }
392 }
394 > private handleCancelledNotification(request: MCP.CancelledNotification): void {
395 if (request.params.requestId) {
396 this._rpc.cancelPendingRequest(request.params.requestId);
397 }
398 }
400 > private handleLoggingNotification(request: MCP.LoggingMessageNotification): void {
401 translateMcpLogMessage(this.logger, request.params);
402 }
404 > /**
405 > * Send a response to a ping request
406 > */
407 > private handlePing(_request: MCP.PingRequest): {} {
408 return {};
409 }
411 > /**
412 > * Send a response to a roots/list request
413 > */
414 > private handleRootsList(_request: MCP.ListRootsRequest): MCP.ListRootsResult {
415 this._hasAnnouncedRoots = true;
416 return { roots: this._roots };
417 }
419 > private cancelAllRequests() {
420 this._rpc.cancelAllRequests();
421 }
423 > public override dispose(): void {
424 this.cancelAllRequests();
425 super.dispose();
426 }
428 > /**
429 > * Forwards log level changes to the MCP server if it supports logging
430 > */
431 > private async _sendLogLevelToServer(logLevel: LogLevel): Promise<void> {
432 try {
433 // Only send if the server supports logging capabilities
441 }
442 }
444 > /**
445 > * Send an initialize request
446 > */
447 > initialize(params: MCP.InitializeRequest['params'], token?: CancellationToken): Promise<MCP.InitializeResult> {
448 return this.sendRequest<MCP.InitializeRequest, MCP.InitializeResult>({ method: 'initialize', params }, token);
449 }
451 > /**
452 > * List available resources
453 > */
454 > listResources(params?: MCP.ListResourcesRequest['params'], token?: CancellationToken): Promise<MCP.Resource[]> {
455 return Iterable.asyncToArrayFlat(this.listResourcesIterable(params, token));
456 }
458 > /**
459 > * List available resources (iterable)
460 > */
461 > listResourcesIterable(params?: MCP.ListResourcesRequest['params'], token?: CancellationToken): AsyncIterable<MCP.Resource[]> {
462 return this.sendRequestPaginated<MCP.ListResourcesRequest, MCP.ListResourcesResult, MCP.Resource>('resources/list', result => result.resources, params, token);
463 }
465 > /**
466 > * Read a specific resource
467 > */
468 > readResource(params: MCP.ReadResourceRequest['params'], token?: CancellationToken): Promise<MCP.ReadResourceResult> {
469 return this.sendRequest<MCP.ReadResourceRequest, MCP.ReadResourceResult>({ method: 'resources/read', params }, token);
470 }
472 > /**
473 > * List available resource templates
474 > */
475 > listResourceTemplates(params?: MCP.ListResourceTemplatesRequest['params'], token?: CancellationToken): Promise<MCP.ResourceTemplate[]> {
476 return Iterable.asyncToArrayFlat(this.sendRequestPaginated<MCP.ListResourceTemplatesRequest, MCP.ListResourceTemplatesResult, MCP.ResourceTemplate>('resources/templates/list', result => result.resourceTemplates, params, token));
477 }
479 > /**
480 > * Subscribe to resource updates
481 > */
482 > subscribe(params: MCP.SubscribeRequest['params'], token?: CancellationToken): Promise<MCP.EmptyResult> {
483 return this.sendRequest<MCP.SubscribeRequest, MCP.EmptyResult>({ method: 'resources/subscribe', params }, token);
484 }
486 > /**
487 > * Unsubscribe from resource updates
488 > */
489 > unsubscribe(params: MCP.UnsubscribeRequest['params'], token?: CancellationToken): Promise<MCP.EmptyResult> {
490 return this.sendRequest<MCP.UnsubscribeRequest, MCP.EmptyResult>({ method: 'resources/unsubscribe', params }, token);
491 }
493 > /**
494 > * List available prompts
495 > */
496 > listPrompts(params?: MCP.ListPromptsRequest['params'], token?: CancellationToken): Promise<MCP.Prompt[]> {
497 return Iterable.asyncToArrayFlat(this.sendRequestPaginated<MCP.ListPromptsRequest, MCP.ListPromptsResult, MCP.Prompt>('prompts/list', result => result.prompts, params, token));
498 }
500 > /**
501 > * Get a specific prompt
502 > */
503 > getPrompt(params: MCP.GetPromptRequest['params'], token?: CancellationToken): Promise<MCP.GetPromptResult> {
504 return this.sendRequest<MCP.GetPromptRequest, MCP.GetPromptResult>({ method: 'prompts/get', params }, token);
505 }
507 > /**
508 > * List available tools
509 > */
510 > listTools(params?: MCP.ListToolsRequest['params'], token?: CancellationToken): Promise<MCP.Tool[]> {
511 return Iterable.asyncToArrayFlat(this.sendRequestPaginated<MCP.ListToolsRequest, MCP.ListToolsResult, MCP.Tool>('tools/list', result => result.tools, params, token));
512 }
514 > /**
515 > * Call a specific tool. Supports tasks automatically if `task` is set on the request.
516 > */
517 > async callTool(params: MCP.CallToolRequest['params'] & MCP.Request['params'], token?: CancellationToken, onStatusMessage?: (message: string) => void): Promise<MCP.CallToolResult> {
518 const response = await this.sendRequest<MCP.CallToolRequest, MCP.CallToolResult | MCP.CreateTaskResult>({ method: 'tools/call', params }, token);
519
530
531 }
533 > /**
534 > * Set the logging level
535 > */
536 > setLevel(params: MCP.SetLevelRequest['params'], token?: CancellationToken): Promise<MCP.EmptyResult> {
537 return this.sendRequest<MCP.SetLevelRequest, MCP.EmptyResult>({ method: 'logging/setLevel', params }, token);
538 }
540 > /**
541 > * Find completions for an argument
542 > */
543 > complete(params: MCP.CompleteRequest['params'], token?: CancellationToken): Promise<MCP.CompleteResult> {
544 return this.sendRequest<MCP.CompleteRequest, MCP.CompleteResult>({ method: 'completion/complete', params }, token);
545 }
547 > /**
548 > * Get task status
549 > */
550 > getTask(params: { taskId: string }, token?: CancellationToken): Promise<MCP.GetTaskResult> {
551 return this.sendRequest<MCP.GetTaskRequest, MCP.GetTaskResult>({ method: 'tasks/get', params }, token);
552 }
554 > /**
555 > * Get task result
556 > */
557 > getTaskResult(params: { taskId: string }, token?: CancellationToken): Promise<MCP.GetTaskPayloadResult> {
558 return this.sendRequest<MCP.GetTaskPayloadRequest, MCP.GetTaskPayloadResult>({ method: 'tasks/result', params }, token);
559 }
561 > /**
562 > * Cancel a task
563 > */
564 > cancelTask(params: { taskId: string }, token?: CancellationToken): Promise<MCP.CancelTaskResult> {
565 return this.sendRequest<MCP.CancelTaskRequest, MCP.CancelTaskResult>({ method: 'tasks/cancel', params }, token);
566 }
568 > /**
569 > * List all tasks
570 > */
571 > listTasks(params?: MCP.ListTasksRequest['params'], token?: CancellationToken): Promise<MCP.Task[]> {
572 return Iterable.asyncToArrayFlat(
573 this.sendRequestPaginated<MCP.ListTasksRequest, MCP.ListTasksResult, MCP.Task>(
576 );
577 }
579 >
580 function isTaskInTerminalState(task: MCP.Task): boolean {
581 return task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled';
582 }
584 > /**
585 > * Implementation of a task that handles polling, status notifications, and handler reconnections. It implements the task polling loop internally and can also be
586 > * updated externally via `onDidUpdateState`, when notifications are received
587 > * for example.
588 > * @internal
589 > */
590 > export class McpTask<T extends MCP.Result> extends Disposable implements IMcpTaskInternal {
591 > private readonly promise = new DeferredPromise<T>();
592 >
593 > public get result(): Promise<T> {
594 > return this.promise.p;
595 > }
596 >
597 > public get id() {
598 return this._task.taskId;
599 }
601 > private _lastTaskState: ISettableObservable<MCP.Task>;
602 > private _handler = observableValue<McpServerRequestHandler | undefined>('mcpTaskHandler', undefined);
603 >
604 > constructor(
605 private readonly _task: MCP.Task,
606 _token: CancellationToken = CancellationToken.None,
734 }));
735 }
737 > onDidUpdateState(task: MCP.Task) {
738 this._lastTaskState.set(task, undefined);
739 if (task.statusMessage && this._onStatusMessage) {
741 }
742 }
744 > setHandler(handler: McpServerRequestHandler | undefined): void {
745 this._handler.set(handler, undefined);
746 }
748 >
749 > /**
750 > * Maps VSCode LogLevel to MCP LoggingLevel
751 > */
752 function mapLogLevelToMcp(logLevel: LogLevel): MCP.LoggingLevel {
753 switch (logLevel) {
src/vs/workbench/contrib/mcp/test/common/mcpRegistryTypes.ts 105 introduced LOC · 23 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpRegistryTypes.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Emitter, Event } from '../../../../../base/common/event.js';
7 > import { Disposable, IDisposable } from '../../../../../base/common/lifecycle.js';
8 > import { IObservable, observableValue } from '../../../../../base/common/observable.js';
9 > import { ConfigurationTarget } from '../../../../../platform/configuration/common/configuration.js';
10 > import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
11 > import { LogLevel, NullLogger } from '../../../../../platform/log/common/log.js';
12 > import { StorageScope } from '../../../../../platform/storage/common/storage.js';
13 > import { IWorkspaceFolderData } from '../../../../../platform/workspace/common/workspace.js';
14 > import { IResolvedValue } from '../../../../services/configurationResolver/common/configurationResolverExpression.js';
15 > import { IMcpHostDelegate, IMcpMessageTransport, IMcpRegistry, IMcpResolveConnectionOptions } from '../../common/mcpRegistryTypes.js';
16 > import { McpServerConnection } from '../../common/mcpServerConnection.js';
17 > import { IMcpServerConnection, LazyCollectionState, McpCollectionDefinition, McpCollectionReference, McpConnectionState, McpDefinitionReference, McpServerDefinition, McpServerTransportType, McpServerTrust } from '../../common/mcpTypes.js';
18 > import { MCP } from '../../common/modelContextProtocol.js';
19 >
20 > /**
21 > * Implementation of IMcpMessageTransport for testing purposes.
22 > * Allows tests to easily send/receive messages and control the connection state.
23 > */
24 > export class TestMcpMessageTransport extends Disposable implements IMcpMessageTransport {
25 > private readonly _onDidLog = this._register(new Emitter<{ level: LogLevel; message: string }>());
26 > public readonly onDidLog = this._onDidLog.event;
27 >
28 > private readonly _onDidReceiveMessage = this._register(new Emitter<MCP.JSONRPCMessage>());
29 > public readonly onDidReceiveMessage = this._onDidReceiveMessage.event;
30 >
31 > private readonly _stateValue = observableValue<McpConnectionState>('testTransportState', { state: McpConnectionState.Kind.Starting });
32 > public readonly state = this._stateValue;
33 >
34 > private readonly _sentMessages: MCP.JSONRPCMessage[] = [];
35 >
36 > constructor() {
37 super();
38
57 }));
58 }
60 > /**
61 > * Set a responder function for a specific method.
62 > * The responder receives the sent message and should return a response object,
63 > * which will be simulated as a server response.
64 > */
65 > public setResponder(method: string, responder: (message: unknown) => MCP.JSONRPCMessage | undefined): void {
66 if (!this._responders) {
67 this._responders = new Map();
69 this._responders.set(method, responder);
70 }
72 > private _responders?: Map<string, (message: MCP.JSONRPCMessage) => MCP.JSONRPCMessage | undefined>;
73 >
74 > /**
75 > * Send a message through the transport.
76 > */
77 > public send(message: MCP.JSONRPCMessage): void {
78 this._sentMessages.push(message);
79 if (this._responders && 'method' in message && typeof message.method === 'string') {
87 }
88 }
90 > /**
91 > * Stop the transport.
92 > */
93 > public stop(): void {
94 this._stateValue.set({ state: McpConnectionState.Kind.Stopped }, undefined);
95 }
97 > // Test Helper Methods
98 >
99 > /**
100 > * Simulate receiving a message from the server.
101 > */
102 > public simulateReceiveMessage(message: MCP.JSONRPCMessage): void {
103 this._onDidReceiveMessage.fire(message);
104 }
106 > /**
107 > * Simulates a reply to an 'initialized' request.
108 > */
109 > public simulateInitialized() {
110 if (!this._sentMessages.length) {
111 throw new Error('initialize was not called yet');
127 });
128 }
130 > /**
131 > * Simulate a log event.
132 > */
133 > public simulateLog(message: string): void {
134 this._onDidLog.fire({ level: LogLevel.Info, message });
135 }
137 > /**
138 > * Set the connection state.
139 > */
140 > public setConnectionState(state: McpConnectionState): void {
141 this._stateValue.set(state, undefined);
142 }
144 > /**
145 > * Get all messages that have been sent.
146 > */
147 > public getSentMessages(): readonly MCP.JSONRPCMessage[] {
148 return [...this._sentMessages];
149 }
151 > /**
152 > * Clear the sent messages history.
153 > */
154 > public clearSentMessages(): void {
155 this._sentMessages.length = 0;
156 }
158 >
159 > export class TestMcpRegistry implements IMcpRegistry {
160 > public makeTestTransport = () => new TestMcpMessageTransport();
161 >
162 > constructor(@IInstantiationService private readonly _instantiationService: IInstantiationService) { }
163
164 _serviceBrand: undefined;
193 }]);
194 lazyCollectionState = observableValue(this, { state: LazyCollectionState.AllKnown, collections: [] });
195 > collectionToolPrefix(collection: McpCollectionReference): IObservable<string> { mcpRegistryTypes.ts
196 return observableValue<string>(this, `mcp-${collection.id}-`);
197 }
198 > getServerDefinition(collectionRef: McpDefinitionReference, definitionRef: McpDefinitionReference): IObservable<{ server: McpServerDefinition | undefined; collection: McpCollectionDefinition | undefined }> { mcpRegistryTypes.ts
199 const collectionObs = this.collections.map(cols => cols.find(c => c.id === collectionRef.id));
200 return collectionObs.map((collection, reader) => {
203 });
204 }
205 > discoverCollections(): Promise<McpCollectionDefinition[]> { mcpRegistryTypes.ts
206 throw new Error('Method not implemented.');
207 }
208 > registerDelegate(delegate: IMcpHostDelegate): IDisposable { mcpRegistryTypes.ts
209 throw new Error('Method not implemented.');
210 }
211 > registerCollection(collection: McpCollectionDefinition): IDisposable { mcpRegistryTypes.ts
212 throw new Error('Method not implemented.');
213 }
214 > resetTrust(): void { mcpRegistryTypes.ts
215 throw new Error('Method not implemented.');
216 }
217 > clearSavedInputs(scope: StorageScope, inputId?: string): Promise<void> { mcpRegistryTypes.ts
218 throw new Error('Method not implemented.');
219 }
220 > editSavedInput(inputId: string, folderData: IWorkspaceFolderData | undefined, configSection: string, target: ConfigurationTarget): Promise<void> { mcpRegistryTypes.ts
221 throw new Error('Method not implemented.');
222 }
223 > setSavedInput(inputId: string, target: ConfigurationTarget, value: string): Promise<void> { mcpRegistryTypes.ts
224 throw new Error('Method not implemented.');
225 }
226 > getSavedInputs(scope: StorageScope): Promise<{ [id: string]: IResolvedValue }> { mcpRegistryTypes.ts
227 throw new Error('Method not implemented.');
228 }
229 > resolveConnection(options: IMcpResolveConnectionOptions): Promise<IMcpServerConnection | undefined> { mcpRegistryTypes.ts
230 const collection = this.collections.get().find(c => c.id === options.collectionRef.id);
231 const definition = collection?.serverDefinitions.get().find(d => d.id === options.definitionRef.id);
src/vs/workbench/contrib/mcp/common/mcpServerConnection.ts 47 introduced LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpServerConnection.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationTokenSource } from '../../../../base/common/cancellation.js';
7 > import { CancellationError } from '../../../../base/common/errors.js';
8 > import { Emitter } from '../../../../base/common/event.js';
9 > import { Disposable, DisposableStore, IReference, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
10 > import { autorun, IObservable, observableValue } from '../../../../base/common/observable.js';
11 > import { localize } from '../../../../nls.js';
12 > import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
13 > import { ILogger, log, LogLevel } from '../../../../platform/log/common/log.js';
14 > import { IMcpHostDelegate, IMcpMessageTransport } from './mcpRegistryTypes.js';
15 > import { McpServerRequestHandler } from './mcpServerRequestHandler.js';
16 > import { McpTaskManager } from './mcpTaskManager.js';
17 > import { IMcpClientMethods, IMcpPotentialSandboxBlock, IMcpServerConnection, McpCollectionDefinition, McpConnectionState, McpServerDefinition, McpServerLaunch } from './mcpTypes.js';
18 >
19 > export class McpServerConnection extends Disposable implements IMcpServerConnection {
20 > private readonly _launch = this._register(new MutableDisposable<IReference<IMcpMessageTransport>>());
21 > private readonly _state = observableValue<McpConnectionState>('mcpServerState', { state: McpConnectionState.Kind.Stopped });
22 > private readonly _requestHandler = observableValue<McpServerRequestHandler | undefined>('mcpServerRequestHandler', undefined);
23 > private readonly _onPotentialSandboxBlock = this._register(new Emitter<IMcpPotentialSandboxBlock>());
24 >
25 > public readonly state: IObservable<McpConnectionState> = this._state;
26 > public readonly handler: IObservable<McpServerRequestHandler | undefined> = this._requestHandler;
27 > public readonly onPotentialSandboxBlock = this._onPotentialSandboxBlock.event;
28 >
29 > constructor(
30 private readonly _collection: McpCollectionDefinition,
31 public readonly definition: McpServerDefinition,
39 super();
40 }
42 > /** @inheritdoc */
43 > public async start(methods: IMcpClientMethods): Promise<McpConnectionState> {
44 const currentState = this._state.get();
45 if (!McpConnectionState.canBeStarted(currentState.state)) {
64 }
65 }
67 > private adoptLaunch(launch: IMcpMessageTransport, methods: IMcpClientMethods): IReference<IMcpMessageTransport> {
68 const store = new DisposableStore();
69 const cts = new CancellationTokenSource();
120 return { dispose: () => store.dispose(), object: launch };
121 }
123 > public async stop(): Promise<void> {
124 this._logger.info(localize('mcpServer.stopping', 'Stopping server {0}', this.definition.label));
125 this._launch.value?.object.stop();
126 await this._waitForState(McpConnectionState.Kind.Stopped, McpConnectionState.Kind.Error);
127 }
129 > public override dispose(): void {
130 this._requestHandler.get()?.dispose();
131 super.dispose();
132 this._state.set({ state: McpConnectionState.Kind.Stopped }, undefined);
133 }
135 > private _waitForState(...kinds: McpConnectionState.Kind[]): Promise<McpConnectionState> {
136 const current = this._state.get();
137 if (kinds.includes(current.state)) {
149 });
150 }
152 > private _toPotentialSandboxBlock(message: string): IMcpPotentialSandboxBlock | undefined {
153 if (!this.definition.sandboxEnabled) {
154 return undefined;
173 return undefined;
174 }
176 > private _extractSandboxPath(line: string): string | undefined {
177 const bracketedPath = line.match(/\[(\/[^\]\r\n]+)\]/);
178 if (bracketedPath?.[1]) {
188 return trailingPath?.[1]?.trim();
189 }
191 > private _extractSandboxHost(value: string): string | undefined {
192 const match = value.match(/No matching config rule, denying:\s+(?<host>[^:\s]+):\d+\.?$/i);
193 return match?.groups?.host;
194 }
src/vs/workbench/contrib/mcp/common/mcpTaskManager.ts 4 introduced LOC · 1 range

Open complete file

37 */
38 export class McpTaskManager extends Disposable {
39 > private readonly _serverTasks = this._register(new DisposableMap<string, TaskEntry>()); mcpTaskManager.ts
40 > private readonly _clientTasks = this._register(new DisposableMap<string, IMcpTaskInternal>());
41 > private readonly _onDidUpdateTask = this._register(new Emitter<MCP.Task>());
42 > public readonly onDidUpdateTask = this._onDidUpdateTask.event;
43
44 /**
src/vs/workbench/test/common/workbenchTestServices.ts 2 introduced LOC · 1 range

Open complete file

47 export class TestLoggerService extends AbstractLoggerService {
48 constructor(logsHome?: URI) {
49 > super(LogLevel.Info, logsHome ?? URI.file('tests').with({ scheme: 'vscode-tests' })); workbenchTestServices.ts
50 > }
51 protected doCreateLogger(): ILogger { return new NullLogger(); }
52 }