Skip to content

Conversation

@connor4312
Copy link
Member

This adds initial support for MCP discovery and connections in VS Code.

  • It finds servers installed in claude_desktop_config as a demo, and also supports .vscode/mcp.json
  • This works for both local and remotes.
  • There is a command MCP: List Servers that allows listing and manually starting/stopping servers
  • When MCP servers are started, they can be used as tools in chat.

Granular changes can be found in commits within this PR. Closes #242864, more issues will come under the chat-mcp tag for future work.

connor4312 and others added 11 commits March 9, 2025 12:14
This is some basic work to get MCP hooked up. It's enough to discover
and establish connections to MCP servers on the machine with very very
basic commands to manage them:

![](https://memes.peet.io/img/25-03-2220f93e-3d1f-41ab-867e-0b9ba616ec6f.mp4)

Refs #242864

The McpRegistry registers both collections of servers (from various
config files) and 'delegates', which is currently _only_ the node
extension host but is pretty generic and so could point at other
processes in the future. SSE could even be served from the renderer when
we aren't on a remote.

It wraps into IMcpServerConnection's, which do some basic connection
management and expose the McpServerRequestHandler which speaks JSON-RPC
to the MCP server. This is wrapped into the IMcpServer which is the
complete, stateful representation of the server. It does stuff like
caching discovered tools such that they can be viewed and controlled
even when the MCP server isn't running.

The IMcpService is the 'public' entry for other VS Code features. Its
API is very simple right now, exposing an observable of the available
servers, which should be easy for chat to consume.

Still need to get some good tests going, add proper and more discovery,
and excercise currently-untested API. SSE is also a stub right now.
- register mcp server tools as tools
- add `IMcpTool#id`
- make sure `callOn` awaits result before disposing fyi @connor4312
- There's an mcpDiscoveryRegistry that allows components to register in
  how they discover MCP servers.
- Config discovery is one of these. Figured out all the bits for a
  standalone file config shebang. Duplication there that could be
  cleaned up but it works.
- The others are remote and local filesystem discovery. I ended up
  making another message channel for the main process/remote server to
  get a couple environment variables we need since I didn't see anything
  generic for this already(?)

![](https://memes.peet.io/img/25-03-29927218-daa9-4206-8cef-29992850d9ba.mp4)
@connor4312 connor4312 self-assigned this Mar 11, 2025
@connor4312 connor4312 enabled auto-merge March 11, 2025 17:01
@connor4312 connor4312 changed the title mcp: initial mpc work mcp: initial work Mar 11, 2025
@vs-code-engineering vs-code-engineering bot added this to the March 2025 milestone Mar 11, 2025
Copy link
Member

@bpasero bpasero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, is there more things planned for the channel in the future that warrant it to be its own thing?

I suggest to use ProxyChannel.fromService, you don't have to implement the channel yourself.

//cc @sandy081 for config changes

@bpasero bpasero requested a review from sandy081 March 11, 2025 17:14
@connor4312
Copy link
Member Author

connor4312 commented Mar 11, 2025

Curious, is there more things planned for the channel in the future that warrant it to be its own thing?

Not right now. But I didn't see that we had other ways to get environment variables outside of the common ones from IEnvironmentService/IRemoteEnvironment. I'd be very happy to do away with the extra channel if there's something I missed. Or maybe we put APPDATA and the XDG_CONFIG_HOME directory in these two interfaces, although it's quite possible we'll need more values later. What do you think?

@connor4312
Copy link
Member Author

actually, I suggest keeping the channel for now regardless since I might need to do more on-machine stuff for other configs over the next few days. But I'll move to ProxyChannel.fromService.

@connor4312 connor4312 requested a review from bpasero March 11, 2025 17:54
Copy link
Member

@roblourens roblourens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet


for (const pick of picks) {
if (pick.type === 'item' && !seen.has(pick.tool)) {
pick.tool.updateEnablement(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose in the future the enablement state could be per-chat view, wouldn't worry about it for now...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was thinking about this and wanna do that but ATM we don't have a way to express this. Tools only have the global when-clause and doing something session-specific would require new API which enables certain tools only for certain sessions. Like sending along tools with the request like ChatRequest#toolReferences but without the reference treatment, e.g without the rendering

async prepareToolInvocation(parameters, token) {
return {
confirmationMessages: {
title: localize('aaa', "Run tool from {0}", server.definition.label),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should figure out how to have a nicer looking confirmation message, and auto-run at some point of course. You might want to fill in the localization ids at least

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any problem with 3P extensions being able to call these? I suppose not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to fill in the localization ids at least

I think nls ids aren't surfaces anywhere, afaik it's all array indicies and not even the translators see them. We only use them as dedupe-key (which could be inferred from the value and extra-args). That we still write them is debt and we could do what we have done for the API - just strings w/o ids

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should figure out how to have a nicer looking confirmation message, and auto-run at some point of course.

Enlighten me. Is there more/better API for this? Ideally something that works for all tool calls and not special-cases for MCP-tools vs normal tools

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'm just thinking more along the lines of something like a "display name" for these tools, but maybe that doesn't exist in MCP?

Probably this confirmation should include the arguments too?

@connor4312 connor4312 dismissed bpasero’s stale review March 11, 2025 21:47

addressed, future changes can be in future PRs!

@connor4312 connor4312 merged commit 279244f into main Mar 11, 2025
8 checks passed
@connor4312 connor4312 deleted the connor4312/mcp-1 branch March 11, 2025 21:47
@iwangbowen
Copy link

Awesome

@vs-code-engineering vs-code-engineering bot locked and limited conversation to collaborators Apr 25, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discover and run MCP servers

6 participants