1
>
/*---------------------------------------------------------------------------------------------
mcpServer.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 { AsyncIterableProducer, raceCancellationError, Sequencer } from '../../../../base/common/async.js';
7
>
import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
8
>
import { Iterable } from '../../../../base/common/iterator.js';
9
>
import * as json from '../../../../base/common/json.js';
10
>
import { normalizeDriveLetter } from '../../../../base/common/labels.js';
11
>
import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
12
>
import { LRUCache } from '../../../../base/common/map.js';
13
>
import { Schemas } from '../../../../base/common/network.js';
14
>
import { mapValues } from '../../../../base/common/objects.js';
15
>
import { autorun, autorunSelfDisposable, derived, derivedDisposable, disposableObservableValue, IDerivedReader, IObservable, IReader, ITransaction, observableFromEvent, ObservablePromise, observableValue, transaction } from '../../../../base/common/observable.js';
16
>
import { basename } from '../../../../base/common/resources.js';
17
>
import { URI } from '../../../../base/common/uri.js';
18
>
import { createURITransformer } from '../../../../base/common/uriTransformer.js';
19
>
import { generateUuid } from '../../../../base/common/uuid.js';
20
>
import { localize } from '../../../../nls.js';
21
>
import { ICommandService } from '../../../../platform/commands/common/commands.js';
22
>
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
23
>
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
24
>
import { IMcpServerIdentity } from '../../../../platform/mcp/common/allowedMcpServers.js';
25
>
import { IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js';
26
>
import { ILogger, ILoggerService } from '../../../../platform/log/common/log.js';
27
>
import { INotificationService, IPromptChoice, Severity } from '../../../../platform/notification/common/notification.js';
28
>
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
29
>
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
30
>
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
31
>
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
32
>
import { ConfigurationResolverExpression } from '../../../services/configurationResolver/common/configurationResolverExpression.js';
33
>
import { IEditorService } from '../../../services/editor/common/editorService.js';
34
>
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js';
35
>
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
36
>
import { IOutputService } from '../../../services/output/common/output.js';
37
>
import { chatSessionResourceToId } from '../../chat/common/model/chatUri.js';
38
>
import { ToolProgress } from '../../chat/common/tools/languageModelToolsService.js';
39
>
import { mcpActivationEvent } from './mcpConfiguration.js';
40
>
import { McpDevModeServerAttache } from './mcpDevMode.js';
41
>
import { McpIcons, parseAndValidateMcpIcon, StoredMcpIcons } from './mcpIcons.js';
42
>
import { IMcpRegistry } from './mcpRegistryTypes.js';
43
>
import { IMcpSandboxService } from './mcpSandboxService.js';
44
>
import { McpServerRequestHandler } from './mcpServerRequestHandler.js';
45
>
import { McpTaskManager } from './mcpTaskManager.js';
46
>
import { ElicitationKind, extensionMcpCollectionPrefix, IMcpElicitationService, IMcpIcons, IMcpPotentialSandboxBlock, IMcpPrompt, IMcpPromptMessage, IMcpResource, IMcpResourceTemplate, IMcpSamplingService, IMcpServer, IMcpServerConnection, IMcpServerStartOpts, IMcpTool, IMcpToolCallContext, McpCapability, McpCollectionDefinition, McpCollectionReference, McpConnectionFailedError, McpConnectionState, McpDefinitionReference, mcpPromptReplaceSpecialChars, McpResourceURI, McpServerCacheState, McpServerDefinition, McpServerLaunch, McpServerStaticToolAvailability, McpServerTransportType, McpToolName, McpToolVisibility, MpcResponseError, UserInteractionRequiredError } from './mcpTypes.js';
47
>
import { ContributionEnablementState, IEnablementModel } from '../../chat/common/enablement.js';
48
>
import { MCP } from './modelContextProtocol.js';
49
>
import { McpApps } from './modelContextProtocolApps.js';
50
>
import { UriTemplate } from '../../../../base/common/uriTemplate.js';
51
>
52
>
type ServerBootData = {
53
>
supportsLogging: boolean;
54
>
supportsPrompts: boolean;
55
>
supportsResources: boolean;
56
>
toolCount: number;
57
>
serverName: string;
58
>
serverVersion: string;
59
>
};
60
>
type ServerBootClassification = {
61
>
owner: 'connor4312';
62
>
comment: 'Details the capabilities of the MCP server';
63
>
supportsLogging: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Whether the server supports logging' };
64
>
supportsPrompts: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Whether the server supports prompts' };
65
>
supportsResources: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Whether the server supports resource' };
66
>
toolCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The number of tools the server advertises' };
67
>
serverName: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the MCP server' };
68
>
serverVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The version of the MCP server' };
69
>
};
70
>
71
>
type ElicitationTelemetryData = {
72
>
serverName: string;
73
>
serverVersion: string;
74
>
};
75
>
76
>
type ElicitationTelemetryClassification = {
77
>
owner: 'connor4312';
78
>
comment: 'Triggered when elictation is requested';
79
>
serverName: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the MCP server' };
80
>
serverVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The version of the MCP server' };
81
>
};
82
>
83
>
export type McpServerInstallData = {
84
>
serverName: string;
85
>
source: 'gallery' | 'local';
86
>
scope: string;
87
>
success: boolean;
88
>
error?: string;
89
>
hasInputs: boolean;
90
>
};
91
>
92
>
export type McpServerInstallClassification = {
93
>
owner: 'connor4312';
94
>
comment: 'MCP server installation event tracking';
95
>
serverName: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the MCP server being installed' };
96
>
source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Installation source (gallery or local)' };
97
>
scope: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Installation scope (user, workspace, etc.)' };
98
>
success: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Whether installation succeeded' };
99
>
error?: { classification: 'CallstackOrException'; purpose: 'FeatureInsight'; comment: 'Error message if installation failed' };
100
>
hasInputs: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Whether the server requires input configuration' };
101
>
};
102
>
103
>
type ServerBootState = {
104
>
state: string;
105
>
time: number;
106
>
};
107
>
type ServerBootStateClassification = {
108
>
owner: 'connor4312';
109
>
comment: 'Details the capabilities of the MCP server';
110
>
state: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The server outcome' };
111
>
time: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Duration in milliseconds to reach that state' };
112
>
};
113
>
114
>
type StoredMcpPrompt = MCP.Prompt & { _icons: StoredMcpIcons };
115
>
116
>
interface IToolCacheEntry {
117
>
readonly serverName: string | undefined;
118
>
readonly serverInstructions: string | undefined;
119
>
readonly serverIcons: StoredMcpIcons;
120
>
121
>
readonly trustedAtNonce: string | undefined;
122
>
123
>
readonly nonce: string | undefined;
124
>
/** Cached tools so we can show what's available before it's started */
125
>
readonly tools: readonly ValidatedMcpTool[];
126
>
/** Cached prompts */
127
>
readonly prompts: readonly StoredMcpPrompt[] | undefined;
128
>
/** Cached capabilities */
129
>
readonly capabilities: McpCapability | undefined;
130
>
}
131
>
132
>
const emptyToolEntry: IToolCacheEntry = {
133
>
serverName: undefined,
134
>
serverIcons: [],
135
>
serverInstructions: undefined,
136
>
trustedAtNonce: undefined,
137
>
nonce: undefined,
138
>
tools: [],
139
>
prompts: undefined,
140
>
capabilities: undefined,
141
>
};
142
>
143
>
interface IServerCacheEntry {
144
>
readonly servers: readonly McpServerDefinition.Serialized[];
145
>
}
146
>
147
>
const toolInvalidCharRe = /[^a-z0-9_-]/gi;
148
>
149
>
export class McpServerMetadataCache extends Disposable {
150
>
private didChange = false;
151
>
private readonly cache = new LRUCache<string, IToolCacheEntry>(128);
152
>
private readonly extensionServers = new Map</* collection ID */string, IServerCacheEntry>();
153
>
154
>
constructor(
155
scope: StorageScope,
156
@IStorageService storageService: IStorageService,