Claude Agent SDK init message: check the Sume server status first

Read the init message's mcp_servers statuses before a paid Sume call. failed and needs-auth mean the tools are not usable. pending is not a failure on its own.

5 min readSume
All posts

Read the system init message and check each server's status before any paid call. Per the Claude Agent SDK docs, the status is one of pending, connected, failed, needs-auth or disabled, and a server that fails to connect does not throw (read 2026-10-05). Without that check, an agent can run a whole session without any Sume tools and still answer, which hides the problem.

Which statuses mean trouble

The docs say to check for failed or needs-auth to detect servers that will not be usable, and not to treat pending as a failure by itself (read 2026-10-05). Pending can mean the server has not connected yet, that its tool list came from a cache and connects on first use, or that the deadline expired.

Timing matters for a remote server without a cached tool list: the first turn waits up to MCP_TIMEOUT, 30 seconds by default, and the connection fails at that deadline. CLAUDE_CODE_MCP_STARTUP_WAIT_MS sets the wait yourself and requires Claude Code v2.1.274 or later.

Init status values and what to do, read 2026-10-05
StatusMeaningAction for a Sume session
connectedServer reachable, tools listedProceed
pendingNot connected yet, or cached listRe-check status later; do not abort
failedCould not connectStop; check URL and network
needs-authCredentials missing or rejectedStop; check the API key or OAuth login
disabledTurned offStop; enable the server

A status gate in Python

This loop reads the init message, stops if the Sume server is unusable, and otherwise lets the query continue. It needs the claude-agent-sdk package and a key.

import asyncio, os
from claude_agent_sdk import (query, ClaudeAgentOptions,
                              SystemMessage, ResultMessage)

BAD = ("failed", "needs-auth", "disabled")

async def main() -> None:
    options = ClaudeAgentOptions(
        mcp_servers={"sume": {
            "type": "http", "url": "https://mcp.sume.com/mcp",
            "headers": {"Authorization":
                        "Bearer " + os.environ["SUME_API_KEY"]}}},
        allowed_tools=["mcp__sume__mcp_health"])
    async for msg in query(prompt="Call mcp_health.", options=options):
        if isinstance(msg, SystemMessage) and msg.subtype == "init":
            for s in msg.data.get("mcp_servers", []):
                if s.get("name") == "sume" and s.get("status") in BAD:
                    raise SystemExit("sume unusable: " + s["status"])
        if isinstance(msg, ResultMessage) and msg.subtype == "success":
            print(msg.result)

asyncio.run(main())

Confirm the auth source too

A connected server is not enough. Sume's quickstart suggests calling mcp_health first. For an OAuth session, authenticated.auth_source should read mcp_oauth, which confirms the session is the one you expect before anything that changes data runs.

The status can change after it first reports connected. The SDK docs note that a dropped remote server returns to pending while it reconnects, so re-check before a paid step in a long session.

What a silent failure looks like

Without a gate, the agent would carry on without Sume tools. It might tell the user it cannot generate media, or it might improvise with whatever other tools it has. Neither outcome raises an error, and you only notice when a deliverable is missing.

A status gate turns that into a visible, early failure with a reason. In a scheduled job, that is the difference between an alert at start-up and a gap in output discovered next week.

Checklist

Wire these into the worker's start-up path so a missing tool surface fails loudly.

  • Fail fast on failed, needs-auth and disabled.
  • Re-check status before each paid tool, not only once.
  • Call mcp_health as the first tool, a free read.
  • Log the status value, never the headers.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume