Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { emptyWorkspaceInfo, getWorkingDirectory, IWorkspaceInfo } from '../../c
import { buildChatHistoryFromEvents, RequestIdDetails, stripReminders } from '../common/copilotCLITools';
import { ICustomSessionTitleService } from '../common/customSessionTitleService';
import { IChatDelegationSummaryService } from '../common/delegationSummaryService';
import { SessionIdForCLI } from '../common/utils';
import { getCopilotCLISessionDir, getCopilotCLISessionEventsFile, getCopilotCLIWorkspaceFile } from './cliHelpers';
import { getAgentFileNameFromFilePath, ICopilotCLIAgents, ICopilotCLISDK } from './copilotCli';
import { CopilotCliBridgeSpanProcessor } from './copilotCliBridgeSpanProcessor';
Expand Down Expand Up @@ -536,7 +537,8 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
}

public async createSession(options: ICreateSessionOptions, token: CancellationToken): Promise<RefCountedSession> {
const { mcpConfig: mcpServers, disposable: mcpGateway } = await this.mcpHandler.loadMcpConfig();
const resource = options.sessionId ? SessionIdForCLI.getResource(options.sessionId) : URI.from({ scheme: 'copilot-cli', path: `mcp-gateway-${generateUuid()}` });
const { mcpConfig: mcpServers, disposable: mcpGateway } = await this.mcpHandler.loadMcpConfig(resource);
try {
const sessionOptions = await this.createSessionsOptions({ ...options, mcpServers });
const sessionManager = await raceCancellationError(this.getSessionManager(), token);
Expand Down Expand Up @@ -726,7 +728,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS

const [sessionManager, { mcpConfig: mcpServers, disposable: mcpGateway }] = await Promise.all([
raceCancellationError(this.getSessionManager(), token),
this.mcpHandler.loadMcpConfig(),
this.mcpHandler.loadMcpConfig(SessionIdForCLI.getResource(options.sessionId)),
]);
try {
const sessionOptions = await this.createSessionsOptions({ ...options, mcpServers });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { createServiceIdentifier } from '../../../../util/common/services';
import { Disposable, DisposableStore, IDisposable } from '../../../../util/vs/base/common/lifecycle';
import { hasKey } from '../../../../util/vs/base/common/types';
import { URI } from '../../../../util/vs/base/common/uri';
import { generateUuid } from '../../../../util/vs/base/common/uuid';
import type { LanguageModelToolInformation } from '../../../../vscodeTypes';
import { GitHubMcpDefinitionProvider } from '../../../githubMcp/common/githubMcpDefinitionProvider';

Expand All @@ -34,7 +33,7 @@ export type MCPServerConfig = NonNullable<Session['mcpServers']>[string];

export interface ICopilotCLIMCPHandler {
readonly _serviceBrand: undefined;
loadMcpConfig(): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }>;
loadMcpConfig(sessionUri: URI): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }>;
}

export const ICopilotCLIMCPHandler = createServiceIdentifier<ICopilotCLIMCPHandler>('ICopilotCLIMCPHandler');
Expand All @@ -48,15 +47,15 @@ export class CopilotCLIMCPHandler implements ICopilotCLIMCPHandler {
@IMcpService private readonly mcpService: IMcpService,
) { }

public async loadMcpConfig(): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }> {
public async loadMcpConfig(sessionUri: URI): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }> {

// TODO: Sessions window settings override is not honored with extension
// configuration API, so this needs to be a core setting
const isSessionsWindow = this.configurationService.getNonExtensionConfig<boolean>('chat.experimentalSessionsWindowOverride') ?? false;

// Sessions window: use the gateway approach which proxies all MCP servers from core
if (isSessionsWindow) {
return this.loadMcpConfigWithGateway();
return this.loadMcpConfigWithGateway(sessionUri);
}

// Standard path: use the CLIMCPServerEnabled setting
Expand All @@ -65,7 +64,7 @@ export class CopilotCLIMCPHandler implements ICopilotCLIMCPHandler {

if (enabled) {
this.logService.info('[CopilotCLIMCPHandler] MCP server forwarding is enabled, using gateway configuration');
return this.loadMcpConfigWithGateway();
return this.loadMcpConfigWithGateway(sessionUri);
}

const processedConfig: Record<string, MCPServerConfig> = {};
Expand All @@ -79,11 +78,11 @@ export class CopilotCLIMCPHandler implements ICopilotCLIMCPHandler {
/**
* Use the Gateway to handle all connections
*/
private async loadMcpConfigWithGateway(): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }> {
private async loadMcpConfigWithGateway(sessionUri: URI): Promise<{ mcpConfig: Record<string, MCPServerConfig> | undefined; disposable: IDisposable }> {
const mcpConfig: Record<string, MCPServerConfig> = {};
const disposable = new DisposableStore();
try {
const gateway = await this.mcpService.startMcpGateway(URI.from({ scheme: 'copilot-cli', path: `mcp-gateway-${generateUuid()}` }));
const gateway = await this.mcpService.startMcpGateway(sessionUri);
if (gateway) {
disposable.add(gateway);
for (const server of gateway.servers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class NullICopilotCLIImageSupport implements ICopilotCLIImageSupport {

export class NullCopilotCLIMCPHandler implements ICopilotCLIMCPHandler {
_serviceBrand: undefined;
async loadMcpConfig(): Promise<{ mcpConfig: Record<string, NonNullable<SessionOptions['mcpServers']>[string]> | undefined; disposable: IDisposable }> {
async loadMcpConfig(_resource: URI): Promise<{ mcpConfig: Record<string, NonNullable<SessionOptions['mcpServers']>[string]> | undefined; disposable: IDisposable }> {
return { mcpConfig: undefined, disposable: Disposable.None };
}
}
Loading