The MCP connector lets the Messages API talk to remote Model Context Protocol (MCP) servers without you writing an MCP client. It is enabled with the beta header mcp-client-2025-11-20 and is available on the Claude API, Claude Platform on AWS, and Microsoft Foundry Hosted-on-Anthropic deployments — see the platform split if you are on Bedrock or Vertex AI, where it is not offered. This article is about what the request and response actually look like.
Half one: the mcp_servers array
The mcp_servers parameter tells the API how to reach each server. Every entry has four possible fields:
| Field | Required | Rules |
|---|---|---|
type | Yes | Only "url" is supported |
url | Yes | Must start with https:// |
name | Yes | Unique; must be referenced by exactly one toolset |
authorization_token | No | OAuth token you obtained yourself |
Two constraints follow directly from the type and url rules: the server must be publicly exposed over HTTP (both Streamable HTTP and SSE transports work), and local STDIO servers — the kind you launch as a subprocess on your own machine — cannot be connected. For those, use the client-side MCP helpers instead. Also note the connector supports only the tool-calling part of the MCP specification: MCP prompts and MCP resources do not come through.
Half two: the matching mcp_toolset
Defining a server does not grant Claude any tools. For each server you must add an mcp_toolset entry to the ordinary tools array, referencing the server by name. A minimal two-server request body looks like this:
{
"mcp_servers": [
{"type": "url", "url": "https://mcp.example.com", "name": "crm"},
{"type": "url", "url": "https://mcp.other.com", "name": "docs"}
],
"tools": [
{"type": "mcp_toolset", "mcp_server_name": "crm"},
{"type": "mcp_toolset", "mcp_server_name": "docs"}
]
}
The validation is strict and symmetric: every mcp_server_name must match a defined server, and every defined server must be referenced by exactly one toolset. One dangling half in either direction is an error. The one deliberate exception: naming an unknown tool inside a toolset's per-tool configs only logs a backend warning, because MCP servers can add and remove tools dynamically. Toolsets also accept default_config and per-tool configs for allowlist and denylist filtering, plus cache_control for prompt-caching breakpoints.
If you used the deprecated mcp-client-2025-04-04 version: its tool_configuration object (with enabled and allowed_tools on the server definition) is exactly what the toolset replaces.
The response: two dedicated block types
With ordinary client tools, Claude returns a tool_use block, stops with stop_reason: "tool_use", and waits for your application to run the tool and send back a tool_result. MCP connector calls execute server-side, so the conversation instead contains two dedicated block types recording what already happened:
mcp_tool_use— the call Claude made. Itsidis prefixedmcptoolu_(nottoolu_), and alongsidenameandinputit carries aserver_namefield telling you which connected server handled it.mcp_tool_result— the outcome, withtool_use_idlinking back to the call, anis_errorflag, and thecontentthe server returned.
The practical difference for your code: there is no execute-and-reply loop to implement for these blocks. Your application's job is to log them, display them, or audit them — not to fulfil them. If you also pass regular client tools in the same request, you handle those exactly as before; the two systems coexist in one tools array.
Odds and ends worth knowing
Claude calls MCP tools when a request maps to a tool's described capability, not for general knowledge questions about the connected service — you can steer eagerness via the system prompt. mcp_servers also works inside the Message Batches API at regular Messages pricing. And the connector is not eligible for Zero Data Retention: tool definitions and results follow Anthropic's standard retention policy.
Where to go next
Continue with tool filtering patterns, running the OAuth flow yourself, and controlling context cost with defer_loading.