feat(cli): scripts/demo.py + mcp-curl.sh — drive MCP without Claude; README/DEMO Step 4 rewrite#19
Merged
Merged
Conversation
…Claude
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.
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
MCP could not be loadedon Claude Desktop. Two realissues underneath that symptom:
{"mcpServers": {"aceguard": {"url": "..."}}}is the Claude.ai webCustom Connectors schema, not the Claude Desktop one. Claude
Desktop only speaks stdio MCP. To attach an HTTP MCP endpoint to
it you need the community-standard
mcp-remotestdio↔HTTP bridge.bad tokens, server bugs, and client-config bugs all surfaced as the
same opaque "could not be loaded" string, leaving the user no
diagnostic.
This PR fixes both. Pairs with #18 — together they make
aceguard_pay_for_apiactually work end-to-end and give the user away to prove that without depending on any specific LLM client.
What's added
scripts/demo.py— pure-Python CLI demohttpx+ stdlib, no SDK / no MCP libraries. Speaks JSON-RPC to theendpoint and runs the full sequence:
Argument-parsed:
--url,--body,--method,--skip-pay. Errorpaths return distinct exit codes (1 = fatal; 2 = pre-flight failure
e.g. paused / empty vault / 401 token; 3 =
pay_for_apiisErrorcase — policy rejection or upstream non-200).
Smoke-tested live against
https://x402guard.acedata.cloud/mcp/<bad-token>:Right answer, with remediation. Live test against a real funded vault
needs an unmerged token + USDC; reviewer with prod access can run it
manually.
scripts/mcp-curl.sh— bash + curl + jq variantSame flow, no Python required. Useful for users on minimal containers
or for the "5-minute screen recording" we'll cut for the submission
video.
README.md— Step 4 rewriteThe old "wire the URL into Claude Desktop" section was replaced with
four sub-steps in order of "how much LLM machinery do you need?":
python scripts/demo.py <URL>mcp-remotebridge (with the correct JSON config)@acedatacloud/x402-clientSDK directlyapi.acedata.cloudcall from your own wallet, without the on-chain policy enforcement that x402guard adds.Cross-links to the
@acedatacloud/x402-clientSDK and itsscripts/test-solana-e2e.tsfor path 4d. The framingmakes it explicit that x402guard is value-on-top of the SDK
(spending caps + allowlist enforced on-chain), not a different product.
DEMO.md— same correction in the demo scriptThe 1:20–1:50 segment of the recorded demo now uses the
mcp-remotebridge form. Added a B-roll suggestion: split-screen Claude Desktop
against
python scripts/demo.pyto make the "the boundary lives inthe program, not the client" point visually.
Added two troubleshooting rows:
{"url": "..."}→ switch to bridge formVerification
uvx ruff check scripts/demo.py— cleanbash -n scripts/mcp-curl.sh— cleanpython3 -c "import ast; ast.parse(open('scripts/demo.py').read())"— parses401 handling
Risk
Documentation + new files only. No behaviour change in the running
backend / web / Anchor program.