MCP Fusion/Protocol and runtime/エラー
エラー
ワイヤーにおけるエラー契約:tool_error XML エンベロープ、正規のエラーコード、warning の重大度、自己修復的な検証メッセージ、そして fluent な ErrorBuilder。
MCP サーバーにおけるエラーは、スタックトレースではなく言語モデルへのメッセージです。MCP Fusion はすべての失敗を、エージェントが対応できる構造化 XML エンベロープにシリアライズします。このページはそのエンベロープの仕様です。
tool_error エンベロープ
<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>toolError(code, { message, suggestion, availableActions, details, retryAfter }) が構築します。message は必須で、他は設定されたときだけ出力される省略可能なセクションです。コンテンツのエスケープは意図的に & と < のみを XML エスケープし、> や引用符は、唯一の利用者であるモデルにとって読みやすいままになります。
重大度のルール
| 重大度 | isError | 意味 |
|---|---|---|
error | true | action は失敗した |
critical | true | 失敗し、安易な再試行は不可 |
warning | false | 案内は成功パスに添えられる |
warning が興味深い存在です。レスポンスは <tool_error> の案内を乗せても isError: false であり得るので、モデルは失敗シグナルなしに留意事項を受け取れます(deprecated なパラメータの使用、フォールバックの適用、部分結果の切り詰め)。
正規のエラーコード
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。この型は閉じてから開く設計です。オートコンプリートには上記が並びますが、独自コードも許可されます。RATE_LIMITED は retry_after 秒を運び、SERVER_BUSY は concurrency guard の負荷軽減(load shedding)から、キューへの案内付きで返ります。
自己修復のために書かれる検証エラー
Zod のリジェクトはそのまま渡されません。ValidationErrorFormatter は次を出力します:
<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>各問題は、送信された値と期待された値を並べた 1 行になり、Zod の issue コード(invalid_format、too_small、unrecognized_keys...)ごとに調整されます。「Do not explain the error」という最後の指示があるのは、モデルの本能が、tool を再呼び出しするより先にユーザーへ謝ることにあるからです。
上乗せされるコントラクト差分
attachToServer({ selfHealing })を設定すると、検証エラーには <contract_awareness> セクションも埋め込まれます。既知の良好な lockfile に対する直近の ContractDiff から、BREAKING と RISKY の差分を、失敗した action に絞って件数上限付き(デフォルト 5 件)で提示するものです。古いコントラクトを学習したエージェントは、同じエラーのターンで何が変わったのかを正確に知らされます。詳しくは Governance を参照してください。
throw と return の使い分け
handler は return toolError(...) も throw toolError(...) も可能です。ブランド付きの ToolResponse の throw はパイプラインをそのまま通り抜けるため、コード、重大度、セクションは維持されます。ブランドのない throw(自分のコードや依存関係からの実異常)は、復旧案内「do not blindly retry」を添えた INTERNAL_ERROR としてラップされます。ミドルウェアも同じルールに従います。
fluent ビルダー
f.error('NOT_FOUND', 'Invoice missing') はチェーン可能なビルダーを返します。.suggest()、.actions('billing.list_invoices')、.severity('warning')、.details({ requestedId })、.retryAfter(30)。ToolResponse の duck-typing を満たす作り(content getter は遅延構築)なので、handler では .build() なしに return f.error(...) をそのまま使えます。
クライアント側では
型付きクライアントはこのエンベロープを再度解釈します。throwOnError: true を渡すと、MCPFusionClientError は code、recovery、availableActions、severity、そしてパース済みの raw オブジェクトを運びます。ラップが発生する箇所は Runtime architecture を参照してください。
次のステップ
- Wire format:成功側のエンベロープ
- Security pipeline:どの guard がどのコードを出すか
- Testing:エラー形状に対するアサーション
