Skip to content

fix(python/mcp): gate tool output on settlement success#2356

Merged
phdargen merged 2 commits into
x402-foundation:mainfrom
apmcdermott:amandamcdermott/python-mcp-settlement-success-check
May 18, 2026
Merged

fix(python/mcp): gate tool output on settlement success#2356
phdargen merged 2 commits into
x402-foundation:mainfrom
apmcdermott:amandamcdermott/python-mcp-settlement-success-check

Conversation

@apmcdermott
Copy link
Copy Markdown
Contributor

@apmcdermott apmcdermott commented May 18, 2026

Description

The MCP payment wrappers in python/x402/mcp/server_sync.py and server_async.py call facilitator.settle() but don't branch on settle_result.success before returning the wrapped tool's output. Add the missing check so a failed settlement returns a structured 402 error result, matching the HTTP server path at python/x402/server.py:225-243.

Tests

  • python/x402/mcp/tests/test_server.py::test_create_payment_wrapper_settlement_returns_failure
  • python/x402/mcp/tests/test_server_async.py::test_create_payment_wrapper_async_settlement_returns_failure
  • python/x402/tests/unit/mcp/test_server_wrappers.py — verifies the settlement-failure helpers preserve extensions

Checklist

  • I have formatted and linted my code
  • All new and existing tests pass
  • My commits are signed

The MCP payment wrappers in server_sync.py and server_async.py called
facilitator.settle() but never branched on settle_result.success before
returning the wrapped tool's output. A signed EIP-3009 authorization
could be replayed indefinitely: verify passed each time, the tool ran,
settle returned success=False with AuthorizationAlreadyUsed, and the
wrapper returned the tool output stamped with the failed settlement
response in _meta.

Mirror the success check from the non-MCP path in server.py and route
to the existing _create_settlement_failed_result_{sync,async} helpers
on failure. Add regression tests covering the success=False branch
(distinct from the existing exception-path test) and assert that
on_after_settlement does not fire on failure.

Also fix a stale signature on the test mock's
_create_payment_required_response_real that was missing the extensions
parameter, which had been masking other test failures.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

@apmcdermott is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added sdk Changes to core v2 packages python labels May 18, 2026
@phdargen phdargen self-assigned this May 18, 2026
Copy link
Copy Markdown
Collaborator

@phdargen phdargen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you @apmcdermott

@phdargen phdargen merged commit 92f06b5 into x402-foundation:main May 18, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python sdk Changes to core v2 packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants