Configuring MCP Servers
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page is written against the Claude Code CLI 2.1.283, VS Code 1.139 with the GitHub Copilot Chat extension, and the GitHub Copilot CLI 1.0.88, all re-verified as current as of 2026-09-28; re-check the linked docs before relying on an exact flag or key name, since MCP tooling changes fast across all three products.
An MCP (Model Context Protocol) server is a separate process, local or remote, that exposes tools, resources or prompts to an agent over a standard protocol — for example, a server that queries the DocsAssistant API sample’s own Postgres database directly instead of the agent guessing at the schema from source, the same scenario Agent Mode introduces. This page covers using an existing MCP server: where its configuration lives, how to add one, and how its tools are named for permissions. Building one — the server side of the protocol — belongs to the Model Context Protocol (MCP) sub-section, out of scope here.
.mcp.json and scopes in Claude Code
Claude Code resolves a server’s configuration from three scopes, verified against Claude Code — Connect Claude Code to tools via MCP, listed here from highest to lowest precedence:
| Scope | File | Shared with the team? |
|---|---|---|
Local (default) |
A project-specific entry inside |
No — personal to the current project on this machine |
Project |
|
Yes — meant to be committed, so every teammate gets the same servers |
User |
The top-level |
No — personal, but available across every project |
A project-scope .mcp.json uses the same mcpServers object other MCP-aware tools read:
.mcp.json{
"mcpServers": {
"docsassistant-db": {
"type": "http",
"url": "https://mcp.internal.example.com/docsassistant-db"
}
}
}
Because the file is committed, it holds no secret values directly — see the environment-variable syntax
below. A server added at project scope asks for one-time approval the first time each teammate’s interactive
session loads it; claude -p and other non-interactive runs load it without prompting.
claude mcp add
claude mcp add writes a server into one of the three scopes above (local unless you pass --scope),
verified against the same reference. Its key flags:
| Flag | Purpose |
|---|---|
|
Which scope to write to: |
|
The server’s transport: |
|
Sets one |
|
Sets one HTTP header, e.g. for an |
A remote http server, added at project scope so the whole team shares it:
$ claude mcp add --transport http --scope project docsassistant-db \
https://mcp.internal.example.com/docsassistant-db
A local stdio server, started as a child process. Everything after the -- separator is the command and its
own arguments, untouched by Claude’s own flag parsing:
$ export DOCSASSISTANT_DB_DSN="postgresql://readonly:<password>@localhost:5432/docsassistant"
$ claude mcp add --transport stdio --scope local docsassistant-db \
-- npx -y @bytebase/dbhub --dsn "$DOCSASSISTANT_DB_DSN"
The shell expands $DOCSASSISTANT_DB_DSN before Claude Code sees it, so local scope stores the resulting
connection string in plain text in ~/.claude.json — outside the repository, but still on disk; use a
read-only database user, as the official DBHub example does. See
Claude Code — Add a local stdio server.
Never write a real password, token or connection string into a committed .mcp.json. For a project-scope
server, reference an environment variable instead of a literal value; Claude Code expands ${VAR} (and
${VAR:-default} with a fallback) from each developer’s own shell when it loads the server:
.mcp.json (project scope, no secret committed){
"mcpServers": {
"docsassistant-db": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${DOCSASSISTANT_DB_DSN}"]
}
}
}
claude mcp list shows every configured server and its health status (a project server nobody has approved yet
shows as pending approval); /mcp inside a running session shows the same and lets you authenticate an
OAuth-backed server.
VS Code’s mcp.json
VS Code reads its own workspace file, .vscode/mcp.json, using a top-level servers object rather than
mcpServers, verified against
VS Code — Add and manage MCP servers in VS
Code. It also reads a portable, project-root .mcp.json (the same mcpServers shape Claude Code writes) and
a user-profile mcp.json opened with the MCP: Open User Configuration command; MCP: Add Server from the
Command Palette walks through adding a server with either Workspace or Global as the target.
For a value that must not be committed, an inputs entry makes VS Code prompt for it (masked, when
"password": true) the first time the server starts, and substitutes it wherever ${input:<id>} appears — verified against
VS
Code — MCP configuration reference: input variables for sensitive data:
.vscode/mcp.json{
"inputs": [
{
"type": "promptString",
"id": "docsassistant-dsn",
"description": "DocsAssistant read-only Postgres DSN",
"password": true
}
],
"servers": {
"docsassistant-db": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${input:docsassistant-dsn}"]
}
}
}
An envFile field pointing at an uncommitted file (for example "envFile": "${workspaceFolder}/.env") is the
other option VS Code’s docs describe for a value that should not live in the committed configuration at all.
The Copilot cloud-agent MCP config
The Copilot cloud agent (formerly the coding agent: the agent that works unattended and opens a pull request,
covered on Cloud & Background Agents) reads
its MCP configuration from the repository’s settings on GitHub.com (Settings > Copilot > MCP servers), not
from a file in the repository; Copilot code review shares the same configuration. Verified against
GitHub
Copilot — Configure MCP servers for your repository, it takes the same mcpServers JSON shape and adds a
required tools allowlist per server:
{
"mcpServers": {
"docsassistant-db": {
"type": "local",
"command": "npx",
"args": ["-y", "@bytebase/dbhub"],
"env": {
"DSN": "$COPILOT_MCP_DOCSASSISTANT_DSN"
},
"tools": ["search_objects"]
}
}
}
tools names exactly which tools the agent may call from that server — here only DBHub’s read-only schema
browser, search_objects, not its execute_sql tool. GitHub’s docs strongly recommend allowlisting specific,
read-only tools rather than "", because the cloud agent calls them autonomously and never asks for approval
once the server is configured. A secret referenced from this JSON must first be added as an *Agents secret or
variable whose name is prefixed COPILOT_MCP_; only secrets and variables with that prefix are made available
to the configuration, referenced as $COPILOT_MCP_<NAME> or ${COPILOT_MCP_<NAME>} (with an
optional ${COPILOT_MCP_<NAME>:-default} fallback) — never as a literal value in the JSON itself.
Tool naming for permissions
Once a server is connected, each tool it exposes appears to Claude Code as mcp<server-name><tool-name>,
verified against Claude Code — Connect Claude Code to tools via MCP. That name is what
a permissions.allow / ask / deny rule matches, the same rule syntax
Permissions & Settings covers for built-in
tools:
.claude/settings.json — allow one MCP tool without prompting, keep another behind a prompt{
"permissions": {
"allow": [
"mcp__docsassistant-db__search_objects"
],
"ask": [
"mcp__docsassistant-db__execute_sql"
]
}
}
A rule naming just the server, mcpdocsassistant-db, or its glob form mcpdocsassistant-db*, matches
every tool the server exposes (permission rules use globs, unlike the regular-expression matchers of
hooks, which write the same thing as mcpdocsassistant-db__.*).
As an allow rule that is useful for a server you trust completely, but it removes the per-tool review a
narrower rule gives you, the same allow/deny
trade-off Permissions & Settings covers more broadly. Once a server is
added, Agent Mode covers the session-level mechanics of using
its tools — the tools picker, per-call approvals and /mcp — rather than repeating that ground here.
Bundling MCP in plugins
A Claude Code plugin can ship its own MCP server configuration — a .mcp.json at the plugin’s root, or an
inline mcpServers field in its manifest — so enabling the plugin connects the server automatically instead
of asking every user to hand-edit their own .mcp.json:
.claude-plugin/plugin.json (excerpt){
"name": "docsassistant-tools",
"mcpServers": {
"db": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server"
}
}
}
${CLAUDE_PLUGIN_ROOT} resolves to the plugin’s installation directory. A plugin-bundled server’s tools get a
plugin-scoped name, mcpplugin_<plugin-name>_<server-name><tool-name> — here
mcpplugin_docsassistant-tools_db<tool> — so permission rules, allowed-tools lists and hook matchers
written against the bare mcpdb… form never match them. See
Claude Code — Plugin-provided MCP servers.
The packaging mechanism, its manifest fields and a complete plugin are covered on
Plugins & Marketplaces; MCP servers are one of the component kinds,
alongside skills, agents and hooks, that a plugin can distribute.