Guide · IDE Integration

MCP server in VS Code

Visual Studio Code added built-in MCP support in version 1.99 (April 2025). MCP servers configured in .vscode/mcp.json or user settings are automatically discovered, their tools are surfaced in GitHub Copilot Chat's agent mode, and the Output panel shows every JSON-RPC message exchanged. This guide covers the complete setup path: configuration file format, HTTP vs stdio transport, tool invocation in Copilot Chat, API key injection with input variables, debugging protocol failures, and why your MCP server needs external monitoring when VS Code users depend on it.

TL;DR

Create .vscode/mcp.json in your workspace root with a servers object. Each entry is a named server with type ("http" or "stdio") and a URL or command. Restart VS Code (or use MCP: Restart Server from the Command Palette) — Copilot Chat will discover the server's tools automatically via tools/list and make them available in agent mode. View the raw protocol exchange in the Output panel: View → Output → MCP: <server-name>. Add AliveMCP monitoring so you know when the server is unreachable before developers start filing Copilot issues.

How VS Code discovers MCP servers

VS Code checks two locations for MCP server configurations, in priority order:

LocationScopeCommitted to git?Typical use
.vscode/mcp.jsonWorkspaceYes — shared with teamProject-specific MCP servers all contributors use
settings.json (mcp.servers key)UserNo — in ~/.config/Code/User/Personal MCP servers used across all workspaces

Workspace-scoped servers in .vscode/mcp.json only activate when the workspace is trusted (the VS Code Workspace Trust prompt). User-scoped servers in settings.json are available in all trusted workspaces. If the same server name appears in both locations, the workspace configuration wins.

VS Code sends an initialize JSON-RPC request to each configured server at startup and when you run MCP: Restart Server. It then calls tools/list to build the tool registry. The registry is refreshed automatically when the server sends a notifications/tools/list_changed notification — you do not need to restart VS Code when your tool list changes dynamically.

.vscode/mcp.json configuration format

The configuration file uses a servers object where each key is the server's display name in VS Code:

{
  "servers": {
    "my-api-tools": {
      "type": "http",
      "url": "https://api.example.com/mcp"
    },
    "local-dev-server": {
      "type": "http",
      "url": "http://localhost:3000/mcp"
    },
    "local-stdio-server": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/my-mcp-server/dist/index.js"],
      "env": {
        "NODE_ENV": "development"
      }
    }
  }
}

The configuration supports three server types:

TypeRequired fieldsWhen to use
"http"urlRemote or locally hosted MCP servers with HTTP/SSE transport. The server must implement the MCP Streamable HTTP transport (POST /mcp, GET /mcp for SSE). VS Code sends a single Content-Type: application/json POST for each request and handles SSE event streams on the GET channel.
"stdio"command, optionally args and envLocal MCP servers launched as subprocesses. VS Code starts the process, communicates over stdin/stdout with JSON-RPC newline-delimited messages, and kills the process when the workspace closes.
"sse"urlLegacy SSE-only transport (MCP spec before 2024-11-05). Use "http" for servers implementing the current Streamable HTTP transport instead.

For HTTP servers, VS Code includes Mcp-Session-Id headers on subsequent requests after the initialize handshake completes. Your server must echo the session ID in its response headers and route subsequent requests to the correct session context.

Injecting secrets with input variables

Do not put API keys in .vscode/mcp.json — the file is committed to git. VS Code supports input variable substitution that prompts the developer once and stores the value in the VS Code secret storage:

{
  "inputs": [
    {
      "id": "my-api-key",
      "type": "promptString",
      "description": "API key for my-api-tools server",
      "password": true
    }
  ],
  "servers": {
    "my-api-tools": {
      "type": "http",
      "url": "https://api.example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${input:my-api-key}"
      }
    },
    "local-stdio-server": {
      "type": "stdio",
      "command": "node",
      "args": ["dist/index.js"],
      "env": {
        "DATABASE_URL": "${input:database-url}",
        "API_SECRET": "${input:my-api-key}"
      }
    }
  }
}

