Using Servers in Real Hosts
You usually do not write the host
Section titled “You usually do not write the host”Most servers are used from hosts someone else built. Knowing how those hosts are configured tells you what your server must look like from the outside: what command launches it, what URL it lives at, which environment variables it reads, and how a user authorizes it.
flowchart LR cc["Claude Code"] cd["Claude Desktop"] api["Claude API MCP connector"] insp["MCP Inspector"] s["Your MCP server"] cc --> s cd --> s api --> s insp --> s
Claude Code
Section titled “Claude Code”Claude Code adds servers with claude mcp add. The transport flag chooses how it connects.
# Remote server over Streamable HTTPclaude mcp add --transport http notion https://mcp.notion.com/mcp
# Remote server with a static bearer tokenclaude mcp add --transport http secure-api https://api.example.com/mcp \ --header "Authorization: Bearer your-token"
# Local server over stdio — everything after -- is the launch commandclaude mcp add --transport stdio airtable --env AIRTABLE_API_KEY=YOUR_KEY \ -- npx -y airtable-mcp-serverThe -- separator is not optional for stdio servers: it tells the CLI where its own options end and the server command begins.
Scopes
Section titled “Scopes”| Scope | Where it is stored | Shared? | Use for |
|---|---|---|---|
local (default) | ~/.claude.json, per project | No | Personal experiments |
project | .mcp.json at the repo root | Yes, via git | Team-wide servers |
user | ~/.claude.json | No | Tools you want in every project |
claude mcp add --transport http stripe --scope project https://mcp.stripe.comclaude mcp add --transport stdio db --scope user -- npx -y @bytebase/dbhubThe project file
Section titled “The project file”A project-scoped server is just an entry in .mcp.json. Commit it so teammates get the same servers. Values support ${VAR} and ${VAR:-default} expansion in command, args, env, and headers, so secrets stay out of the repo.
{ "mcpServers": { "shared-server": { "type": "http", "url": "https://example.com/mcp" }, "local-db": { "type": "stdio", "command": "/path/to/server", "args": ["--config", "${CLAUDE_PROJECT_DIR}/config.json"], "env": { "DB_URL": "${DB_URL:-postgresql://localhost}" }, "timeout": 600000 } }}Authorization and housekeeping
Section titled “Authorization and housekeeping”Remote servers that require OAuth are authorized interactively: run /mcp inside a session and follow the browser flow, or claude mcp login <name> from the shell. Pre-registered client credentials can be supplied with --client-id and --client-secret (read from MCP_CLIENT_SECRET in CI).
claude mcp list # every configured server and its statusclaude mcp get notion # details for one serverclaude mcp remove notion # drop itUseful knobs: MCP_TIMEOUT=10000 claude bounds server startup in milliseconds; a per-server timeout in .mcp.json bounds tool execution; MAX_MCP_OUTPUT_TOKENS caps how much tool output is fed to the model. Inside Claude Code your tools appear as mcp__<server>__<tool> — the same namespacing idea from the previous lesson, which is what you use in permission rules and hooks.
Claude Desktop
Section titled “Claude Desktop”Claude Desktop reads claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\). The shape is the same mcpServers map.
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/Desktop"] } }}Restart the app after editing. Because Desktop launches stdio servers itself, the command must be on the app’s PATH — a common failure is a server that works in your shell but not from the app because node lives in a version-manager directory.
The Claude API MCP connector
Section titled “The Claude API MCP connector”If you are calling the Messages API directly, you can let Anthropic make the MCP connection server-side instead of running a client yourself. Two request parts are required together: mcp_servers declares the connection, and an mcp_toolset entry in tools exposes it to the model. Omitting either half is a validation error, and every server must be referenced by exactly one toolset.
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic();
const response = await anthropic.beta.messages.create({ model: 'claude-opus-5', max_tokens: 16000, betas: ['mcp-client-2025-11-20'], mcp_servers: [ { type: 'url', url: 'https://mcp.example.com/mcp', name: 'example-mcp', authorization_token: process.env.EXAMPLE_TOKEN }, ], tools: [ { type: 'mcp_toolset', mcp_server_name: 'example-mcp', default_config: { enabled: false }, // allowlist mode configs: { get_weather: { enabled: true } }, // only this tool is exposed }, ], messages: [{ role: 'user', content: 'What is the weather in Bangkok?' }],});import osimport anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create( model="claude-opus-5", max_tokens=16000, betas=["mcp-client-2025-11-20"], mcp_servers=[ {"type": "url", "url": "https://mcp.example.com/mcp", "name": "example-mcp", "authorization_token": os.environ.get("EXAMPLE_TOKEN")}, ], tools=[ {"type": "mcp_toolset", "mcp_server_name": "example-mcp", "default_config": {"enabled": False}, "configs": {"get_weather": {"enabled": True}}}, ], messages=[{"role": "user", "content": "What is the weather in Bangkok?"}],)The connector only reaches servers that are publicly routable over HTTPS, and the loop runs on Anthropic’s side — you get the final message, not per-call hooks. Use it when you want the least code; run your own client when you need consent prompts, local stdio servers, or custom routing.
The Inspector as a host
Section titled “The Inspector as a host”While developing, the MCP Inspector is the fastest host to point at your server. It runs your server, shows every tool, resource, and prompt, and logs the raw protocol traffic.
# Web UI against a local stdio servernpx @modelcontextprotocol/inspector node build/index.js
# Web UI against a remote servernpx @modelcontextprotocol/inspector --server-url https://api.example.com/mcp --transport http
# CLI mode for scripts and CInpx @modelcontextprotocol/inspector --cli node build/index.js --method tools/listIt negotiates both protocol eras, so it is also how you check that a legacy-only client would still work against your server. The testing lesson goes deeper.
Design notes for server authors
Section titled “Design notes for server authors”- Publish the launch command. Hosts need a one-liner;
npx -y your-packageoruvx your-packageis the convention. - Read secrets from the environment on stdio; never ask for them as tool arguments.
- Expose a stable HTTPS URL for remote use and implement the OAuth resource-server side so
/mcpin Claude Code can authorize it. - Keep tool names header-safe and unique, because hosts will prefix them and may mirror them into HTTP headers.