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
11 changes: 11 additions & 0 deletions src/vs/base/common/htmlContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { illegalArgument } from './errors.js';
import { escapeIcons } from './iconLabels.js';
import { Schemas } from './network.js';
import { isEqual } from './resources.js';
import { escapeRegExpCharacters } from './strings.js';
import { URI, UriComponents } from './uri.js';
Expand Down Expand Up @@ -201,3 +202,13 @@ export function parseHrefAndDimensions(href: string): { href: string; dimensions
}
return { href, dimensions };
}

export function markdownCommandLink(command: { title: string; id: string; arguments?: unknown[] }): string {
const uri = URI.from({
scheme: Schemas.command,
path: command.id,
query: command.arguments?.length ? encodeURIComponent(JSON.stringify(command.arguments)) : undefined,
}).toString();

return `[${escapeMarkdownSyntaxTokens(command.title)}](${uri})`;
}
10 changes: 8 additions & 2 deletions src/vs/workbench/api/node/extHostMpcNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,15 @@ export class NodeExtHostMpcService extends ExtHostMcpService {

child.on('spawn', () => this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Running }));

child.on('error', onError);
child.on('error', e => {
if (abortCtrl.signal.aborted) {
this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Stopped });
} else {
onError(e);
}
});
child.on('exit', code =>
code === 0
code === 0 || abortCtrl.signal.aborted
? this._proxy.$onDidChangeState(id, { state: McpConnectionState.Kind.Stopped })
: this._proxy.$onDidChangeState(id, {
state: McpConnectionState.Kind.Error,
Expand Down
11 changes: 10 additions & 1 deletion src/vs/workbench/contrib/mcp/browser/mcp.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,39 @@ import { ConfigMcpDiscovery } from '../common/discovery/configMcpDiscovery.js';
import { ExtensionMcpDiscovery } from '../common/discovery/extensionMcpDiscovery.js';
import { mcpDiscoveryRegistry } from '../common/discovery/mcpDiscovery.js';
import { RemoteNativeMpcDiscovery } from '../common/discovery/nativeMcpRemoteDiscovery.js';
import { IMcpConfigPathsService, McpConfigPathsService } from '../common/mcpConfigPathsService.js';
import { mcpServerSchema } from '../common/mcpConfiguration.js';
import { McpContextKeysController } from '../common/mcpContextKeys.js';
import { McpRegistry } from '../common/mcpRegistry.js';
import { IMcpRegistry } from '../common/mcpRegistryTypes.js';
import { McpService } from '../common/mcpService.js';
import { IMcpService } from '../common/mcpTypes.js';
import { AddConfigurationAction, ListMcpServerCommand, MCPServerActionRendering, McpServerOptionsCommand, ResetMcpCachedTools, ResetMcpTrustCommand } from './mcpCommands.js';
import { AddConfigurationAction, EditStoredInput, ListMcpServerCommand, MCPServerActionRendering, McpServerOptionsCommand, RemoveStoredInput, ResetMcpCachedTools, ResetMcpTrustCommand, ShowOutput, StartServer, StopServer } from './mcpCommands.js';
import { McpDiscovery } from './mcpDiscovery.js';
import { McpLanguageFeatures } from './mcpLanguageFeatures.js';

registerSingleton(IMcpRegistry, McpRegistry, InstantiationType.Delayed);
registerSingleton(IMcpService, McpService, InstantiationType.Delayed);
registerSingleton(IMcpConfigPathsService, McpConfigPathsService, InstantiationType.Delayed);

mcpDiscoveryRegistry.register(new SyncDescriptor(RemoteNativeMpcDiscovery));
mcpDiscoveryRegistry.register(new SyncDescriptor(ConfigMcpDiscovery));
mcpDiscoveryRegistry.register(new SyncDescriptor(ExtensionMcpDiscovery));

registerWorkbenchContribution2('mcpDiscovery', McpDiscovery, WorkbenchPhase.AfterRestored);
registerWorkbenchContribution2('mcpContextKeys', McpContextKeysController, WorkbenchPhase.BlockRestore);
registerWorkbenchContribution2('mcpLanguageFeatures', McpLanguageFeatures, WorkbenchPhase.Eventually);

registerAction2(ListMcpServerCommand);
registerAction2(McpServerOptionsCommand);
registerAction2(ResetMcpTrustCommand);
registerAction2(ResetMcpCachedTools);
registerAction2(AddConfigurationAction);
registerAction2(RemoveStoredInput);
registerAction2(EditStoredInput);
registerAction2(StartServer);
registerAction2(StopServer);
registerAction2(ShowOutput);

registerWorkbenchContribution2('mcpActionRendering', MCPServerActionRendering, WorkbenchPhase.BlockRestore);

Expand Down
94 changes: 93 additions & 1 deletion src/vs/workbench/contrib/mcp/browser/mcpCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ import { IActionViewItemService } from '../../../../platform/actions/browser/act
import { MenuEntryActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { Action2, MenuId, MenuItemAction } from '../../../../platform/actions/common/actions.js';
import { ICommandService } from '../../../../platform/commands/common/commands.js';
import { ConfigurationTarget } from '../../../../platform/configuration/common/configuration.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js';
import { StorageScope } from '../../../../platform/storage/common/storage.js';
import { spinningLoading } from '../../../../platform/theme/common/iconRegistry.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
import { ActiveEditorContext, ResourceContextKey } from '../../../common/contextkeys.js';
import { IWorkbenchContribution } from '../../../common/contributions.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
Expand Down Expand Up @@ -205,7 +208,6 @@ export class McpServerOptionsCommand extends Action2 {
}
}


export class MCPServerActionRendering extends Disposable implements IWorkbenchContribution {
public static readonly ID = 'workbench.contrib.mcp.discovery';

Expand Down Expand Up @@ -412,3 +414,93 @@ export class AddConfigurationAction extends Action2 {
return accessor.get(IInstantiationService).createInstance(McpAddConfigurationCommand, configUri).run();
}
}


export class RemoveStoredInput extends Action2 {
static readonly ID = 'workbench.mcp.removeStoredInput';

constructor() {
super({
id: RemoveStoredInput.ID,
title: localize2('mcp.resetCachedTools', "Reset Cached Tools"),
category,
f1: false,
});
}

run(accessor: ServicesAccessor, scope: StorageScope, id?: string): void {
accessor.get(IMcpRegistry).clearSavedInputs(scope, id);
}
}

export class EditStoredInput extends Action2 {
static readonly ID = 'workbench.mcp.editStoredInput';

constructor() {
super({
id: EditStoredInput.ID,
title: localize2('mcp.editStoredInput', "Edit Stored Input"),
category,
f1: false,
});
}

run(accessor: ServicesAccessor, inputId: string, uri: URI | undefined, configSection: string, target: ConfigurationTarget): void {
const workspaceFolder = uri && accessor.get(IWorkspaceContextService).getWorkspaceFolder(uri);
accessor.get(IMcpRegistry).editSavedInput(inputId, workspaceFolder || undefined, configSection, target);
}
}

export class ShowOutput extends Action2 {
static readonly ID = 'workbench.mcp.showOutput';

constructor() {
super({
id: ShowOutput.ID,
title: localize2('mcp.command.showOutput', "Show Output"),
category,
f1: false,
});
}

run(accessor: ServicesAccessor, serverId: string): void {
accessor.get(IMcpService).servers.get().find(s => s.definition.id === serverId)?.showOutput();
}
}

export class StartServer extends Action2 {
static readonly ID = 'workbench.mcp.startServer';

constructor() {
super({
id: StartServer.ID,
title: localize2('mcp.command.startServer', "Start Server"),
category,
f1: false,
});
}

async run(accessor: ServicesAccessor, serverId: string) {
const s = accessor.get(IMcpService).servers.get().find(s => s.definition.id === serverId);
await s?.stop();
await s?.start();
}
}

export class StopServer extends Action2 {
static readonly ID = 'workbench.mcp.stopServer';

constructor() {
super({
id: StopServer.ID,
title: localize2('mcp.command.stopServer', "Stop Server"),
category,
f1: false,
});
}

async run(accessor: ServicesAccessor, serverId: string) {
const s = accessor.get(IMcpService).servers.get().find(s => s.definition.id === serverId);
await s?.stop();
}
}
Loading
Loading