mcpServer.ts ×36

Frontier kind: Code frontier

unlabeled · c_be93e06b8c5a

8 tests · 42282 LOC · 190 files · introduces 0 tests · 246 LOC · 10 files

Introduces — evidence that enters the hierarchy at this concept

Code
59 ranges246 lines · 10 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4191 ranges42282 lines · 190 files · Browse complete extent
All tests (intent)
8 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.

10 files ranked by introduced lines: 246 introduced LOC across 59 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/contrib/mcp/common/mcpServer.ts 183 introduced LOC · 36 ranges

Open complete file

197 /** Sets cached primitives for a server */
198 store(definitionId: string, entry: Partial<IToolCacheEntry>): void {
199 > const prev = this.get(definitionId) || emptyToolEntry; mcpServer.ts
200 > this.cache.set(definitionId, { ...prev, ...entry });
201 > this.didChange = true;
202 > }
203
204 /** Gets cached servers for a collection (used for extensions, before the extension activates) */
425 private readonly _capabilities: CachedPrimitive<number | undefined, number | undefined>;
426 public get capabilities() {
427 > return this._capabilities.value; mcpServer.ts
428 > }
429
430 private readonly _tools: CachedPrimitive<readonly IMcpTool[], readonly ValidatedMcpTool[]>;
545 const connection = this._connection.read(reader);
546 if (connection) {
547 > // Authoritative: the connection carries the fully resolved launch. mcpServer.ts
548 > return this._evaluatePolicy(this._identityFromLaunch(connection.launchDefinition));
549 > }
550 // At rest, only decide when we have a concrete, fully-resolved launch. If the definition
551 // has not been provided yet (e.g. a lazy/extension server before activation) or the launch
601 return;
602 }
603 > mcpServer.ts
604 > cnx.roots = workspaces.read(reader)
605 > .filter(w => w.uri.authority === (initialCollection.remoteAuthority || ''))
606 > .map(w => {
607 > let uri = URI.from(uriTransformer?.transformIncoming(w.uri) ?? w.uri);
608 > if (uri.scheme === Schemas.file) { // #271812
609 > uri = URI.file(normalizeDriveLetter(uri.fsPath, true));
610 > }
611 >
612 > return { name: w.name, uri: uri.toString() };
613 > });
614 }));
615
619 const handler = cnx?.handler.read(reader);
620 if (handler) {
621 > this._populateLiveData(handler, cnx?.definition.cacheNonce, reader.store); mcpServer.ts
622 } else if (this._tools) {
623 > this.resetLiveData(); mcpServer.ts
624 > }
625 }));
626
758
759 public start({ interaction, autoTrustChanges, promptType, debug, errorOnUserInteraction }: IMcpServerStartOpts = {}): Promise<McpConnectionState> {
760 > interaction?.participants.set(this.definition.id, { s: 'unknown' }); mcpServer.ts
761 >
762 > return this._connectionSequencer.queue<McpConnectionState>(async () => {
763 > // Evaluated against the definition here (no connection yet). `_policyBlock` re-evaluates
764 > // against the resolved launch once the connection exists (checked again below).
765 > const preStartBlock = this._policyBlock.get();
766 > if (preStartBlock) {
767 return preStartBlock;
768 }
769 > mcpServer.ts
770 > const activationEvent = mcpActivationEvent(this.collection.id.slice(extensionMcpCollectionPrefix.length));
771 > if (this._requiresExtensionActivation && !this._extensionService.activationEventIsDone(activationEvent)) {
772 await this._extensionService.activateByEvent(activationEvent);
773 await Promise.all(this._mcpRegistry.delegates.get()
779 }
780 }
781 > mcpServer.ts
782 > let connection = this._connection.get();
783 > this._isQuietStart = !!errorOnUserInteraction;
784 > if (connection && McpConnectionState.canBeStarted(connection.state.get().state)) {
785 connection.dispose();
786 connection = undefined;
787 this._connection.set(connection, undefined);
788 }
789 > mcpServer.ts
790 > if (!connection) {
791 > this._lastModeDebugged = !!debug;
792 > const that = this;
793 > connection = await this._mcpRegistry.resolveConnection({
794 > interaction,
795 > autoTrustChanges,
796 > promptType,
797 > trustNonceBearer: {
798 > get trustedAtNonce() { return that.trustedAtNonce; },
799 > set trustedAtNonce(nonce: string | undefined) { that.trustedAtNonce = nonce; }
800 > },
801 > logger: this._logger,
802 > collectionRef: this.collection,
803 > definitionRef: this.definition,
804 > debug,
805 > errorOnUserInteraction,
806 > taskManager: this._taskManager,
807 > });
808 > if (!connection) {
809 return { state: McpConnectionState.Kind.Stopped };
810 }
811 > mcpServer.ts
812 > if (this._store.isDisposed) {
813 connection.dispose();
814 return { state: McpConnectionState.Kind.Stopped };
815 }
816 > mcpServer.ts
817 > this._connection.set(connection, undefined);
818 >
819 > if (connection.definition.devMode) {
820 this.showOutput();
821 }
822 > } mcpServer.ts
823 >
824 > // Re-evaluate the policy against the *resolved* launch definition. Extension activation and
825 > // variable/input substitution during resolution can change the URL or command, so the
826 > // identity that actually launches may differ from the one checked before resolution.
827 > // `_policyBlock` now sees the live connection and uses its resolved launch.
828 > const resolvedBlock = this._policyBlock.get();
829 > if (resolvedBlock) {
830 this._connection.set(undefined, undefined); // dispose the just-resolved connection
831 return resolvedBlock;
832 }
833 > mcpServer.ts
834 > this._potentialSandboxBlocks.length = 0;
835 >
836 > const start = Date.now();
837 > let state = await connection.start({
838 > createMessageRequestHandler: (params, token) => this._samplingService.sample({
839 isDuringToolCall: this.runningToolCalls.size > 0,
840 server: this,
841 params,
842 }, token).then(r => r.sample),
843 > elicitationRequestHandler: async (req, token) => { mcpServer.ts
844 const serverInfo = connection.handler.get()?.serverInfo;
845 if (serverInfo) {
854 return r.value;
855 }
856 > }); mcpServer.ts
857 >
858 > this._telemetryService.publicLog2<ServerBootState, ServerBootStateClassification>('mcp/serverBootState', {
859 > state: McpConnectionState.toKindString(state.state),
860 > time: Date.now() - start,
861 > });
862 >
863 > // MCP servers that need auth can 'start' but will stop with an interaction-needed
864 > // error they first make a request. In this case, wait until the handler fully
865 > // initializes before resolving (throwing if it ends up needing auth)
866 > if (errorOnUserInteraction && state.state === McpConnectionState.Kind.Running) {
867 let disposable: IDisposable;
868 state = await new Promise<McpConnectionState>((resolve, reject) => {
884 }).finally(() => disposable.dispose());
885 }
886 > mcpServer.ts
887 > if (state.state === McpConnectionState.Kind.Error) {
888 let disposable: IDisposable;
889 state = await new Promise<McpConnectionState>((resolve, reject) => {
901 }).finally(() => disposable.dispose());
902 }
903 > mcpServer.ts
904 > return state;
905 > }).finally(() => {
906 > interaction?.participants.set(this.definition.id, { s: 'resolved' });
907 > });
908 > }
909
910 private showInteractiveError(cnx: IMcpServerConnection, error: McpConnectionState.Error, debug?: boolean) {
1052
1053 private resetLiveData() {
1054 > transaction(tx => { mcpServer.ts
1055 > this._tools.fromServerPromise.set(undefined, tx);
1056 > this._prompts.fromServerPromise.set(undefined, tx);
1057 > });
1058 > }
1059
1060 private async _normalizeTool(originalTool: MCP.Tool): Promise<ValidatedMcpTool | { error: string[] }> {
1158 */
1159 private _parseIcons(icons: MCP.Icons) {
1160 > const cnx = this._connection.get(); mcpServer.ts
1161 > if (!cnx) {
1162 return [];
1163 }
1164 > mcpServer.ts
1165 > return parseAndValidateMcpIcon(icons, cnx.launchDefinition, this._logger);
1166 > }
1167
1168 private _setServerTools(nonce: string | undefined, toolsPromise: Promise<MCP.Tool[]>, tx: ITransaction | undefined) {
1169 > const toolPromiseSafe = toolsPromise.then(async tools => { mcpServer.ts
1170 this._logger.info(`Discovered ${tools.length} tools`);
1171 const data = await this._getValidatedTools(tools);
1172 this._primitiveCache.store(this.definition.id, { tools: data, nonce });
1173 return { data, nonce };
1174 > }); mcpServer.ts
1175 > this._tools.fromServerPromise.set(new ObservablePromise(toolPromiseSafe), tx);
1176 > return toolPromiseSafe;
1177 > }
1178
1179 private _setServerPrompts(nonce: string | undefined, promptsPromise: Promise<MCP.Prompt[]>, tx: ITransaction | undefined) {
1180 > const promptsPromiseSafe = promptsPromise.then((result): { data: StoredMcpPrompt[]; nonce: string | undefined } => { mcpServer.ts
1181 > const data: StoredMcpPrompt[] = result.map(prompt => ({
1182 ...prompt,
1183 _icons: this._parseIcons(prompt)
1184 > })); mcpServer.ts
1185 > this._primitiveCache.store(this.definition.id, { prompts: data, nonce });
1186 > return { data, nonce };
1187 > });
1188 >
1189 > this._prompts.fromServerPromise.set(new ObservablePromise(promptsPromiseSafe), tx);
1190 > return promptsPromiseSafe;
1191 > }
1192
1193 private _toStoredMetadata(serverInfo?: MCP.Implementation, instructions?: string): StoredServerMetadata {
1194 > return { mcpServer.ts
1195 > serverName: serverInfo ? serverInfo.title || serverInfo.name : undefined,
1196 > serverInstructions: instructions,
1197 > serverIcons: serverInfo ? this._parseIcons(serverInfo) : undefined,
1198 > };
1199 > }
1200
1201 private _setServerMetadata(
1202 > nonce: string | undefined, mcpServer.ts
1203 > { serverInfo, instructions, capabilities }: { serverInfo: MCP.Implementation; instructions: string | undefined; capabilities: MCP.ServerCapabilities },
1204 > tx: ITransaction | undefined,
1205 > ) {
1206 > const serverMetadata: StoredServerMetadata = this._toStoredMetadata(serverInfo, instructions);
1207 > this._serverMetadata.fromServerPromise.set(ObservablePromise.resolved({ nonce, data: serverMetadata }), tx);
1208 >
1209 > const capabilitiesEncoded = encodeCapabilities(capabilities);
1210 > this._capabilities.fromServerPromise.set(ObservablePromise.resolved({ data: capabilitiesEncoded, nonce }), tx);
1211 > this._primitiveCache.store(this.definition.id, { ...serverMetadata, nonce, capabilities: capabilitiesEncoded });
1212 > }
1213
1214 private _populateLiveData(handler: McpServerRequestHandler, cacheNonce: string | undefined, store: DisposableStore) {
1215 > const cts = new CancellationTokenSource(); mcpServer.ts
1216 > store.add(toDisposable(() => cts.dispose(true)));
1217 >
1218 > const updateTools = (tx: ITransaction | undefined) => {
1219 > const toolPromise = handler.capabilities.tools ? handler.listTools({}, cts.token) : Promise.resolve([]);
1220 > return this._setServerTools(cacheNonce, toolPromise, tx);
1221 > };
1222 >
1223 > const updatePrompts = (tx: ITransaction | undefined) => {
1224 > const promptsPromise = handler.capabilities.prompts ? handler.listPrompts({}, cts.token) : Promise.resolve([]);
1225 > return this._setServerPrompts(cacheNonce, promptsPromise, tx);
1226 > };
1227 >
1228 > store.add(handler.onDidChangeToolList(() => {
1229 this._logger.info('Tool list changed, refreshing tools...');
1230 updateTools(undefined);
1231 > })); mcpServer.ts
1232 >
1233 > store.add(handler.onDidChangePromptList(() => {
1234 this._logger.info('Prompts list changed, refreshing prompts...');
1235 updatePrompts(undefined);
1236 > })); mcpServer.ts
1237 >
1238 > transaction(tx => {
1239 > this._setServerMetadata(cacheNonce, { serverInfo: handler.serverInfo, instructions: handler.serverInstructions, capabilities: handler.capabilities }, tx);
1240 > updatePrompts(tx);
1241 > const toolUpdate = updateTools(tx);
1242 >
1243 > toolUpdate.then(tools => {
1244 this._telemetryService.publicLog2<ServerBootData, ServerBootClassification>('mcp/serverBoot', {
1245 supportsLogging: !!handler.capabilities.logging,
1250 serverVersion: handler.serverInfo.version,
1251 });
1252 > }); mcpServer.ts
1253 > });
1254 > }
1255 }
1256
1290 }
1291
1292 > function encodeCapabilities(cap: MCP.ServerCapabilities): McpCapability { mcpServer.ts
1293 > let out = 0;
1294 > if (cap.logging) { out |= McpCapability.Logging; }
1295 > if (cap.completions) { out |= McpCapability.Completions; }
1296 > if (cap.prompts) {
1297 out |= McpCapability.Prompts;
1298 if (cap.prompts.listChanged) {
1300 }
1301 }
1302 > if (cap.resources) { mcpServer.ts
1303 > out |= McpCapability.Resources;
1304 > if (cap.resources.subscribe) {
1305 out |= McpCapability.ResourcesSubscribe;
1306 }
1307 > if (cap.resources.listChanged) { mcpServer.ts
1308 out |= McpCapability.ResourcesListChanged;
1309 }
1310 > } mcpServer.ts
1311 > if (cap.tools) {
1312 > out |= McpCapability.Tools;
1313 > if (cap.tools.listChanged) {
1314 out |= McpCapability.ToolsListChanged;
1315 }
1316 > } mcpServer.ts
1317 > return out;
1318 > }
1319
1320 export class McpTool implements IMcpTool {
src/vs/workbench/contrib/mcp/test/common/mcpRegistryTypes.ts 19 introduced LOC · 3 ranges

Open complete file

186 },
187 start: () => {
188 > const t = this.makeTestTransport(); mcpRegistryTypes.ts
189 > setTimeout(() => t.setConnectionState({ state: McpConnectionState.Kind.Running }));
190 > return t;
191 > },
192 waitForInitialProviderPromises: () => Promise.resolve(),
193 }]);
228 }
229 resolveConnection(options: IMcpResolveConnectionOptions): Promise<IMcpServerConnection | undefined> {
230 > const collection = this.collections.get().find(c => c.id === options.collectionRef.id); mcpRegistryTypes.ts
231 > const definition = collection?.serverDefinitions.get().find(d => d.id === options.definitionRef.id);
232 > if (!collection || !definition) {
233 throw new Error(`Collection or definition not found: ${options.collectionRef.id}, ${options.definitionRef.id}`);
234 }
235 > const del = this.delegates.get()[0]; mcpRegistryTypes.ts
236 > return Promise.resolve(new McpServerConnection(
237 > collection,
238 > definition,
239 > del,
240 > definition.launch,
241 > new NullLogger(),
242 > false,
243 > options.taskManager,
244 > this._instantiationService,
245 > ));
246 > }
247 }
src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.ts 16 introduced LOC · 5 ranges

