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();