Claude Code mcp_server_errors: fail CI when Sume never loaded
In stream-json runs Claude Code reports a skipped MCP entry in mcp_server_errors. Check it with jq before a CI job spends on Sume, then verify with mcp_health.

Read the mcp_server_errors field of the system init event and fail the job if it is not empty. Claude Code's MCP documentation says that in --output-format stream-json runs, a skipped --mcp-config entry is reported there, so scripts can detect that the server never loaded; that needs Claude Code v2.1.219 or later. For a Sume job this matters because a skipped entry does not stop the run: the agent simply finishes without any Sume tools, and the pipeline looks green.
Claude Code's claims here come from its MCP documentation, read on 2026-10-03. Sume's come from MCP OAuth and API keys and MCP tools and gates.
What does mcp_server_errors tell a script?
The documentation names the field and the version; it does not publish the item shape, so treat the contents as opaque text for a human and test only whether the field has entries. The case the docs call out is a config entry Claude Code could not load, for example an entry with a url and no type, or an in-process sdk entry that only an SDK host can register.
It does not cover a server that loaded and then failed to connect or authenticate. Those show up as connection statuses (Failed to connect, Needs authentication) in claude mcp list and /mcp, so a complete gate checks both the config and the live server.
| Failure | Where Claude Code reports it | Script check |
|---|---|---|
Entry skipped (no type, reserved name, sdk type) | mcp_server_errors in the system init event, v2.1.219+ | Fail on a non-empty field |
| Server added but not signed in | Needs authentication in claude mcp list and /mcp | Use an API key in headless runs |
| Server added, endpoint unreachable | Failed to connect, with the HTTP status or code in recent versions | Run claude mcp get <name> before the job |
How do I wire the check for Sume?
Pass the server with --mcp-config and an API key header, since a headless run has no browser for the OAuth sign-in. Sume accepts Authorization: Bearer <key> or x-api-key, and an API-key session sees the full hosted tool set. Add --strict-mcp-config so only that file's servers are used; the docs say a strict session uses only the servers you pass with --mcp-config and, from v2.1.246, no longer waits on approval for project-scoped servers.
The jq filter below does not depend on the field's inner shape. It reads every JSON line, and prints and fails if any line carries a non-empty mcp_server_errors. A missing field and an empty array both count as clean.
claude -p "Call mcp_health and report auth_source" \
--mcp-config ./sume.mcp.json --strict-mcp-config \
--output-format stream-json --verbose > run.ndjson
jq -e -s 'map(.mcp_server_errors // [] | select(length > 0)) | length == 0' run.ndjson \
|| { echo "Sume MCP entry did not load"; exit 1; }What should the job check after the server loads?
Have the prompt call mcp_health, which Sume lists as the read-only tool that reports endpoint readiness, auth source and safety posture. With an API key the auth source is not mcp_oauth, so the field also shows which credential the job used. Do not generate media in a gate step: paid and write calls need an idempotency_key, and dry_run previews cost without submitting.
If the job later waits on a render, remember the hold limit. Every remote POST /mcp caller holds at most 55 seconds per jobs_wait call (50 when the timeout is omitted); on wait_slice_expired, call jobs_wait again with the same ids and never resubmit the create. Jobs and results has the batch form with up to 20 ids.
What does a clean pass look like?
The run prints a stream of JSON lines. The init event is the first one, and for a good config its mcp_server_errors is empty or absent, so the jq expression prints true and the step exits zero. A bad entry, such as a url-only block, makes the filter print false and the || branch fail the job with a clear message instead of a silent no-op.
Keep the gate cheap. It makes one read-only call and runs in seconds. Put it before any step that generates media, so a broken config costs a minute and not a wasted job. Pin the Claude Code version in CI as well: the field needs v2.1.219 or later, and an older binary simply will not emit it, which the jq filter would read as clean.
Sources
Related posts
More in Developers
- Claude Code token usage vs Sume spend: two meters, one session
Claude Code's token totals and Sume's generation spend are billed in different places. Log tokens with a mod, read Sume's wallet with usage_get, and compare.
- claude plugin install --config: setting a bundled MCP server
Claude Code 2.1.285 added claude plugin install --config for bundled MCP server settings. What to put there for a Sume plugin, and what never to.
- claude plugin validate: read the hooks and calls lines of a mod
Before installing a Claude Code mod, run claude plugin validate and read its hooks and calls lines. Which combinations matter when Sume's MCP is connected.
- Sonnet 5.5 thinking disabled is a 400 at effort high: Sume
On Sonnet 5.5, thinking disabled is a 400 at effort high or below; use between_tools. Sume's Claude rows expose no thinking or effort fields.
Written by Sume