DeepDojo.AIPublished 2026-11-13Updated 2026-11-13中文

When Claude Code Actually Needs an MCP Server

Claude CodeAI Coding

For everyday refactoring, every file is on your local disk, and Claude reads it all with its built-in tools. Slightly more realistic work outgrows a single machine. During code review, the code is local, but the twenty-odd latest review comments your team left on the PR live on the remote. To analyze a production order-loss bug, however well you understand the application logic, you still need to query the current transaction state in a read-only database.

These tasks need a safe channel to external systems to get their current state. That's what MCP (Model Context Protocol) is for. Think of it as a standard plug: Claude Code is the socket, and each MCP server is an adapter that connects to GitHub, Postgres, Jira, or your own internal APIs.

When you actually start connecting things, three questions tend to come up:

  • Which needs really call for MCP, and which are covered by local files, memory, or an existing CLI?
  • Which connection type suits remote services versus local tools, and how do you pass tokens without them landing in config files?
  • Should the configuration be personal or project-wide, and should environment variables have defaults?

Start with four questions that decide whether to connect at all. If you do connect, begin with one read-only service, learn its permissions and output format, then add more gradually.

01 What MCP does in the chain

Claude Code → MCP server → external service
                 │
                 ├─ Describes tool purpose and parameters
                 ├─ Handles connection, auth, and permissions
                 └─ Returns results, asking the user for more input when needed

An MCP server takes care of authentication, parameter validation, and result formatting, so you don't have to improvise a Python script or curl command every time. An MCP server can expose several kinds of capability:

CapabilityMeaningUse case
ToolsCallable toolsQuery, create, update, run external operations
PromptsPredefined promptsTurn a server's workflow into a slash command
ResourcesReferenceable resourcesReference docs, objects, or external data with @
ElicitationAsking the user for more informationMulti-step forms, confirmations, choices, missing fields

Tools take actions; prompts reuse workflows and show up as /mcp__<server>__<prompt>; resources are referenced as @server-name:protocol://resource/path; elicitation asks for structured details, such as priority or owner, before creating a ticket.

02 Where MCP, memory, and local files divide

MCP and memory both supply context, but they solve different problems:

NeedBetter fit
Long-term preferences, team rules, project backgroundMemory
Live data that changesMCP
Current tickets, merge requests, database stateMCP
Calling external APIs or internal toolsMCP
Fixed coding standardsMemory or CLAUDE.md

"It needs context" doesn't settle which one to use. Take a PR: the team's coding standards rarely change, so they go in memory; the current review state changes, so you query it live; if the same summary is already exported locally, just read the file. For where long-term rules belong, see where each Claude Code rule belongs in memory.

If a reliable CLI already does the query, keep using it. MCP fills a real gap only when you need a stable connection to an external system, tool discovery, and reusable authentication. Adding a connection layer just to read a local document usually isn't worth it.

03 Four questions before connecting

The external services you could connect vary widely: code hosting, business databases, the local file system, ticketing, team notifications, or internal APIs. Try the one you need most right now. Before each connection, ask four questions:

  1. Does this data need live access?
  2. Does Claude Code really need to call this capability directly?
  3. What's the minimum permission you can grant?
  4. If the tool returns a lot of data, how will you limit it?

Applied to a ticket lookup:

QuestionThis time
Live data?Latest comments and current status are queried live; weekly exports can be read as files
Called directly in the session?Ad hoc lookups during discussion suit MCP; fixed exports may not need it
How much permission?Read-only means a read scope
How much output?Prefer single-item details; cap lists at around 20 to start

04 Choose the transport by where the server runs

MCP servers can connect through different transports:

TransportGood for
HTTPRemote MCP services, team-shared services, services that need auth
stdioLocally running MCP servers, development and debugging, project tools
SSEMay appear in older configs; new configs usually prefer HTTP or stdio
WebSocketTwo-way connections the server supports; set "type": "ws" in JSON config

To pick a transport, first find out where the server runs. Team-shared remote services usually start with HTTP; local tools, project scripts, and debugging usually start with stdio. The protocol-level definitions are in the transports section of the MCP specification.

The @company/... package names and addresses below are placeholders; replace them with an address or launch command your provider supplies and you've reviewed. HTTP suits remote services:

claude mcp add --transport http project-api "https://mcp.example.com/mcp"

stdio suits local servers, and can pass environment variables too:

claude mcp add --transport stdio local-tools -- npx @company/mcp-server

On Windows, a local server may need an explicit cmd /c:

claude mcp add --transport stdio my-server -- cmd /c npx -y @company/mcp-server

05 Passing tokens without writing them into config

To authenticate an HTTP service, use a header or OAuth. Look at what this command does:

claude mcp add --transport http secure-api "https://mcp.example.com/mcp" \
  --header "Authorization: Bearer $API_TOKEN"

