豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit ed2aef2

Browse files
feat: enhance MCP gateway handling to support multiple servers and improve error logging (#4470)
* feat: enhance MCP gateway handling to support multiple servers and improve error logging * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Updates * Updates --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent c01995a commit ed2aef2

File tree

8 files changed

+83
-36
lines changed

8 files changed

+83
-36
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,7 +4480,7 @@
44804480
},
44814481
"github.copilot.chat.cli.mcp.enabled": {
44824482
"type": "boolean",
4483-
"default": false,
4483+
"default": true,
44844484
"markdownDescription": "%github.copilot.config.cli.mcp.enabled%",
44854485
"tags": [
44864486
"advanced",
@@ -6267,5 +6267,5 @@
62676267
"node-gyp": "npm:node-gyp@10.3.1",
62686268
"zod": "3.25.76"
62696269
},
6270-
"vscodeCommit": "6f7de9c47ab13c3d886928c04c382d527c9bf11d"
6270+
"vscodeCommit": "6f5263699012243ac0e0b5f8381fcd86ff503b2b"
62716271
}

src/extension/chatSessions/claude/node/claudeCodeAgent.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,20 @@ export class ClaudeCodeSession extends Disposable {
391391
const mcpServers: Record<string, McpServerConfig> = await buildMcpServersFromRegistry(this.instantiationService) ?? {};
392392

393393
// Create or reuse the MCP gateway for this session
394-
this._gateway ??= await this.mcpService.startMcpGateway(ClaudeSessionUri.forSessionId(this.sessionId)) ?? undefined;
395-
if (this._gateway) {
396-
mcpServers['vscode-mcp-gateway'] = {
397-
type: 'http',
398-
url: this._gateway.address.toString(),
399-
};
394+
try {
395+
this._gateway ??= await this.mcpService.startMcpGateway(ClaudeSessionUri.forSessionId(this.sessionId)) ?? undefined;
396+
if (this._gateway) {
397+
for (const server of this._gateway.servers) {
398+
const serverId = server.label.toLowerCase().replace(/[^a-z0-9_-]/g, '_').replace(/^_+|_+$/g, '') || `vscode-mcp-server-${Object.keys(mcpServers).length}`;
399+
mcpServers[serverId] = {
400+
type: 'http',
401+
url: server.address.toString(),
402+
};
403+
}
404+
}
405+
} catch (error) {
406+
const errorMessage = error instanceof Error ? (error.stack ?? error.message) : String(error);
407+
this.logService.warn(`[ClaudeCodeSession] Failed to start MCP gateway: ${errorMessage}`);
400408
}
401409
const options: Options = {
402410
cwd,

src/extension/chatSessions/copilotcli/node/mcpHandler.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,17 @@ export class CopilotCLIMCPHandler implements ICopilotCLIMCPHandler {
7373
const gateway = await this.mcpService.startMcpGateway(URI.from({ scheme: 'copilot-cli', path: `mcp-gateway-${generateUuid()}` }));
7474
if (gateway) {
7575
disposable.add(gateway);
76-
mcpConfig['vscode-mcp-gateway'] = {
77-
type: 'http',
78-
url: gateway.address.toString(),
79-
isDefaultServer: true,
80-
tools: ['*'],
81-
displayName: 'VS Code MCP Gateway',
82-
};
76+
for (const server of gateway.servers) {
77+
const serverId = this.normalizeServerName(server.label) ?? `vscode-mcp-server-${Object.keys(mcpConfig).length}`;
78+
mcpConfig[serverId] = {
79+
type: 'http',
80+
url: server.address.toString(),
81+
tools: ['*'],
82+
displayName: server.label,
83+
};
84+
}
8385
const serverIds = Object.keys(mcpConfig);
84-
this.logService.trace(`[CopilotCLIMCPHandler] gateway: ${gateway.address.toString()}, server(s): [${serverIds.join(', ')}]`);
86+
this.logService.trace(`[CopilotCLIMCPHandler] gateway started, server(s): [${serverIds.join(', ')}]`);
8587
} else {
8688
this.logService.warn('[CopilotCLIMCPHandler] gateway failed to start');
8789
disposable.dispose();

src/extension/vscode.proposed.chatSessionsProvider.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ declare module 'vscode' {
9999
readonly prompt: string;
100100
readonly command?: string;
101101
};
102+
103+
readonly sessionOptions: ReadonlyArray<{ optionId: string; value: string | ChatSessionProviderOptionItem }>;
102104
}
103105

104106
/**
@@ -447,10 +449,13 @@ declare module 'vscode' {
447449
*
448450
* @param resource The URI of the chat session to resolve.
449451
* @param token A cancellation token that can be used to cancel the operation.
452+
* @param context Additional context for the chat session.
450453
*
451454
* @return The {@link ChatSession chat session} associated with the given URI.
452455
*/
453-
provideChatSessionContent(resource: Uri, token: CancellationToken): Thenable<ChatSession> | ChatSession;
456+
provideChatSessionContent(resource: Uri, token: CancellationToken, context: {
457+
readonly sessionOptions: ReadonlyArray<{ optionId: string; value: string | ChatSessionProviderOptionItem }>;
458+
}): Thenable<ChatSession> | ChatSession;
454459

455460
/**
456461
* @param resource Identifier of the chat session being updated.
@@ -483,10 +488,11 @@ declare module 'vscode' {
483488
*
484489
* @param scheme The uri-scheme to register for. This must be unique.
485490
* @param provider The provider to register.
491+
* @param defaultChatParticipant The default {@link ChatParticipant chat participant} used in sessions provided by this provider.
486492
*
487493
* @returns A disposable that unregisters the provider when disposed.
488494
*/
489-
export function registerChatSessionContentProvider(scheme: string, provider: ChatSessionContentProvider, chatParticipant: ChatParticipant, capabilities?: ChatSessionCapabilities): Disposable;
495+
export function registerChatSessionContentProvider(scheme: string, provider: ChatSessionContentProvider, defaultChatParticipant: ChatParticipant, capabilities?: ChatSessionCapabilities): Disposable;
490496
}
491497

492498
export interface ChatContext {

src/extension/vscode.proposed.mcpServerDefinitions.d.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,47 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
// version: 1
7+
68
declare module 'vscode' {
79

810
// https://github.com/microsoft/vscode/issues/288777 @DonJayamanne
911

1012
/**
11-
* Represents an MCP gateway that exposes MCP servers via HTTP.
12-
* The gateway provides an HTTP endpoint that external processes can connect
13-
* to in order to interact with MCP servers known to the editor.
13+
* Represents a single MCP server exposed by the gateway via its own HTTP endpoint.
1414
*/
15-
export interface McpGateway extends Disposable {
15+
export interface McpGatewayServer {
16+
/**
17+
* The human-readable label of the MCP server.
18+
*/
19+
readonly label: string;
20+
1621
/**
1722
* The address of the HTTP MCP server endpoint.
18-
* External processes can connect to this URI to interact with MCP servers.
23+
* External processes can connect to this URI to interact with this MCP server.
1924
*/
2025
readonly address: Uri;
2126
}
2227

28+
/**
29+
* Represents an MCP gateway that exposes MCP servers via HTTP.
30+
* Each known MCP server gets its own HTTP endpoint. The gateway
31+
* dynamically tracks server additions and removals.
32+
*/
33+
export interface McpGateway extends Disposable {
34+
/**
35+
* The MCP servers currently exposed by the gateway.
36+
* Each server has its own HTTP endpoint address.
37+
*/
38+
readonly servers: readonly McpGatewayServer[];
39+
40+
/**
41+
* Event that fires when the set of gateway servers changes.
42+
* This can be due to MCP servers being added, removed, or restarted.
43+
*/
44+
readonly onDidChangeServers: Event<readonly McpGatewayServer[]>;
45+
}
46+
2347
/**
2448
* Namespace for language model related functionality.
2549
*/
@@ -42,14 +66,16 @@ declare module 'vscode' {
4266
export const onDidChangeMcpServerDefinitions: Event<void>;
4367

4468
/**
45-
* Starts an MCP gateway that exposes MCP servers via an HTTP endpoint.
69+
* Starts an MCP gateway that exposes MCP servers via HTTP endpoints.
4670
*
47-
* The gateway creates a localhost HTTP server that external processes (such as
48-
* CLI-based agent loops) can connect to in order to interact with MCP servers
49-
* that the editor knows about.
71+
* The gateway creates a localhost HTTP server where each MCP server known
72+
* to the editor gets its own endpoint. External processes (such as CLI-based
73+
* agent loops) can connect to these endpoints to interact with individual
74+
* MCP servers.
5075
*
5176
* The HTTP server is shared among all gateways and is automatically torn down
52-
* when the last gateway is disposed.
77+
* when the last gateway is disposed. The gateway dynamically tracks server
78+
* additions and removals via {@link McpGateway.onDidChangeServers}.
5379
*
5480
* @returns A promise that resolves to an {@link McpGateway} if successful,
5581
* or `undefined` if no Node process is available (e.g., in serverless web environments).

src/platform/configuration/common/configurationService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ export namespace ConfigKey {
610610
export const CLICustomAgentsEnabled = defineAndMigrateSetting<boolean | undefined>('chat.advanced.cli.customAgents.enabled', 'chat.cli.customAgents.enabled', true);
611611
export const CLIPlanModeEnabled = defineAndMigrateSetting<boolean | undefined>('chat.advanced.cli.planMode.enabled', 'chat.cli.planMode.enabled', false);
612612
export const CLIPlanExitModeEnabled = defineSetting<boolean>('chat.cli.planExitMode.enabled', ConfigType.Simple, false);
613-
export const CLIMCPServerEnabled = defineAndMigrateSetting<boolean | undefined>('chat.advanced.cli.mcp.enabled', 'chat.cli.mcp.enabled', false);
613+
export const CLIMCPServerEnabled = defineAndMigrateSetting<boolean | undefined>('chat.advanced.cli.mcp.enabled', 'chat.cli.mcp.enabled', true);
614614
export const CLIBranchSupport = defineSetting<boolean>('chat.cli.branchSupport.enabled', ConfigType.Simple, false);
615615
export const CLIIsolationOption = defineSetting<boolean>('chat.cli.isolationOption.enabled', ConfigType.Simple, true);
616616
export const CLICheckpointsEnabled = defineSetting<boolean>('chat.cli.checkpoints.enabled', ConfigType.Simple, false);

src/platform/mcp/vscode/mcpServiceImpl.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { McpGateway, Uri, lm } from 'vscode';
6+
import { McpGateway, McpGatewayServer, lm, type Event } from 'vscode';
77
import { IDisposable } from '../../../util/vs/base/common/lifecycle';
88
import { ResourceMap } from '../../../util/vs/base/common/map';
99
import { URI } from '../../../util/vs/base/common/uri';
10-
import { AbstractMcpService } from '../common/mcpService';
1110
import { ILogService } from '../../log/common/logService';
11+
import { AbstractMcpService } from '../common/mcpService';
1212

1313
class TrackedMcpGateway implements McpGateway {
1414
constructor(
1515
private readonly _gateway: McpGateway,
1616
private readonly _onDispose: () => void
1717
) { }
1818

19-
get address(): Uri {
20-
return this._gateway.address;
19+
get servers(): readonly McpGatewayServer[] {
20+
return this._gateway.servers;
21+
}
22+
23+
get onDidChangeServers(): Event<readonly McpGatewayServer[]> {
24+
return this._gateway.onDidChangeServers;
2125
}
2226

2327
dispose(): void {

src/platform/mcp/vscode/test/mcpService.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import { McpService } from '../mcpServiceImpl';
2424

2525
function createMockGateway() {
2626
return {
27-
address: { toString: () => 'http://localhost:1234' },
27+
servers: [{ label: 'test-server', address: { toString: () => 'http://localhost:1234' } }],
28+
onDidChangeServers: () => ({ dispose() { } }),
2829
dispose: vi.fn(),
2930
};
3031
}
@@ -53,7 +54,7 @@ describe('McpService', () => {
5354
const result = await service.startMcpGateway(resource1);
5455

5556
expect(result).toBeDefined();
56-
expect(result!.address).toBe(mockGateway.address);
57+
expect(result!.servers).toBe(mockGateway.servers);
5758
expect(mockStartMcpGateway).toHaveBeenCalledOnce();
5859
});
5960

@@ -122,7 +123,7 @@ describe('McpService', () => {
122123

123124
const second = await service.startMcpGateway(resource1);
124125
expect(second).toBeDefined();
125-
expect(second!.address).toBe(mockGateway.address);
126+
expect(second!.servers).toBe(mockGateway.servers);
126127
});
127128

128129
test('disposing a gateway removes it from tracking', async () => {

0 commit comments

Comments
 (0)