feat(mcp): handle McpError(-32042) for MCP payment challenges#1728
Open
tenequm wants to merge 4 commits intocoinbase:mainfrom
Open
feat(mcp): handle McpError(-32042) for MCP payment challenges#1728tenequm wants to merge 4 commits intocoinbase:mainfrom
tenequm wants to merge 4 commits intocoinbase:mainfrom
Conversation
The MCP TypeScript SDK's McpServer catch block discards error.data for all McpError codes except -32042 (UrlElicitationRequired from SEP-1036). This is the only error code that survives the McpServer round-trip with data intact, as tracked in: modelcontextprotocol/typescript-sdk#774 MCP servers using McpError(-32042) for payment challenges (per SEP-1036 which explicitly covers payment flows) need x402MCPClient to catch these thrown errors in addition to parsing isError tool results. Changes: - Add JSONRPC_PAYMENT_REQUIRED_CODE (-32042) constant - Update isPaymentRequiredError() to handle both 402 and -32042 codes - Add extractPaymentRequiredFromError() to x402MCPClient for extracting PaymentRequired from thrown McpError exceptions - Wrap callTool() and getToolPaymentRequirements() with try/catch to handle thrown -32042 errors alongside existing isError result parsing - Support both direct error.data and namespaced error.data.x402 formats - Add 17 new test cases covering all -32042 paths
Eliminate duplicated validation logic in extractPaymentRequiredFromError by using the isPaymentRequiredError() type guard as the gate, then extracting PaymentRequired from the validated error shape. Removes the JSONRPC_PAYMENT_REQUIRED_CODE import from the client module since the code check is now delegated to the type guard.
🟡 Heimdall Review Status
|
|
@tenequm is attempting to deploy a commit to the Coinbase Team on Vercel. A member of the Team first needs to authorize it. |
Bortlesboat
added a commit
to Bortlesboat/x402
that referenced
this pull request
Mar 30, 2026
Port TypeScript PR coinbase#1728 to Python SDK. When an MCP server throws -32042 (SEP-1036 UrlElicitationRequired) with payment requirements in error.data, the client now catches and processes payment automatically. Adds JSONRPC_PAYMENT_REQUIRED_CODE constant, updates error extraction utilities, and wraps both async and sync client call_tool methods.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The MCP TypeScript SDK's
McpServercatch block discardserror.datafor allMcpErrorcodes except-32042(UrlElicitationRequiredfrom SEP-1036). This is tracked in modelcontextprotocol/typescript-sdk#774.MCP servers that use
McpError(-32042)for payment challenges (which SEP-1036 explicitly covers as a use case) can deliverPaymentRequireddata intact through the SDK. However,x402MCPClientonly parses payment info fromisErrortool results - it doesn't catch thrown-32042exceptions, so these payment challenges are silently lost.Solution
Teach
x402MCPClientto handle both delivery mechanisms:isErrortool results withPaymentRequiredinstructuredContentorcontent[0].text(backwards-compatible with all current x402 MCP servers)McpError(-32042)withPaymentRequiredinerror.data(directly or namespaced undererror.data.x402)This is additive - no breaking changes. Existing servers using
isErrorresults continue to work unchanged.Changes
src/types/mcp.tsJSONRPC_PAYMENT_REQUIRED_CODE(-32042) constant with SEP-1036 / SDK#774 contextisPaymentRequiredError()type guard to accept both402and-32042error codes, including theerror.data.x402namespaced formatsrc/client/x402MCPClient.tscallTool()andgetToolPaymentRequirements()in try/catch to intercept thrown-32042errorsextractPaymentRequiredFromError()private method that uses theisPaymentRequiredErrortype guard, then extractsPaymentRequiredfrom the correct locationtest/unit/client.test.ts-32042data, namespacederror.data.x402, non-payment error re-throwing, retry with payment metadata, approval flow, hooks, andgetToolPaymentRequirements()Why -32042?
SEP-1036 defines
-32042for flows where "the server needs the client to provide something before proceeding" and explicitly includes payment as a use case. It is the only custom error code the MCP TypeScript SDK propagates witherror.dataintact throughMcpServer's tool handler. Using it for payment challenges is the standard-compliant path forward until SDK#774 is resolved.Testing
advanced.tshas pre-existing unrelated errors onmain)