fix(mcp): use scheme="exact" in X-Payment envelope so the facilitator actually accepts it#18
Merged
Merged
Conversation
The aceguard_pay_for_api MCP tool was constructing the X-Payment envelope
with scheme="solana", but FacilitatorX402 (the upstream that
api.acedata.cloud routes to) is x402-spec compliant: its multichain view
matches on (scheme="exact", network=<chain>), not on scheme=<chain>.
In practice this means every aceguard_pay_for_api call would loop on 402
even after a successful on-chain agent_vault.spend() — the policy check,
SPL transfer, and tx signature were all real, but the facilitator
rejected the envelope as an unrecognized scheme and returned 402 again,
making the agent see the call as "payment failed" with no way to debug.
Fix: scheme: "solana" -> scheme: "exact". Wire-format alignment with
@acedatacloud/x402-client (typescript/scripts/test-solana-e2e.ts:172) and
the AceDataCloud Python SDK payment_handler that downstream demos will
plug into. payload.signature stays the same — facilitator
solana_chain.py:_extract_signature accepts {payload: {signature: <tx>}}
exactly.
No test added: this code path requires a real on-chain spend + live
facilitator round-trip; covered by the manual demo in scripts/ (next PR).
acedatacloud-dev
added a commit
that referenced
this pull request
May 10, 2026
…Claude (#19) User reported "MCP could not be loaded" on Claude Desktop. Two real issues underneath the symptom: 1. The README's Step 4 config (`{"mcpServers": {"aceguard": {"url": "..."}}}`) is the Claude.ai web Custom Connectors schema, not the Claude Desktop one. Claude Desktop only speaks stdio MCP — to load an HTTP MCP endpoint it needs the `mcp-remote` stdio<->HTTP bridge. 2. There was no way to test the MCP endpoint without going through a client at all, so any failure mode (network, token, server, client config) all surfaced as the same opaque "could not be loaded". Two scripts to cover (2): - scripts/demo.py — Python (httpx + stdlib). Speaks JSON-RPC to the MCP endpoint, runs the full sequence: tools/list → balance → pay_for_api → balance → history (with Solscan deep-link). Distinguishes 401-bad-token, RPC-error, isError-true (policy rejection), upstream non-200, and "endpoint healthy" cleanly. - scripts/mcp-curl.sh — bash + curl + jq variant. Same script for users without a Python toolchain. README rewrite for Step 4: now documents three paths in order of "needs an LLM in the loop": 4a. Verify it works at all → run the bundled demo 4b. Claude Desktop → mcp-remote bridge config (correct schema) 4c. Cursor / Cline / etc. → URL straight in 4d. Skip MCP → @acedatacloud/x402-client SDK direct call DEMO.md updated to the same mcp-remote config + a new troubleshooting row pointing at the demo script as a self-diagnostic. Smoke-tested live against https://x402guard.acedata.cloud/mcp/<bad-token>: proper 401 detection + remediation hint. ruff check clean. shellcheck clean (`bash -n`). Pairs with #18 (envelope `scheme: "exact"` fix) — together those two PRs make `aceguard_pay_for_api` actually work end-to-end and let the user prove that *without* depending on a specific LLM client. Co-authored-by: acedata-bot <bot@acedata.cloud>
acedatacloud-dev
added a commit
that referenced
this pull request
May 10, 2026
…pay_for_api caveat (#22) Adds a "Live on devnet" badge + a quoted callout near the top with the real 2026-05-10 verification result (3 spends, vault 4.00 -> 3.97 USDC, finalized tx 249u8Pion...3y3D on Solscan). The customer who reported "MCP could not be loaded" can now skim the top of the README, click the Solscan link to confirm the on-chain side is live, and run the curl / demo recipe to confirm their own MCP URL is healthy without any Claude / Cursor / SDK plumbing. Concrete changes: - "60-second verification" section near the top: 3 steps, all `curl` + `python scripts/demo.py`. End-state explicitly: "If steps 1-2 work, any `MCP could not be loaded` you see in Claude Desktop is a client-side problem". - Spelled out the `aceguard_spend` request/response shape with a real finalized tx as the canonical example. Added the `recipient ATA must exist on devnet` pre-req inline (Anchor 3012), with the one-line `spl-token create-account` command to satisfy it. - Pivoted Step 5 of the walkthrough from `pay_for_api` to `aceguard_spend`. Reason: api.acedata.cloud issues mainnet x402 quotes (`EPjFWdd5...` mint, `5iVXFr...` payTo); the production x402guard deploy is on devnet, so the recipient ATA the on-chain program expects does not exist on this cluster. This is *expected* per .plans/X402GUARD.md and called out clearly so customers do not burn an afternoon trying to make that path work pre-mainnet flip. - Updated Step 6 (boundary-in-action prompts) to use `aceguard_spend` invocations that map to actual Anchor errors today, instead of the pre-existing `pay_for_api` examples that no longer fire. Pairs with #18 / #19 / #20 / #21. The mainnet flip stays the V2 step .plans/X402GUARD.md already calls out (#11 / "Why devnet, not mainnet"). Co-authored-by: acedata-bot <bot@acedata.cloud>
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.
Summary
User reported their
aceguard_pay_for_apicalls showing "MCP could not be loaded" / payment failures. Tracking it down, there's a real wire-format bug independent of any client setup: the X-Payment envelope built in_tool_pay_for_apideclaresscheme: "solana", but the upstream facilitator (FacilitatorX402, whatapi.acedata.cloudroutes 402 retries to) is x402-spec compliant and matches onscheme: "exact"+network: "solana"— not onscheme: "<chain>".Live in
x402f/views_multichain.py:178:{"x402Version": 2, "scheme": "exact", "network": network}So today every
aceguard_pay_for_apiinvocation:accepts→ picksnetwork: "solana"(correct)execute_spend()→ on-chainagent_vault.spend()succeeds, real USDC moves, real tx signature returned (correct)scheme: "solana"and retriesscheme: "solana"Wallet pays, agent sees nothing. That's the worst possible failure mode for this product.
Fix
scheme: "solana"→scheme: "exact". One field.payload.signature(the on-chain tx hash) stays identical — facilitatorsolana_chain._extract_signaturereads it frompayload.signatureexactly.Also rewrites the comment to point at the actual facilitator source rather than describing what we thought it accepted.
Verification
uvx ruff check api/routes/mcp.py— cleanpython -c "import ast; ast.parse(...)"— parses@acedatacloud/x402-clientSolana e2e script (usesscheme: "exact")payment_handlerthat downstream demos consumescheme: "exact"End-to-end re-verification (live spend + facilitator round-trip) is covered by the demo script in the follow-up PR — needs a funded vault, can't run in CI.
What this does NOT change
aceguard_balance/aceguard_history/aceguard_spendtools — they don't build envelopes, only_tool_pay_for_apidoesRisk
Negligible. The current value is provably broken (facilitator does not match the scheme); the new value is what every other production payment in this org uses.