Connecting Hosts
|
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 was written against the 2026-07-28 revision of the specification and the Claude Code documentation for version 2.1.283 (the commands below were executed with the locally installed Claude Code 2.1.267), VS Code 1.139.0, Claude Desktop and the GitHub Copilot cloud agent as documented on 2026-09-29 (see the Model Context Protocol baseline for the SDK versions). Host products change their menus and flags quickly, so the official pages are linked after every example; where a detail could not be confirmed in the official documentation, this page describes the behaviour without naming a flag.
A server is only useful once a host launches or contacts it, discovers its tools and shows them to a model. The
servers on Python MCP Servers, Spring Boot MCP Servers
and Node.js MCP Servers are the same docs-assistant on three stacks. This page connects
them to the hosts a developer actually uses. The generic mechanics of MCP configuration in Claude Code and Copilot — the
.mcp.json scopes, the flags of claude mcp add, VS Code’s mcp.json and the Copilot cloud agent JSON — are already
documented on Configuring MCP Servers and are not repeated here;
this page adds what is specific to docs-assistant: the three stacks over both transports, the protocol-era skew,
authentication against the setup from Authorization, output limits, tool naming and
troubleshooting.
The hosts and the endpoints
A host is the application the user talks to; it embeds one MCP client per configured server (see MCP Architecture). The client either starts the server as a child process and speaks over its standard streams (stdio) or POSTs to a URL (Streamable HTTP), as described on Transports.
The scratch builds used to write this page expose these endpoints. Replace the paths with your own; stdio entries must use absolute paths because the host does not start the process in your project directory.
| Stack | stdio command | Streamable HTTP URL | Protocol revision spoken |
|---|---|---|---|
Python ( |
|
|
2026-07-28, plus legacy clients |
TypeScript ( |
|
|
2026-07-28, plus legacy clients |
Java (Spring AI 2.0.1, Spring Boot 4.1.1) |
|
|
2025-11-25 only |
The Java server is the outlier because the MCP Java SDK 2.0.x speaks only protocol 2025-11-25 (see
Spring Boot MCP Servers). That is not a problem for a host: a host negotiates. Claude
Code’s documentation says it asks HTTP servers whether they support the newer revision and falls back to the older one
otherwise; when the scratch Python and Spring Boot servers were registered in a throw-away home directory, claude mcp list
reported both as connected, so the same host talks 2026-07-28 to one and 2025-11-25 to the other with no configuration
difference. The other hosts below document their MCP support on a per-feature basis rather than per revision; this page
does not claim which revision each of them sends, so test the server you deploy against each host you support.
Claude Code
Claude Code is the host with the most complete MCP support: tools, resources (as @ mentions), prompts (as slash commands),
OAuth and dynamic tool updates. This section shows the commands for docs-assistant; the flag reference and the scope
precedence are on Configuring MCP Servers.
Adding the server with claude mcp add
The syntax is claude mcp add [options] <name> <commandOrUrl> [args…]. Options such as --transport, --scope and
--env come before the server name, and for stdio everything after the -- separator is the server command, passed
untouched. Both transports for the three stacks:
# Python, stdio (the host starts the process)
$ claude mcp add --transport stdio docs-assistant-py -- \
/abs/path/.venv/bin/python /abs/path/server.py
# TypeScript, stdio
$ claude mcp add --transport stdio docs-assistant-ts -- \
npx tsx /abs/path/src/stdio.ts
# Java, stdio (jar built with the stdio starter)
$ claude mcp add --transport stdio docs-assistant-java -- \
java -jar /abs/path/docs-assistant.jar
# Python or TypeScript, Streamable HTTP (already running)
$ claude mcp add --transport http docs-assistant http://127.0.0.1:8000/mcp
# Java, Streamable HTTP, shared with the team through .mcp.json
$ claude mcp add --transport http --scope project docs-assistant-java http://127.0.0.1:8080/mcp
The --transport flag accepts stdio, http and sse (stdio is the default when it is omitted). sse is the
deprecated HTTP+SSE transport; use http. Each of the commands above was run against a throw-away HOME and printed
Added stdio MCP server … or Added HTTP MCP server …. The stdio servers were started by claude mcp list itself,
the HTTP ones needed the server running first. See
Claude Code — Connect Claude Code to tools via MCP.
To pass configuration to a stdio server, repeat --env KEY=value before the name; keep credentials out of the command
line and out of .mcp.json and let the server read them from the environment (the OAuth section below shows the
alternative for HTTP).
Scopes and the .mcp.json it writes
The default scope is local (private to you in the current project), --scope project writes a .mcp.json at the
repository root that is meant to be committed, and --scope user makes the server available in every project. With
--scope project, the registration above produced exactly this file (paths shortened):
.mcp.json written by claude mcp add --scope project{
"mcpServers": {
"docs-assistant-py": {
"type": "stdio",
"command": "/abs/path/.venv/bin/python",
"args": ["/abs/path/server.py"],
"env": {}
},
"docs-assistant-http": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
}
Project-scoped servers are not started or contacted until you approve them: in the throw-away directory, claude mcp list
showed both as Pending approval (run claude to approve) and did not launch the Python process. In non-interactive
claude -p runs and in cloud sessions there is no prompt, so those runs load a project-scoped server without asking, which
is one more reason never to commit a server that can change things without a review of the tools it exposes. Start
interactive Claude Code once in the project to approve, or reset the decisions with claude mcp reset-project-choices.
The official page gives the same scope table and the approval rule; see
Claude Code — Connect Claude Code to tools via MCP.
Checking what is connected
claude mcp list health-checks every approved server and claude mcp get <name> shows one server. Output from the same
session, with the scratch paths shortened:
claude mcp list and claude mcp get$ claude mcp list
Checking MCP server health...
docs-assistant-ts: npx --prefix .../ts-server tsx .../src/stdio.ts - ✔ Connected
docs-http: http://127.0.0.1:8000/mcp (HTTP) - ✔ Connected
docs-java: http://127.0.0.1:8080/mcp (HTTP) - ✔ Connected
broken: /nonexistent/cmd - ✘ Failed to connect - ENOENT: no such file or directory, posix_spawn '/nonexistent/cmd'
$ claude mcp get docs-http
docs-http:
Scope: User config (available in all your projects)
Status: ✔ Connected
Type: http
URL: http://127.0.0.1:8000/mcp
The three statuses the official page documents are connected, needs authentication and failed to connect; for a failure,
claude mcp get adds an Issue: line with the HTTP status or error code and any text the server returned. Inside a
session, /mcp lists the same servers, lets you authenticate and shows each server’s tools.
Signing in to a protected server
A docs-assistant protected as on Authorization answers an unauthenticated request with a
401 and a WWW-Authenticate challenge that points at its Protected Resource Metadata. Claude Code follows that discovery
chain itself, so there is nothing to configure for an OAuth-capable server: the registration is the plain http command,
and the server shows up as needing authentication. Two ways to run the browser login:
# inside a session
> /mcp
# select docs-assistant, choose to authenticate, finish the sign-in in the browser
# or from the shell
$ claude mcp login docs-assistant
$ claude mcp login docs-assistant --no-browser # SSH sessions: print the URL instead
$ claude mcp logout docs-assistant # clear the stored credentials
The client identity step of the authorization flow is automatic when the authorization server supports Dynamic Client Registration; the documentation states that Claude Code also supports servers that use a Client ID Metadata Document instead and discovers them automatically. When the authorization server offers neither, register a client yourself and give Claude Code the client id, a masked prompt for the secret and a fixed callback port for the redirect URI you registered:
$ claude mcp add --transport http \
--client-id <client-id> --client-secret --callback-port 8080 \
docs-assistant https://docs-mcp.example.com/mcp
--client-secret prompts for the value with masked input, or reads the MCP_CLIENT_SECRET environment variable for CI. These
flags exist in claude mcp add --help of the installed 2.1.267 and are described on
Claude Code — Connect Claude Code to tools via MCP. Tokens are then stored and sent
by Claude Code on every request to that server only, consistent with the audience-binding and no-passthrough rules of the
authorization page.
Output limits: MAX_MCP_OUTPUT_TOKENS
A tool result goes straight into the model’s context, so Claude Code caps it. According to the documentation, Claude Code
prints a warning when a result exceeds 10,000 tokens and enforces a default limit of 25,000 tokens, which the environment
variable MAX_MCP_OUTPUT_TOKENS changes for tools that do not declare their own limit; the string exists in the installed
binary too. A tool can instead ask for a larger text limit itself through the anthropic/maxResultSizeChars key in its
_meta on the tools/list result; that value then replaces the variable for that tool’s text content, up to a documented
ceiling of 500,000 characters, and image data stays subject to MAX_MCP_OUTPUT_TOKENS.
$ MAX_MCP_OUTPUT_TOKENS=50000 claude
How this relates to the structuredContent that docs-assistant returns: the official page describes the limits in terms
of text content and images and says nothing specific about structuredContent. The SDKs, however, return the same result
twice, once as a JSON text block in content (for hosts and models that only read text) and once as structuredContent
(see the tools/call response on Transports), so a large result costs its size in
the context whichever field the host feeds to the model. The practical rules are therefore the ones that make
tool output small in the first place: cap top_k, return snippets and identifiers rather than whole pages, and let the
model read a page through the docs://{component}/{page} resource on demand (see
Tools, Resources, Prompts & Elicitation). Raise the limit for a tool only when large output is
its purpose, for example a schema dump. The declaration is one line in each stack (each snippet was type-checked or run
against the real package):
anthropic/maxResultSizeChars on a tool, three stacks@mcp.tool(meta={"anthropic/maxResultSizeChars": 200000})
def get_schema(component: str) -> str:
...
server.registerTool(
'get_schema',
{
description: 'Return the schema of one component',
inputSchema: z.object({ component: z.string() }),
_meta: { 'anthropic/maxResultSizeChars': 200000 }
},
async ({ component }) => ({ content: [{ type: 'text', text: component }] })
);
public class LargeResult implements MetaProvider {
@Override
public Map<String, Object> getMeta() {
return Map.of("anthropic/maxResultSizeChars", 200000);
}
}
@McpTool(name = "get_schema", description = "Return the schema of one component",
metaProvider = LargeResult.class)
public String getSchema(@McpToolParam(description = "component") String component) { ... }
The Python signature MCPServer.tool(…, meta=…) and the Python output [\{'anthropic/maxResultSizeChars': 200000}]
of list_tools() were checked by running it; the TypeScript _meta option compiled with tsc --noEmit against
@modelcontextprotocol/server 2.2.0; the Java metaProvider attribute and the MetaProvider.getMeta() interface were
read from the spring-ai-mcp-annotations 2.0.1 jar and the class compiled with javac. Whether Claude Code honours the
key is documented on the Claude Code MCP page; the key is a Claude Code convention,
not part of the MCP specification, and other hosts ignore it.
How the tools are named
Every tool of a connected server appears to Claude Code as mcp<server-name><tool-name>, with characters outside
letters, digits, underscore and hyphen replaced by underscores. Registered as docs-assistant, the search tool is
mcpdocs-assistantsearch_docs. Permission rules, hook matchers and allowed-tools lists use that name; the rule
syntax is on Configuring MCP Servers and
Permissions & Settings. The name of the server you chose in
claude mcp add is therefore part of every permission rule: renaming docs-assistant-http to docs silently detaches the
rules written for the old name. Because search_docs is declared read-only (see
Tools, Resources, Prompts & Elicitation), it is a reasonable candidate for an allow rule, but
remember that the annotation is a hint from the server that the host does not verify; the decision to trust a server is
yours. Resources of the server become @ mentions and its prompts slash commands, so answer_with_citations is available
as a command once the server is connected.
Claude Desktop
Claude Desktop has two separate ways to add a server, and they are not interchangeable. This section was checked against the MCP project’s connect guides and Anthropic’s support article on custom connectors on 2026-09-29.
Local servers are listed in claude_desktop_config.json. Open the Claude menu, choose Settings, then Developer, and
click Edit Config; that creates the file if it does not exist. It lives at
~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json
on Windows. The file uses the same mcpServers object as .mcp.json, and the app must be quit and restarted to load a
change. A stdio docs-assistant looks like this:
claude_desktop_config.json{
"mcpServers": {
"docs-assistant": {
"command": "/abs/path/.venv/bin/python",
"args": ["/abs/path/server.py"]
}
}
}
Use absolute paths, as the troubleshooting list of the official guide stresses. The host writes each server’s standard
error to mcp-server-<name>.log and connection problems to mcp.log in ~/Library/Logs/Claude on macOS and
%APPDATA%\Claude\logs on Windows, so a print() to stdout that corrupts the protocol shows up there. See
MCP — Connect to local MCP servers.
Remote servers are not added to that file. Anthropic’s support article states that remote MCP servers must be added
through Settings and Connectors, using Add and then Add custom connector, where you enter the server URL and optionally an
OAuth client id and secret under advanced settings; the same article says custom connectors are available on the Free, Pro,
Max, Team and Enterprise plans and that servers configured in claude_desktop_config.json are separate and are not
available on claude.ai or in Cowork. The MCP guide walks through the same dialogs and adds that, once connected, the
server’s resources and prompts are attached from the "Add files, connectors, and more" menu and its tools can be
enabled or disabled per tool. The pages read do not say whether a http://127.0.0.1 URL is accepted for a custom
connector, so develop against the stdio entry and use the connector dialog for a deployed HTTPS endpoint (see
Deploying Remote Servers). See
MCP — Connect to remote MCP servers and
Get started with custom connectors using remote MCP.
Claude Code can also import Desktop’s local servers with claude mcp add-from-claude-desktop, which the CLI and the
official page both restrict to macOS and Windows Subsystem for Linux.
VS Code and GitHub Copilot
VS Code (1.139.0 here) reads MCP servers from .vscode/mcp.json in the workspace, from the user profile (command MCP: Open
User Configuration) and, in the portable format, from a .mcp.json at the workspace root. The important difference from
Claude Code is the top-level key: VS Code’s own file uses servers (Claude Code’s .mcp.json and Claude Desktop use
mcpServers), and it adds a top-level inputs array for values VS Code should ask the user for instead of storing them.
An input of type promptString with "password": true masks what is typed, and a server references it as
$\{input:<id>}.
.vscode/mcp.json for the three docs-assistant builds{
"inputs": [
{
"type": "promptString",
"id": "docs-gateway-key",
"description": "API key of the docs-assistant gateway",
"password": true
}
],
"servers": {
"docs-assistant-py": {
"type": "stdio",
"command": "${workspaceFolder}/.venv/bin/python",
"args": ["${workspaceFolder}/server.py"]
},
"docs-assistant-ts": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "${workspaceFolder}/src/stdio.ts"]
},
"docs-assistant-java": {
"type": "http",
"url": "http://127.0.0.1:8080/mcp"
},
"docs-assistant-gateway": {
"type": "http",
"url": "https://docs-mcp.example.com/mcp",
"headers": {
"X-Api-Key": "${input:docs-gateway-key}"
}
}
}
}
The keys used above are the documented ones: type is stdio (with command, and optionally args, cwd, env,
envFile and a dev object with file-watch patterns) or http/sse (with url, optional headers and an optional
oauth object whose clientId is required when present). The http entry for OAuth-protected servers needs no header at
all: for a server configured with OAuth, the documentation says VS Code runs the flow and opens a browser on the first
connection. ${workspaceFolder} is substituted in paths. VS Code supports tools, resources, prompts (invoked as
/<server>.<prompt>) and MCP Apps, and it offers MCP: Add Server and MCP: List Servers commands, which start,
stop and show the log of each server. Verify the JSON with a linter before committing it: a stray comma makes VS Code
ignore the whole file. The example above was parsed with jq.
Whether VS Code sends the 2026-07-28 revision or the previous one is not stated on the pages read; as with every host above, test it against the server you deploy. See VS Code — Add and manage MCP servers in VS Code and VS Code — MCP configuration reference. The same file format is described from the Copilot side on Configuring MCP Servers.
The Copilot cloud agent
The Copilot cloud agent runs unattended in a GitHub-hosted environment, so its MCP configuration is stricter than the
interactive hosts. A repository administrator sets it in the repository’s Settings, under Copilot and then MCP servers;
the page has an MCP configuration box and a Save MCP configuration button that validates the JSON. (The menu label in
the current GitHub documentation is MCP servers, not "Cloud agent".) The format is the mcpServers object with three
rules that differ from the other hosts:
-
every server needs a
toolsarray, either the names of the tools the agent may call or"*"; allowlist only the read-only ones, because the agent calls them without asking -
typeislocal,stdio,httporsse, and local servers takecommandandargs, remote onesurl -
values that come from secrets must be named with the
COPILOT_MCP_prefix, stored as Agents secrets or variables, and referenced as$COPILOT_MCP_<NAME>or$\{COPILOT_MCP_<NAME>}; the documentation adds that they live in thecopilotenvironment
{
"mcpServers": {
"docs-assistant": {
"type": "local",
"command": "python",
"args": ["server.py"],
"env": {
"DOCS_DB_URL": "$COPILOT_MCP_DOCS_DB_URL"
},
"tools": ["search_docs"]
}
}
}
This example starts the Python build from the repository checkout, which only works if the environment the agent runs in
has the dependencies installed; the GitHub page describes how to customise that environment and it is not repeated
here. DOCS_DB_URL is a hypothetical setting of a real vector store behind search_docs, supplied by the secret rather
than by the file.
Two limits matter for docs-assistant. First, GitHub states that the cloud agent and Copilot code review support only MCP
tools: the resource template docs://{component}/{page} and the prompt answer_with_citations are invisible to it, so
anything the agent must be able to do has to be reachable through a tool, which is one reason docs-assistant keeps
search_docs self-contained. Second, GitHub states that remote MCP servers that use OAuth for authorization are not
supported, so the OAuth-protected deployment of Authorization cannot be reached
directly from the cloud agent; run a local server as above or front the endpoint with something that authenticates
without an interactive OAuth flow, and keep that credential read-only. The other rules of the platform, such as the
default GitHub and Playwright servers, are on the official page; see
GitHub Copilot — Configure MCP servers for your repository.
Pointers to other hosts
Two more families of hosts speak MCP, and their setup belongs to other AI sub-sections rather than here.
Microsoft Copilot Studio can connect an existing MCP server to an agent from a tool’s Model Context Protocol wizard (or
through a custom connector) and supports the Streamable transport, with authentication of none, an API key, or OAuth 2.0;
Microsoft 365 Copilot declarative agents use MCP servers through plugins built with the Microsoft 365 Agents Toolkit. Both
are covered in the Conversational Channels sub-section. ElevenLabs agents accept custom MCP servers by URL, with
an optional secret and headers, over SSE or Streamable HTTP transport, and offer approval modes for tool use; that is
covered in ElevenLabs Agents. For any of these, deploy docs-assistant as an HTTPS endpoint as
described on Deploying Remote Servers and give it the least privilege the
agent needs. See
Copilot Studio — Connect your agent to an existing MCP server,
Plugins for Microsoft 365 Copilot and
ElevenLabs — Model Context Protocol.
Choosing a host
| Claude Code | Claude Desktop | VS Code and Copilot Chat | Copilot cloud agent | |
|---|---|---|---|---|
Configuration |
|
|
|
Repository Settings > Copilot > MCP servers |
Top-level key |
|
|
|
|
Transports |
stdio, http, sse |
stdio (file), remote URL (connector) |
stdio, http, sse |
local/stdio, http, sse |
Secrets |
environment variables, OAuth login |
connector OAuth fields; environment in the file |
|
|
OAuth to the server |
yes, |
yes, in the connector dialog |
yes, automatic browser flow |
no for remote servers |
Tools, resources, prompts |
all three |
all three |
all three, plus MCP Apps |
tools only |
Approval |
per tool through permission rules |
per tool in the app |
per tool in the chat |
none: the |
Troubleshooting a server that does not appear
Work from the outside in; each step below names the command that would show the failure.
-
Nothing listed at all. In Claude Code a project-scoped server stays
Pending approvaluntil you runclaudein the project and accept it (claude mcp listsays so); in Claude Desktop the file is read only at start-up, so quit the app completely and reopen it; VS Code shows servers only from a file it parsed, so check the JSON and the key (servers, notmcpServers, in.vscode/mcp.json). -
Listed, but failed to connect. Run
claude mcp get <name>: anENOENT … posix_spawnissue means the command or path is wrong (use absolute paths),ConnectionRefusedmeans the HTTP server is not running or the port differs. Run the stdio command by hand in a terminal and pipe it a request; a server that prints anything to standard output other than protocol messages, such as a startup banner or aprint(), corrupts the stream (see Transports). -
Failed on start-up only. Claude Code allows a server up to the greatest of 60 seconds, the applicable tool timeout and
MCP_TIMEOUT, so a slownpxoruvxfirst run can be given longer withMCP_TIMEOUT=<milliseconds>; a Spring Boot jar or a Python import of a large model is the usual reason. -
Needs authentication. The server answered 401. Run
/mcporclaude mcp login <name>. If the login loops or the authorization server rejects the client, revisit client identity andisshandling on Authorization; if the registration needs a fixed redirect URI, pass--callback-port. -
Connected, but the tools are missing or renamed. Look at the exact
mcp<server><tool>name in/mcpand compare it with your permission rules. For the Copilot cloud agent, thetoolsarray is the allowlist, so a tool missing from it is not available to the agent. -
Connected to the wrong protocol behaviour. Claude Code lets you force the behaviour: the documentation names
MCP_SDK_GENERATIONto choose between its v1 and v2 runtimes (v2 from Claude Code 2.1.232) andMCP_PROTOCOL_NEGOTIATIONset toautoorlegacyto control whether it asks servers for the newer revision. The names exist in the installed binary; use them only to reproduce a problem, not as a permanent setting. -
Reproduce without the host. The MCP Inspector CLI and the contract script on Testing & Debugging speak to the server without any host in between; if they pass and the host fails, the fault is in the host configuration.
Where to go next
-
Building MCP Clients builds the client side yourself instead of relying on a host.
-
Deploying Remote Servers makes the HTTP endpoint reachable and safe for hosts that live outside your machine.
-
Authorization is the server side of the
/mcplogin shown above. -
Configuring MCP Servers holds the generic configuration reference for Claude Code and Copilot.