When VS Code first connects to a server that uses ${input:…} variables, it prompts the developer for each value. The values are stored in VS Code's encrypted secret storage (via OS keychain on macOS/Windows, libsecret on Linux). Subsequent workspace opens do not re-prompt unless the developer clears the secrets via MCP: Clear Stored Inputs from the Command Palette.

For stdio servers, the environment variables set in env are merged with VS Code's process environment. This means PATH, HOME, and other shell environment variables are available to the subprocess without explicit configuration — useful if your stdio server spawns child processes that need the developer's shell environment.

Tool invocation in Copilot Chat agent mode

MCP tools appear in GitHub Copilot Chat when the chat is in agent mode. You enter agent mode by selecting the @workspace agent or choosing a custom MCP server agent from the agent picker. The tool selection dropdown (the tools button, with a tools-wrench icon) shows all tools from all connected MCP servers.

Copilot Chat invokes MCP tools by generating a tools/call JSON-RPC request with the tool name and arguments derived from the LLM's response. The tool call goes through an approval step:

Approval modeSettingBehavior
Always askDefaultVS Code shows the tool name + arguments inline in the chat; developer clicks "Allow" or "Block" before execution.
Allow for this sessionClick "Always Allow" on first promptSubsequent calls to the same tool in the same VS Code session run without prompting. Resets on VS Code restart.
Always allowClick "Always Allow" then "Remember"Permanently stored in user settings — the tool runs without prompt across all future sessions. Use only for read-only tools you fully trust.

Tools that modify files, call external APIs, or run shell commands should never be permanently allowed — the approval step is the last line of defense before an LLM-generated tool call executes. Your MCP server should implement tool annotations (readOnlyHint, destructiveHint) to signal the risk level to VS Code, which uses them to color-code the approval prompt.

The tool result is returned inline in the chat thread. If your tool returns content with type: "text", VS Code renders the text in the chat message. If the tool returns type: "image", VS Code renders the image inline. If the tool sets isError: true, Copilot Chat shows the error and may ask the user to try a different approach.

Debugging MCP connections in VS Code

The Output panel shows every JSON-RPC message exchanged with each MCP server. Open it with View → Output, then select MCP: <server-name> from the dropdown:

[2026-06-26 14:23:01] → initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "clientInfo": { "name": "Visual Studio Code", "version": "1.99.3" },
    "capabilities": { "sampling": {} }
  }
}

[2026-06-26 14:23:01] ← initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "serverInfo": { "name": "my-api-tools", "version": "1.2.0" },
    "capabilities": { "tools": {} }
  }
}

[2026-06-26 14:23:01] → notifications/initialized
{}

[2026-06-26 14:23:01] → tools/list
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

[2026-06-26 14:23:01] ← tools/list
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      { "name": "search_docs", "description": "Search documentation", "inputSchema": { ... } },
      { "name": "create_issue", "description": "Create a new issue", "inputSchema": { ... } }
    ]
  }
}

Common failure patterns visible in the Output panel:

Symptom in Output panelRoot causeFix
Connection timeout / no response after initializeServer unreachable (wrong URL, port not open, CORS blocking preflight)Test the URL directly with curl; check CORS headers on OPTIONS response
tools/list returns empty arrayTool registration code throws during startup; tools registered after initialize completesAdd startup logging; register tools synchronously before calling server.connect()
initialize returns wrong protocolVersionServer running old MCP SDK version not updated to 2024-11-05Update @modelcontextprotocol/sdk to latest; check version field in initialize response
Tool call returns isError: true with empty messageTool handler threw without returning an MCP error — SDK converted unhandled exception to isErrorAdd try/catch in tool handler; return { content: [{ type: "text", text: error.message }], isError: true }
SSE stream closes immediately after connectionServer not implementing the GET /mcp SSE endpoint; returning 404 or 405Implement the SSE stream endpoint; VS Code uses GET for server-to-client notifications

For stdio servers, the Output panel also shows stderr from the subprocess. Print diagnostic messages to stderr from your MCP server — they appear in the VS Code Output panel without interfering with the JSON-RPC protocol on stdout.

Per-workspace vs user-level server configuration

Choosing between workspace and user scope affects security, portability, and sharing:

