CLAUDE LABJP
VERSION — v2.1.227 landed on August 10 with no new features, just fixes around plan detection and CI behaviorAUTO — Two days remain until August 14, when auto mode becomes the default in Claude Code for Pro, Max, and TeamCI — Bash commands no longer fail across the board under claude-code-action with allowed_non_write_users on GitHub-hosted runnersBILLING — Sessions started with an expired token could misread your plan and nudge Max users toward usage credits; that is now fixedSUNSET — The legacy Workbench and the experimental prompt tool APIs retire on August 17, five days outPRICE — Sonnet 5 promo pricing at $2/$10 per Mtok runs through August 31, moving to $3/$15 on September 1VERSION — v2.1.227 landed on August 10 with no new features, just fixes around plan detection and CI behaviorAUTO — Two days remain until August 14, when auto mode becomes the default in Claude Code for Pro, Max, and TeamCI — Bash commands no longer fail across the board under claude-code-action with allowed_non_write_users on GitHub-hosted runnersBILLING — Sessions started with an expired token could misread your plan and nudge Max users toward usage credits; that is now fixedSUNSET — The legacy Workbench and the experimental prompt tool APIs retire on August 17, five days outPRICE — Sonnet 5 promo pricing at $2/$10 per Mtok runs through August 31, moving to $3/$15 on September 1
Articles/API & SDK
API & SDK/2026-06-25Advanced

Reach a Remote MCP Server in a Single API Request: Implementing the Messages API MCP Connector

How to call a remote MCP server's tools using only the Messages API's mcp_servers and mcp_toolset—no local MCP client. Covers allowlist/denylist design, response handling, and the pitfalls to avoid before unattended production use.

Claude API116MCP50connector2Python17indie developer19

Premium Article

You only want a scheduled job to use a remote MCP server—yet before that, you have to keep a local MCP client running, open a transport, and manage its lifecycle. That "scaffolding to call one tool" quietly weighs on headless operations. As an indie developer, I update several sites at fixed times every day, and every time I tucked an MCP client inside that runner, the logs filled up with disconnects and process cleanup.

The Messages API's MCP connector removes that scaffolding entirely. You put a server URL into the request's mcp_servers, and Anthropic's side connects to that remote MCP server, runs the tools, and folds the results into the same response. The point is simple: no client implementation required.

When it helps, and when it doesn't

Let me draw the line first. The MCP connector isn't a universal answer—its fit is clear-cut.

As the documentation states, the only part of the MCP spec currently supported is tool calls. Prompts and resources are out of scope; if you need those, you still have to run your own MCP client. Connections are limited to servers exposed over HTTPS (Streamable HTTP / SSE); local stdio servers can't be connected directly.

My rule of thumb: if you just want to call tools on a URL-reachable remote server, the connector is the shortest path; if you need local servers, prompts, resources, or fine connection control, run your own client. This sits next to the question of how to safely reach a private internal server, covered in MCP tunnel design for Managed Agents—a different answer to the same question of where you draw the boundary of your execution environment.

What you wantThe right tool
Just call tools on a URL-exposed remote MCPMCP connector (mcp_servers)
Use a local stdio serverYour own MCP client + SDK helpers
Use MCP prompts / resourcesYour own MCP client
Reach a private internal serviceMCP tunnel (Managed Agents)

The minimal call

Here's the smallest form: enabling all tools on a single server. Two things matter—connection details go in mcp_servers, and which tools to use go in tools as an mcp_toolset. And you need the beta header.

import anthropic
 
client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
 
response = client.beta.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "List the tools you have, then fetch today's events."}
    ],
    # 1) Connection definition (URL and token)
    mcp_servers=[
        {
            "type": "url",
            "url": "https://example-server.modelcontextprotocol.io/sse",
            "name": "calendar",
            "authorization_token": "YOUR_ACCESS_TOKEN",  # omit for servers that don't need it
        }
    ],
    # 2) Which tools to expose (all tools enabled by default)
    tools=[{"type": "mcp_toolset", "mcp_server_name": "calendar"}],
    # 3) Beta header (the old mcp-client-2025-04-04 is deprecated)
    betas=["mcp-client-2025-11-20"],
)
 
for block in response.content:
    print(block.type)

Expected output (excerpt): blocks arrive in the order textmcp_tool_usemcp_tool_resulttext. When Claude decides it needs the events, the tool is invoked once, and a final text grounded in that result follows.

There's an early pitfall here. If you forget betas=["mcp-client-2025-11-20"], you get an ordinary response as if mcp_servers were ignored entirely. I missed this at first and spent half an hour wondering why "the tool never gets called." The version bumped and the header name changed from mcp-client-2025-04-04, so pasting code from older posts fails silently.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
You'll be able to call a remote MCP server's tools from a single API request, without keeping a local MCP client running
You'll learn to scope tool exposure with allowlist / denylist / defer_loading so unattended jobs never call a destructive tool by accident
You'll sidestep the pitfalls people hit before going live—mcp_tool_use / mcp_tool_result handling, OAuth token management, and the lack of ZDR coverage
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API & SDK2026-07-08
Contract-Test Every Tool Before You Submit or Automate an MCP Connector
A connector that works once in a chat can still break silently in an unattended job through misread response shapes or double-fired writes. Here is a small harness that machine-checks tool descriptions, response contracts, idempotency, and latency, with measured numbers.
API & SDK2026-06-30
When a Tool Result Is Too Big and Melts Your Context Window: Designing Cursor-Based Pagination
When a list tool returns hundreds of rows at once, an agent's context can collapse in a single call. Here is a cursor-based pagination design that keeps tool output small and protects your token budget, with working code.
API & SDK2026-06-28
Did That Post Actually Go Through? Safely Retrying an Interrupted MCP Write Without Double-Executing
When an MCP write tool call is interrupted by a dropped connection, you can't tell whether the server ran it. Here's why naive retries cause double-execution, and a working wrapper that uses idempotency keys and a reconcile read to retry safely — with examples from an unattended pipeline.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →