MCP & Connecting to Tools
The Model Context Protocol (MCP) is the open standard for connecting AI to external tools and data. On the API you don't have to run an MCP client at all: the MCP connector lets you name a remote server in your request and Claude calls its tools inside the normal agent loop. Two request fields replace an entire integration layer.
- When the MCP connector beats hand-defining tools — and when it doesn't
- The exact request shape: mcp_servers for the connection, mcp_toolset for the policy
- Allowlist, denylist, and per-tool config — and how the three config layers merge
- The response blocks you have to handle: mcp_tool_use and mcp_tool_result
- The real limits: HTTPS-only, tools-only, platform gaps, and no ZDR coverage
:::info The protocol underneath just changed MCP itself just shipped its biggest revision since launch — the stateless 2026-07-28 spec — and its first official extension, MCP Apps, which lets a server ship a sandboxed HTML UI a client can render inside a tool call. The connector's request shape on this page is unchanged; what moves is the servers you connect to. :::
MCP vs hand-defined tools
| Tool use (custom) | MCP connector | |
|---|---|---|
| You define | Each tool's schema, and you execute it | A connection to a server that publishes tools |
| Who runs the tool | Your code, in your loop | Anthropic's side calls the remote server |
| Best for | A few bespoke functions in your app | Reusing existing integrations (GitHub, DBs, browsers, SaaS) |
| Auth | Your code | An OAuth bearer token you supply per server |
They coexist. Define your app-specific tools directly, and pull in ready-made capability via MCP.
The request shape
Two pieces, and they are deliberately separate: mcp_servers says where the server is and how to authenticate; the mcp_toolset entry in the tools array says which of its tools you're willing to expose and how.
- anthropic-beta: mcp-client-2025-11-20 — without it the mcp_servers field is not accepted. In the SDKs this is the betas list on a beta.messages.create call.
- Give it type url, an https url, and a unique name. Add authorization_token if the server requires OAuth — you run the OAuth flow yourself and pass the resulting access token.
- Set mcp_server_name to the name you just used. With no further config, every tool on that server is enabled with defaults.
- Claude's reply can contain mcp_tool_use and mcp_tool_result content blocks. Render or log them like tool blocks — do not assume the response is plain text.
Minimal MCP connector call (cURL)
curl https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "X-API-Key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: mcp-client-2025-11-20" \
-d '{
"model": "MODEL_ID",
"max_tokens": 1000,
"messages": [{"role": "user", "content": "What tools do you have available?"}],
"mcp_servers": [
{"type": "url", "url": "https://example.com/sse", "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
],
"tools": [
{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}
]
}':::tip Never hard-code the model
MODEL_ID above is a placeholder on purpose. Read the current ID from Current Models & Pricing and keep it in config, so a model upgrade is a one-line change.
:::
The API enforces a strict pairing: every server in mcp_servers must be referenced by exactly one toolset, and every toolset's mcp_server_name must match a declared server. Mismatches are validation errors, not silent no-ops.
Choose what Claude can actually do
This is the part most integrations get wrong. A toolset takes a default_config applied to every tool, plus configs with per-tool overrides. Precedence, highest first: per-tool configs → set-level default_config → system defaults.
Denylist — enable everything, then switch off the dangerous ones. Reasonable when you want breadth but no destructive writes:
{
"type": "mcp_toolset",
"mcp_server_name": "calendar-mcp",
"configs": {
"delete_all_events": { "enabled": false },
"share_calendar_publicly": { "enabled": false }
}
}
Allowlist — disable by default, then name the survivors. This is the least-privilege posture, and the one to reach for by default:
{
"type": "mcp_toolset",
"mcp_server_name": "calendar-mcp",
"default_config": { "enabled": false },
"configs": {
"search_events": { "enabled": true },
"create_event": { "enabled": true }
}
}
:::warning A denylist only blocks what you thought of
Servers can add tools. A denylist silently grants every tool shipped after you wrote it; an allowlist silently ignores them. For anything touching customer data or money, allowlist. Note too that naming a tool in configs that doesn't exist on the server logs a backend warning but does not error — so a typo in an allowlist quietly disables the tool you meant to enable. Verify against the server's live tool list.
:::
Keep the schemas out of your context
Every enabled tool's description is sent with the request, so a fat catalog taxes every turn. The connector's answer is defer_loading: true: the description stays out of the initial context, and Claude pulls it in on demand via the Tool Search Tool.
{
"type": "mcp_toolset",
"mcp_server_name": "calendar-mcp",
"default_config": { "defer_loading": true },
"configs": {
"search_events": { "defer_loading": false }
}
}
Read that as: defer everything except the one tool this task starts with. A toolset also accepts cache_control, so a stable catalog can sit behind a prompt caching breakpoint instead of being re-billed every turn. For the numbers behind this — and why deferring tools raised selection accuracy rather than lowering it — see The MCP Token Tax. When it's the results rather than the definitions flooding your context, reach for Programmatic Tool Calling instead.
What comes back
Two content-block types you must handle:
{ "type": "mcp_tool_use", "id": "mcptoolu_...", "name": "echo",
"server_name": "example-mcp", "input": { "param1": "value1" } }
{ "type": "mcp_tool_result", "tool_use_id": "mcptoolu_...", "is_error": false,
"content": [ { "type": "text", "text": "Hello" } ] }
Note server_name on the use block: with several servers connected, that's how you attribute a call — essential for logging and for debugging which integration misbehaved. And is_error is a field, not an exception: a failing MCP tool comes back as a result, so your loop must inspect it rather than assume success.
The limits that bite
- Tools only. Of the MCP spec, the connector currently supports tool calls — not prompts or resources. Need those? Run your own client and use the SDK MCP helpers instead.
- Remote HTTPS only. The server must be publicly reachable over HTTP (Streamable HTTP or SSE transports). A local stdio server cannot be connected this way — that is what Claude Code and the desktop apps do.
- Platform gaps. Available on the Claude API, Claude Platform on AWS, and Microsoft Foundry (Hosted-on-Anthropic deployments). Not currently on Amazon Bedrock or Google Cloud.
- No zero-data-retention. Data exchanged with MCP servers — tool definitions and execution results — falls under standard retention, not ZDR.
- You own the OAuth. The API takes an authorization_token; obtaining it and refreshing it before expiry is your job.
Same standard, three surfaces
- API (this page) — remote servers by URL, via the connector.
- Claude Code — local and remote servers in your dev sessions.
- The apps — MCP powers Connectors.
Learn the protocol once; it transfers. Only the wiring differs.
Trust
:::warning An MCP server is code plus access Only connect servers you trust, scope them to least privilege with an allowlist, and remember that content a server returns is untrusted input that can carry prompt injection. Review third-party servers before you wire them in — Reviewing Third-Party Code and Securing MCP Servers. :::
Check yourself
0/4- The connector replaces an MCP client with two request fields — but only for remote HTTPS servers, and only for tool calls.
- mcp_servers is the connection; the mcp_toolset in tools is the policy. Each server must pair with exactly one toolset.
- Allowlist (default_config.enabled false, plus explicit configs) beats denylist: tools added to the server later are ignored, not granted.
- defer_loading and cache_control are your levers when tool schemas start eating the context window.
- Handle mcp_tool_use and mcp_tool_result blocks — including is_error, which is a field, not an exception.
- Check the beta header before shipping: mcp-client-2025-11-20 is current, mcp-client-2025-04-04 is deprecated.
Sources & further reading
- MCP connector — Anthropic docs — the authoritative field reference and migration guide.
- Model Context Protocol specification — the open standard itself, including authorization.