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 ~/.claude.json

No — personal to the current project on this machine

Project

.mcp.json at the repository root

Yes — meant to be committed, so every teammate gets the same servers

User

The top-level mcpServers entry inside ~/.claude.json

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

--scope (-s)

Which scope to write to: local, project or user.

--transport (-t)

The server’s transport: stdio, http or sse. A WebSocket (ws) server can’t be added this way; add it as JSON with claude mcp add-json instead.

--env (-e)

Sets one KEY=value environment variable for the server process; repeatable.

--header (-H)

Sets one HTTP header, e.g. for an Authorization bearer token; repeatable.

A remote http server, added at project scope so the whole team shares it:

In Claude Code — http transport
$ 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:

In Claude Code — stdio transport
$ 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:

Copilot cloud agent — MCP configuration (repository settings)
{
  "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.