MCP Fusion/Protocol and runtime/Errors

Errors

Ask AI about Vinkius

The error contract of the wire: the tool_error XML envelope, the canonical error codes, warning severities, self-healing validation messages and the fluent ErrorBuilder.

An error in an MCP server is a message to a language model, not a stack trace. MCP Fusion serializes every failure into a structured XML envelope the agent can act on. This page is the specification of that envelope.

The tool_error envelope

xml
<tool_error code="NOT_FOUND" severity="error">
  <message>No invoice with that ID</message>
  <recovery>List invoices first, then retry with a real ID</recovery>
  <available_actions>
    <action>billing.list_invoices</action>
  </available_actions>
  <details>
    <detail key="requestedId">inv_2026_9999</detail>
  </details>
  <retry_after>30 seconds</retry_after>
</tool_error>

Built by toolError(code, { message, suggestion, availableActions, details, retryAfter }). message is required; the rest are optional sections emitted only when set. Content is XML-escaped on & and < only, on purpose: > and quotes stay readable for the model, which is the only consumer.

The severity rule

SeverityisErrorMeaning
errortruethe action failed
criticaltruefailed and should not be retried blindly
warningfalseguidance rides the success path

warning is the interesting one: a response can carry <tool_error> guidance and still be isError: false, so a model gets the caveat without the failure signal (deprecated parameter used, fallback applied, partial result truncated).

The canonical codes

MISSING_DISCRIMINATOR, UNKNOWN_ACTION, VALIDATION_ERROR, MISSING_REQUIRED_FIELD, INTERNAL_ERROR, RATE_LIMITED, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, TIMEOUT, SERVER_BUSY, DEPRECATED, AUTH_REQUIRED, HANDOFF_UPSTREAM_UNAVAILABLE, HANDOFF_NAMESPACE_MISMATCH, HANDOFF_CONNECTING. The type is closed-then-open: autocomplete shows these, custom codes are allowed. RATE_LIMITED carries retry_after seconds; SERVER_BUSY comes from the concurrency guard's load shedding with queue guidance.

Validation errors are written to be healed

A Zod rejection is not passed through raw. ValidationErrorFormatter emits:

xml
<validation_error action="billing.get_invoice">
  <field name="id">Invalid email format. You sent: 'not-an-email'. Expected a valid email address.</field>
  <recovery>Fix the fields above and call the tool again. Do not explain the error.</recovery>
</validation_error>

Each issue becomes a line with what was sent and what was expected, tuned per Zod issue code (invalid_format, too_small, unrecognized_keys...). The final instruction, "Do not explain the error", exists because the model's instinct is to apologize to the user instead of re-calling the tool.

Contract deltas on top

With attachToServer({ selfHealing }) configured, a validation error additionally embeds a <contract_awareness> section: the BREAKING and RISKY deltas from the last ContractDiff against the known-good lockfile, scoped to the failing action and capped (five by default). The agent that learned the old contract gets told exactly what changed, in the same error turn. See Governance.

Throwing vs returning

Handlers can return toolError(...) or throw toolError(...): branded ToolResponse throws pass through the pipeline intact, so the code, severity and sections survive. An unbranded throw (a real exception from your code or a dependency) is wrapped as INTERNAL_ERROR with a "do not blindly retry" recovery. Middleware follows the same rule.

The fluent builder

f.error('NOT_FOUND', 'Invoice missing') returns a chainable builder: .suggest(), .actions('billing.list_invoices'), .severity('warning'), .details({ requestedId }), .retryAfter(30). It duck-types ToolResponse (the content getter builds lazily), so return f.error(...) works directly in handlers without .build().

On the client side

The typed client parses this envelope back: MCPFusionClientError carries code, recovery, availableActions, severity and the parsed raw object, when you pass throwOnError: true. See Runtime architecture for where wrapping happens.

Next steps