MCP Fusion/Protocol and runtime/エラー

エラー

VinkiusについてAIに質問

ワイヤーにおけるエラー契約:tool_error XML エンベロープ、正規のエラーコード、warning の重大度、自己修復的な検証メッセージ、そして fluent な ErrorBuilder。

MCP サーバーにおけるエラーは、スタックトレースではなく言語モデルへのメッセージです。MCP Fusion はすべての失敗を、エージェントが対応できる構造化 XML エンベロープにシリアライズします。このページはそのエンベロープの仕様です。

tool_error エンベロープ

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>

toolError(code, { message, suggestion, availableActions, details, retryAfter }) が構築します。message は必須で、他は設定されたときだけ出力される省略可能なセクションです。コンテンツのエスケープは意図的に &< のみを XML エスケープし、> や引用符は、唯一の利用者であるモデルにとって読みやすいままになります。

重大度のルール

重大度isError意味
errortrueaction は失敗した
criticaltrue失敗し、安易な再試行は不可
warningfalse案内は成功パスに添えられる

warning が興味深い存在です。レスポンスは <tool_error> の案内を乗せても isError: false であり得るので、モデルは失敗シグナルなしに留意事項を受け取れます(deprecated なパラメータの使用、フォールバックの適用、部分結果の切り詰め)。

正規のエラーコード

MISSING_DISCRIMINATORUNKNOWN_ACTIONVALIDATION_ERRORMISSING_REQUIRED_FIELDINTERNAL_ERRORRATE_LIMITEDUNAUTHORIZEDFORBIDDENNOT_FOUNDCONFLICTTIMEOUTSERVER_BUSYDEPRECATEDAUTH_REQUIREDHANDOFF_UPSTREAM_UNAVAILABLEHANDOFF_NAMESPACE_MISMATCHHANDOFF_CONNECTING。この型は閉じてから開く設計です。オートコンプリートには上記が並びますが、独自コードも許可されます。RATE_LIMITEDretry_after 秒を運び、SERVER_BUSY は concurrency guard の負荷軽減(load shedding)から、キューへの案内付きで返ります。

自己修復のために書かれる検証エラー

Zod のリジェクトはそのまま渡されません。ValidationErrorFormatter は次を出力します:

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>

各問題は、送信された値と期待された値を並べた 1 行になり、Zod の issue コード(invalid_formattoo_smallunrecognized_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 を渡すと、MCPFusionClientErrorcoderecoveryavailableActionsseverity、そしてパース済みの raw オブジェクトを運びます。ラップが発生する箇所は Runtime architecture を参照してください。

次のステップ