Open complete file

227
228 private _decodeURI(uri: URI) {
229 > let definitionId: string; mcpResourceFilesystem.ts
230 > let resourceURL: URL;
231 > try {
232 > ({ definitionId, resourceURL } = McpResourceURI.toServer(uri));
233 > } catch (e) {
234 throw createFileSystemProviderError(String(e), FileSystemProviderErrorCode.FileNotFound);
235 }
237 > if (resourceURL.pathname.endsWith('/')) {
238 resourceURL.pathname = resourceURL.pathname.slice(0, -1);
239 }
241 > const server = this._mcpService.servers.get().find(s => s.definition.id === definitionId);
242 > if (!server) {
243 throw createFileSystemProviderError(`MCP server ${definitionId} not found`, FileSystemProviderErrorCode.FileNotFound);
244 }
246 > const cap = server.capabilities.get();
247 > if (cap !== undefined && !(cap & McpCapability.Resources)) {
248 throw createFileSystemProviderError(`MCP server ${definitionId} does not support resources`, FileSystemProviderErrorCode.FileNotFound);
249 }
251 > return { definitionId, resourceURI: resourceURL, server };
252 > }
253
254 private async _readURI(uri: URI, token?: CancellationToken) {
src/vs/workbench/contrib/mcp/common/mcpTypes.ts 9 introduced LOC · 5 ranges

Open complete file

743
744 export const toKindString = (s: McpConnectionState.Kind): string => {
745 > switch (s) { mcpTypes.ts
746 > case Kind.Stopped:
747 return 'stopped';
748 > case Kind.Starting: mcpTypes.ts
749 return 'starting';
750 > case Kind.Running: mcpTypes.ts
751 > return 'running';
752 > case Kind.Error:
753 return 'error';
754 > default: mcpTypes.ts
755 assertNever(s);
756 > } mcpTypes.ts
757 > };
758
759 /** Returns if the MCP state is one where starting a new server is valid */
src/vs/base/common/observableInternal/utils/promise.ts 7 introduced LOC · 2 ranges

Open complete file

45
46 public static resolved<T>(value: T): ObservablePromise<T> {
47 > return new ObservablePromise(Promise.resolve(value)); promise.ts
48 > }
49
50 private readonly _value = observableValue<PromiseResult<T> | undefined>(this, undefined);
69 return value;
70 }, error => {
71 > transaction(tx => { promise.ts
72 > /** @description onPromiseRejected */
73 > this._value.set(new PromiseResult<T>(undefined, error), tx);
74 > });
75 > throw error;
76 });
77 }
src/vs/base/common/observableInternal/observables/observableValue.ts 4 introduced LOC · 3 ranges

