DEV Community

Zhengxin
Zhengxin

Posted on

Claude Code MCP Deep Dive (2): From a Configuration Entry to a Handshake

TL;DR: Claude Code cannot connect to an MCP server until that server appears in configuration. A definition may be private to one project, shared with a team, available to one user everywhere, or managed by an organization. When the same server name appears in more than one scope, precedence determines which complete definition wins. After configuration comes a separate job: connecting, handshaking, and negotiating the capabilities that server actually supports.

In the previous article, we used an internal Jira server as the motivating example. Where should that server be declared so Claude Code knows it exists?

There is no single answer. It depends on who should use the server and which parts of its configuration are safe to share.

One server name, several kinds of ownership

Suppose a company provides an MCP server for its internal Jira instance. Everyone on a team should be able to use it, but nobody’s API token should be copied into a shared repository.

That is the first configuration problem MCP needs to solve: the connection details for a shared capability should be declared once, while each person can retain control of their private credentials.

Claude Code’s current public documentation describes three regular installation scopes, plus organization-managed configuration:

  • Project scope lives in a .mcp.json file at the project root. It can be committed to version control, so a team can share the server name, endpoint, and launch method without committing personal credentials.
  • User scope lives in the user’s ~/.claude.json and applies across that user’s projects. It fits personal utility servers that are unrelated to one repository.
  • Local scope is also stored in ~/.claude.json, but keyed to one project only. It stays private and does not appear when the user opens other projects.
  • Managed configuration lets an administrator provide servers centrally for an organization. Individual users do not edit that managed source themselves.

The Claude Code MCP reference documents the storage locations and intended use of these scopes.

The local scope is particularly useful in the shared-Jira scenario. The project’s .mcp.json can declare “this repository uses the Jira server,” while each developer supplies their own credential-bearing configuration privately. The shared repository establishes the integration; the local configuration completes it for one person.

There are also server sources outside this regular scope hierarchy. A session can receive temporary configuration through a command-line option, and connectors configured through Claude.ai can reach Claude Code. Those are separate paths, not substitutes for the ordinary project/user/local choice.

A collision is resolved by precedence, not by field-by-field merging

What if the same server name appears in project, user, and local configuration?

Claude Code resolves that conflict predictably. The public precedence order is:

  1. Local scope
  2. Project scope
  3. User scope
  4. Plugin-provided servers
  5. Claude.ai connectors

Organization-managed server definitions take precedence over all of those when they duplicate a server.

The important detail is easy to miss: Claude Code uses the entire server entry from the winning source. It does not merge individual fields from several scopes into one composite record. That distinction makes debugging less mysterious. If a local definition has the same server name as a project definition, the local definition is the one that Claude Code will use; it is not merely a place to append one extra header to the project record.

This precedence is practical rather than arbitrary. A team can establish a shared baseline in .mcp.json, while an individual retains an explicit way to substitute a private or project-specific definition. If a managed definition exists for the same server, the organization’s definition wins instead.

One more safeguard applies specifically to project-scoped servers. A .mcp.json file usually travels with a repository, so Claude Code asks for approval in interactive sessions before using its project-scoped servers. That makes the connection command and arguments visible before a cloned repository gets to run them. User and local scopes are already the user’s own private configuration, so they do not need the same first-use approval step.

Configuration says “try this,” not “it is usable”

A configuration record is only a declaration that a server should exist. The actual connection still has to be established.

Claude Code tracks a server’s connection state rather than reducing everything to a single yes-or-no flag. States distinguish a connected server from one that failed to connect, is still connecting, is disabled, or needs authentication.

That separation matters because “unreachable” and “reachable but unauthorized” lead to different remedies. A bad URL, missing process, or crashed child process is a connection problem. An expired OAuth session or missing permission is an authentication problem. Treating both as the same generic failure would hide the next useful action.

The connection phase and a later tool call also deserve different timeout expectations. A connection that never responds within a short window is often misconfigured or not running at all. A tool call, by contrast, may ask the server to perform a long-running operation. A client should avoid treating those two waits as if they had the same failure meaning.

The handshake asks what is actually available

A successful transport connection is not yet the end of the setup path. Claude Code still needs to learn what the server supports.

This is capability negotiation. Client and server declare their supported features, and the client enables only the capabilities the server actually advertises. A server might offer tools but no resources; another might expose readable resources while offering no callable tools at all.

That is why MCP should not be described simply as “a way to add tools.” Tools, resources, and prompts are distinct capability families. The Model Context Protocol introduction frames MCP as a standard connection between AI applications and external systems, including data sources, tools, and workflows.

Negotiation keeps that flexibility from becoming guesswork:

  • If a server does not advertise tools, Claude Code does not ask it for a tool list.
  • If it does not support resources, resource-reading behavior stays unavailable for that server.
  • If a feature is supported by both sides, Claude Code can enable the relevant downstream behavior.

The result is an intentionally modest rule: use what the server says it supports, rather than assuming every server implements every part of the protocol.

Connected is not the same as useful

After the handshake and capability negotiation complete, the server is connected. But that still does not mean the model can use a new action yet.

The connection only establishes a working channel and an agreed feature set. The next questions are how bytes move across that channel, and how a declared server tool becomes a normal entry in Claude Code’s own tool list.

Those are separate transformations, and separating them is what makes the system manageable:

  1. Configuration chooses a candidate server.
  2. Connection and handshake establish a usable relationship.
  3. Capability negotiation limits what the relationship can do.
  4. Later layers expose the allowed capabilities to the agent.

The series map provides the broader pipeline, while Part 1 explains why MCP exists at all.

Next: local processes and remote services

A handshake assumes Claude Code already knows how to speak to the server. That may mean launching a local child process and communicating over standard input/output, or making requests to a remote service over a network transport.

The next article examines that transport choice: which connection paths the protocol standardizes, which paths Claude Code supports in practice, and why a local process and a remote service should not be retried or diagnosed in exactly the same way.

References

Top comments (0)