The shell expands $API_TOKEN to its real value before the CLI ever sees it. The command shows a variable, but the generated config may now hold the actual credential. Passing values to a stdio server with --env "API_TOKEN=$API_TOKEN" works the same way. These forms are fine for demonstrating arguments; for shared config definitions, use the environment-variable placeholders in .mcp.json described in the next section.

For MCP servers that support OAuth 2.0, Claude Code can handle browser authorization, token storage, and refresh:

claude mcp add --transport http my-service "https://mcp.example.com/mcp"
claude mcp login my-service

Use claude mcp logout my-service to clear the login. According to the Claude Code MCP documentation, a print-mode run like claude -p has no interactive panel and can't run the OAuth flow, so finish signing in first, with /mcp in an interactive session or claude mcp login in your shell.

The credentials a connection uses decide its real permissions in the external system. Manage them with these rules:

  • Keep keys out of .mcp.json.
  • Prefer environment variables, the system keychain, or OAuth for credentials.
  • Shared team config keeps only the server definition, not personal tokens.
  • Use different credentials for different environments.
  • Clean up expired tokens regularly.
  • Give external services the minimum permission scope.

06 .mcp.json and environment variable expansion

Project-level MCP config goes in .mcp.json at the project root. When adding with the CLI, pass --scope project explicitly; otherwise it goes into your personal local config for the current project. Connect one read-only service first, confirm it can complete a query, then combine several.

{
  "mcpServers": {
    "database": {
      "type": "stdio",
      "command": "npx",
      "args": ["@company/database-mcp"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}"
      }
    },
    "project-api": {
      "type": "http",
      "url": "${PROJECT_API_MCP_ENDPOINT}",
      "headers": {
        "Authorization": "Bearer ${PROJECT_API_TOKEN}"
      }
    }
  }
}

There are two ways to write environment variables:

SyntaxMeaning
${VAR}Uses the variable's value; if it's unset, claude mcp list and /mcp show a warning
${VAR:-default}Uses the default when the variable is unset

Use ${VAR} for required values, and ${VAR:-default} only for things that are safe to default, like a local tool path.

Many people add a fallback for convenience, such as ${DATABASE_URL:-postgresql://localhost/dev}. It feels helpful while experimenting locally, but in team work or real debugging it hides a nasty trap. If whoever runs the task forgets to set the target environment's DATABASE_URL, nothing complains; the server quietly connects to a stale local dev database.

Every read-only query then appears to succeed, and the old data even looks plausible, yet you're not querying the same environment at all. That kind of fake success is more dangerous than a connection that simply fails.

So any variable that defines an environment boundary or a target database address should be written as ${DATABASE_URL}, with no default. When it's missing, claude mcp list and /mcp name the variable in a warning, the text stays unexpanded, and the connection usually fails outright, forcing you to fix the environment right away. One more catch: the docs note that a variable set to an empty string counts as set, so ${VAR:-default} expands to an empty string and ignores the default.

07 Which scope the configuration lives in

MCP configuration has several scopes:

ScopeCommon locationPurposeShareable?
Local (default)Under the current project in ~/.claude.jsonPersonal experiments, private connectionsNo
Project.mcp.jsonTeam-shared server definitionsYes
UserUser-level configPersonal tools across projectsNo
ManagedEnterprise managed configServers the organization allows or blocksControlled by the organization
Plugin.mcp.json inside a pluginTools shipped with the pluginDistributed with the plugin
SubagentSubagent frontmatterOnly for a specific subagentDepends

Where config lives depends on who needs it:

  • A team code-hosting MCP: Project .mcp.json, sharing the connection config while each person injects their own credentials.
  • A personal note-search MCP: User scope, for your own use across projects.
  • An MCP only a data-analysis subagent needs: that agent's frontmatter, available only when that role runs.

Project .mcp.json can be committed, but secrets have to come from environment variables. For safety, an interactive session asks for your approval before using servers defined in a project's .mcp.json; run claude mcp reset-project-choices to reset those approvals. When the same server appears in several scopes, check which one actually takes effect. In enterprises, managed settings such as allowedMcpServers and deniedMcpServers control which servers are allowed or blocked.

08 Manage connections by where they fail

Inside Claude Code, /mcp shows MCP servers, connection status, and auth status, and can trigger related actions. In the terminal, pick the management command you need:

CommandWhat it does
claude mcp listList configured servers
claude mcp get <name>Show one server's details
claude mcp remove <name>Remove a server
claude mcp login <name>Log in or refresh auth
claude mcp logout <name>Log out
claude mcp reset-project-choicesReset project-level approval choices

For routine maintenance, choose the action by where things failed. Confirm config with list and get first; if the problem is auth, check login status; reset only when project approval choices are tangled. Each step changes only the relevant layer, which makes it easy to tell which fix worked.

Getting a connection configured is only the start. Once databases or file systems are connected, keeping account permissions, output size, and suspicious instructions in external content under control is covered in keeping Claude Code's MCP database access narrow.

The first step can be small: pick one read-only code-hosting service, add it to .mcp.json with --scope project, keep the token in an environment variable, and ask it for the latest PR comment. Once that works, connect the next one.