ConsiderationWorkspace (.vscode/mcp.json)User (settings.json)
Shared with team via gitYes — all contributors get the same serversNo — personal to the developer's machine
Workspace trust requiredYes — untrusted workspaces skip MCPNo — user servers always available in trusted workspaces
Secrets in configUse input variables only — file is in gitCan use literal values — file is not shared, but still plaintext on disk
Server tied to repoYes — obvious which server belongs to which projectNo — must be general-purpose enough for all workspaces

The recommended pattern for team-shared MCP servers: put the server URL and non-secret configuration in .vscode/mcp.json (committed), and use ${input:…} variables for any secrets. Each developer is prompted once for their API key; after that, VS Code handles credential storage securely.

Add .vscode/mcp.json.example to your repository showing the structure with placeholder values, and add .vscode/mcp.json to .gitignore only if the configuration itself contains workspace-specific values that differ per developer. If all developers use the same server URL, commit the file.

Monitoring MCP servers that VS Code users depend on

When a team commits an MCP server to .vscode/mcp.json, every developer who opens the workspace connects to that server. A server outage silently breaks Copilot Chat tool calls for the entire team — VS Code shows "Tool unavailable" in the chat without explaining that the server is down vs the tool failed.

The monitoring gap is similar to Lambda: VS Code only sees the tool call result, not the underlying protocol health. An MCP server can return HTTP 200 on a liveness endpoint while the initialize handshake fails or tools/list returns an empty array — VS Code users experience this as "Copilot can't find any tools" with no error message.

AliveMCP runs a full protocol probe — initialize + tools/list + a sentinel tool call — every 60 seconds. When the probe fails, you get an alert before the first developer opens their VS Code and wonders why their MCP tools stopped working. Add your MCP server URL to AliveMCP monitoring as part of your server's deployment checklist.

Frequently asked questions

Which VS Code version added MCP support?

VS Code 1.99 (released April 2025) added the initial MCP server integration. The .vscode/mcp.json configuration format and the MCP Output panel were included in this release. Earlier versions do not support MCP — developers on VS Code <1.99 need to update before MCP tools appear in Copilot Chat.

Do I need GitHub Copilot to use MCP tools in VS Code?

Yes. MCP tool invocation in VS Code is exposed through GitHub Copilot Chat's agent mode. VS Code discovers and connects to MCP servers without Copilot, but the tool call surface is only available in the Copilot Chat panel. You cannot invoke MCP tools directly from the VS Code command palette without Copilot.

How do I restart an MCP server without restarting VS Code?

Open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P) and run MCP: Restart Server. VS Code shows a list of connected servers — select the one to restart. This closes the existing connection, re-reads the configuration, and re-connects. For stdio servers, VS Code kills and restarts the subprocess. For HTTP servers, VS Code re-sends initialize to the same URL.

Can I connect to an MCP server running on localhost during development?

Yes. Set "type": "http", "url": "http://localhost:3000/mcp" and VS Code connects to your local server. VS Code does not apply the same-origin restriction for MCP connections. If you're developing the MCP server, use the Output panel to watch live protocol messages as you add tools. Note: if the local server is not running, VS Code logs a connection error and continues — it does not block VS Code startup.

What CORS headers does my MCP server need for VS Code?

For HTTP-type MCP servers, VS Code sends requests from an extension-host origin (not a browser origin). Strict CORS enforcement from the server side is not required — VS Code's extension host is not subject to browser CORS restrictions. However, if your MCP server also serves browser clients, configure CORS headers correctly for browser use cases. The extension host MCP connection is not affected either way.

How do I share MCP server configuration with my team without exposing API keys?

Use the inputs array in .vscode/mcp.json with "password": true for sensitive values. The file is safe to commit because it contains only the input variable reference (${input:api-key}), not the actual value. Each developer is prompted once when they first open the workspace and VS Code stores the value in OS-level secure storage. If a developer's key rotates, they use MCP: Clear Stored Inputs to clear cached values and are re-prompted on the next connection.

Further reading

Know when your VS Code MCP server is down — before your team does

AliveMCP probes your MCP endpoint every 60 seconds with a full protocol check, so you're alerted before developers start asking why Copilot tools stopped working. Free for public endpoints.

Start monitoring free