Open complete file

115 export class DisposableObservableValue<T extends IDisposable | undefined, TChange = void> extends ObservableValue<T, TChange> implements IDisposable {
116 protected override _setValue(newValue: T): void {
117 > if (this._value === newValue) { observableValue.ts
118 return;
119 }
120 > if (this._value) { observableValue.ts
121 this._value.dispose();
122 }
123 > this._value = newValue; observableValue.ts
124 > }
125
126 public dispose(): void {
src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts 4 introduced LOC · 2 ranges

Open complete file

67
68 public get serverInfo(): MCP.Implementation {
69 > return this._serverInit.serverInfo; mcpServerRequestHandler.ts
70 > }
71
72 public get serverInstructions(): string | undefined {
73 > return this._serverInit.instructions; mcpServerRequestHandler.ts
74 > }
75
76 // Event emitters for server notifications
src/vs/base/common/observableInternal/observables/derived.ts 2 introduced LOC · 1 range

Open complete file

174 store = new DisposableStore();
175 } else {
176 > store.clear(); derived.ts
177 > }
178 const result = computeFn(r);
179 if (result) {
src/vs/base/common/buffer.ts 1 introduced LOC · 1 range

Open complete file

493 return s - 87;
494 } else if (s >= 65 && s <= 70) { // 'A'-'F'
495 > return s - 55; buffer.ts
496 } else {
497 throw new SyntaxError(`Invalid hex character at position ${position}`);
src/vs/workbench/contrib/mcp/common/mcpConfiguration.ts 1 introduced LOC · 1 range

Open complete file

23 */
24 export const mcpActivationEvent = (contributedCollectionId: string) =>
25 > mcpActivationEventPrefix + contributedCollectionId; mcpConfiguration.ts
26
27 export const enum DiscoverySource {