@vauban-org/pay-mcp
v0.5.1
Published
Vauban Pay MCP server -- x402 payment tools over StreamableHTTP
Readme
@vauban-org/pay-mcp
Vauban Pay MCP server -- x402 payment tools for MCP clients.
Install
npx @vauban-org/pay-mcpOr as an MCP client entry (Claude Desktop, Claude Code, any MCP client):
{
"mcpServers": {
"vauban-pay": { "command": "npx", "args": ["-y", "@vauban-org/pay-mcp"] }
}
}Listed in the official MCP Registry
as tech.vauban/pay-mcp — a domain-verified name, not a platform account:
ownership is proven by an Ed25519 signature whose public key lives in a DNS
record at the apex of vauban.tech. Also on
Smithery.
Nothing of ours is required to run it: no account, no token, no Vauban endpoint.
jcs_hash and request_delegation_grant are offline. The two tools that read
Starknet use whichever node you point STARKNET_RPC_URL at, and the default is
a public one we do not operate.
There is a second entrypoint, dist/serve.js, which speaks HTTP and refuses
every call without a JWT issuer, audience and JWKS endpoint. That one is our own
Kubernetes deployment; it needs @vauban-org/auth, which is not on the public
registry, and it exits rather than serve unverified requests when that package
is missing. If you are reading this to try the tools, you want the stdio
entrypoint above.
Try it in 60 seconds (offline, no config)
After the client entry above, ask your agent to canonicalize and hash a JSON
object — jcs_hash is fully offline, so this needs no keys, no RPC, no network:
Use the
jcs_hashtool on{"b": 2, "a": 1}and show me the digest.
You get back the RFC 8785 canonical form {"a":1,"b":2} and its SHA-256. The
point of the demo: two objects that differ only in key order hash to the same
digest — that is the canonicalization every STARK receipt in this ecosystem is
built on. Change a value, and the digest changes; reorder keys, and it does not.
Then, still offline, request_delegation_grant builds and hashes a
bounded-spend authorization object without touching a chain. Only make_payment
in chain mode and verify_receipt in on-chain mode read Starknet, and only when
you give them an RPC — see below.
Tools
| Tool | Description |
|------|-------------|
| jcs_hash | JCS (RFC 8785) canonicalize a JSON object and return its SHA-256 hex digest |
| make_payment | Submit an x402 bounded-spend authorization; emits a real Starknet Sepolia tx when signer env vars are set |
| verify_receipt | Verify a SettlementReceipt via JCS hash comparison (local mode) or by reading the PaymentReceiptEmitted on-chain event (chain mode) |
| request_delegation_grant | Build and JCS-hash a DelegationGrant authorization object |
| check_merchant | Check a merchant's proven service history (e.g. https://demo.pay.vauban.tech/x402/v1/history). Four verdicts, never conflated: PROVEN_SAMPLE, REFUTED (names the contradicting element), NO_RECORD (indeterminate, not negative), UNREACHABLE (a transport fact, not a merchant fact). An RPC outage degrades chain checks to structural level and says so |
| pay_for_resource | The x402 client walk: GET a resource, and if it answers 402, download a STARK proof, gunzip it in memory, and POST it back to settle. Outcomes: no_payment_required (200 direct -- free, not a failure), paid (content + PAYMENT-RESPONSE receipt + manifest), refused (402 again, server's reason verbatim), unreachable (transport fact only). v0 limit: no public prover exists, so the proof submitted is always PRE-GENERATED and published by the merchant, never produced by this agent -- every paid result carries an honesty label saying exactly what the 200 does and does not prove |
Environment variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| STARKNET_RPC_URL | No | https://starknet-sepolia-rpc.publicnode.com | Starknet Sepolia RPC. Point it at whichever node you trust; the default is a public one we do not operate, deliberately. |
| PAY_MCP_SEPOLIA_ACCOUNT_ADDRESS | No | -- | Starknet Sepolia account address for chain mode. When absent, make_payment returns JCS-only (status: pending). |
| PAY_MCP_SEPOLIA_PRIVATE_KEY | No | -- | Private key hex for that account. Never commit it; supply it through your own secrets handling. |
The HTTP transport reads several more, all of them mandatory; it is not the entrypoint you want. See the Install section above.
Chain mode (make_payment)
When PAY_MCP_SEPOLIA_ACCOUNT_ADDRESS and PAY_MCP_SEPOLIA_PRIVATE_KEY are both set:
make_paymentbuilds the DelegationGrant object, JCS-hashes it, then callsemit_receiptonPaymentDemoEmitterat0x044dd87a94a801cf775d4c5e4b6703102d4e97e1cd1d0a8879341219ae4f19ff.- Returns
status: "submitted"withtx_hash,voyager_url,settlement_receipt, andreceipt_jcs_hash. - The Voyager link (
https://sepolia.voyager.online/tx/<hash>) can be opened to verify thePaymentReceiptEmittedevent on-chain.
The Sepolia account must hold testnet STRK to pay for transactions. Obtain from the StarkWare Sepolia faucet.
When signer env vars are absent (fallback / demo-grade mode):
make_paymentreturnsstatus: "pending"with only thepayment_hashandjcs_bytes_b64fields.- No network call is made. This is safe for local development and CI.
verify_receipt modes
Local JCS mode -- provide receipt + expected_hash:
{
"receipt": { "type": "SettlementReceipt", "amount": 5000, "currency": "USDC" },
"expected_hash": "sha256:abcdef..."
}Returns { valid, computed_hash, match }.
On-chain mode -- provide tx_hash:
{ "tx_hash": "0x<starknet_sepolia_tx_hash>" }Reads the PaymentReceiptEmitted event from Starknet Sepolia, reconstructs the receipt object, and returns an audit-ready proof bundle including on_chain_event, reconstructed_receipt, computed_jcs_hash, and voyager_url.
License
Apache License 2.0. See LICENSE.
This package ships compiled output only. It implements the x402 payment wire format and STARK receipt verification described in the Vauban IETF Internet-Drafts; the specification is public and independently implementable.
