
TL;DR
- Three protocols, three concerns. MPP gates access to paid API calls. MCP provides the tool surface for AI agents. ACP structures merchant checkout (cart, buyer, fulfillment, payment) over REST.
- Two transaction flows. (A) Book a demo order through the storefront or ACP REST endpoints — no per-request billing. (B) Call the same tools via MCP
tools/call— with MPP requiring a Stripe test-mode micropayment per invocation when enabled. Handshake methods (initialize,tools/list) stay free. - Stripe test mode only. The Worker rejects
sk_live_keys. MPP charges are $0.01 demo amounts viamppxand Stripe MPP. ACP checkout uses simulated payment tokens. - Shipped. Code on
main, live Worker at acp-peptide-pharmacy-backend.tech-sumit.workers.dev, and the storefront now surfaces MPP alongside ACP and MCP.
Two transaction flows
| What you pay for | Transport | MPP involved? | |
|---|---|---|---|
| Flow A — ACP order booking | Completing the merchant demo checkout (cart → session → simulated payment token) | Browser storefront or REST POST /checkout_sessions … /complete |
No — catalog and checkout stay outside MPP |
| Flow B — MCP + MPP tool access | Each agent tool invocation that hits the Worker as a paid JSON-RPC method | POST /mcp with tools/call |
Yes — Stripe test mode, $0.01 per call when STRIPE_SECRET_KEY + MPP_SECRET_KEY are set |
Flow A is the order story: browse products, build a cart, complete checkout. Flow B is metered API access: the same business logic, but each tools/call requires payment before the Worker processes it. The two concerns — "access to the tool surface" and "merchant payment for the order" — stay separate.
Why three protocols?
| Protocol | Question it answers | Role in the demo |
|---|---|---|
| MPP (mpp.dev) | Who paid for this HTTP request? | Returns HTTP 402 with a WWW-Authenticate: Payment challenge on paid POST /mcp JSON-RPC methods (e.g. tools/call). Handshake methods are exempt — see mcp-methods.ts. |
| MCP (modelcontextprotocol.io) | How does a client invoke tools in a standard way? | Streamable HTTP at /mcp exposes 8 tools: list_products, search_products, get_product_details, create_checkout, update_checkout, get_checkout_status, complete_checkout, cancel_checkout. |
| ACP (checkout style) | How does the merchant model carts, buyers, fulfillment, and orders? | REST checkout_sessions with line items, buyer info, and a simulated payment completion flow. |
MPP is not a replacement for ACP checkout. The $0.01 MPP charge is for access to the MCP tool; the demo order itself uses ACP's simulated payment.
Architecture
flowchart TB
subgraph client [AI or automation client]
Agent[Agent]
end
subgraph worker [Cloudflare Worker]
RL[Rate limiter]
MPP[MPP gate — paid methods only]
MCP[MCP server — 8 tools]
ACP[ACP REST — checkout sessions]
end
subgraph stripe [Stripe test mode]
Verify[SPT verification via mppx]
end
Agent --> RL
RL --> MPP
MPP -->|402 challenge| Agent
Agent -->|Authorization: Payment| MPP
MPP --> Verify
MPP -->|authorized| MCP
MCP --> ACP
Agent -->|browser or REST| ACPInside the Worker, the request flows through: rate limiting → MPP gate (only for chargeable POST /mcp bodies) → MCP handler or ACP REST handler.
Implementation details
Method-aware MPP gating
When MPP is enabled (STRIPE_SECRET_KEY + MPP_SECRET_KEY set as Wrangler secrets), the Worker parses the JSON-RPC request body on POST /mcp before deciding whether to invoke the MPP gate:
- Exempt methods —
initialize,tools/list,ping,notifications/*,prompts/*,resources/*,logging/*,completion/*: pass through to the MCP handler without payment. - Paid methods —
tools/calland anything not in the exempt list: require a validAuthorization: Paymentheader with a Stripe shared payment token. Without it, the Worker returns HTTP 402 with aWWW-Authenticate: Paymentchallenge header.
The gate uses mppx with stripe.charge, a $0.01 USD demo amount, and networkId: 'internal'. The 402 response follows RFC 9457 (problem details) and includes custom headers:
x-mpp-stripe-mode: test— confirms Stripe is in test mode.x-mpp-demo-billing: stripe-test-only-no-live-charges— signals this is a demo.
Discovery metadata
GET / and GET /health include an mpp_demo_billing object so clients can programmatically detect the billing mode before making any tool calls.
MCP transport compatibility
Cursor and mcp-remote connect over Streamable HTTP. They complete initialize and tools/list without encountering MPP. Standard MCP clients do not attach Authorization: Payment headers, so tools/call returns 402 when MPP is active. To make paid calls, use an MPP-aware client (mppx CLI, Stripe MPP docs), or run the test suite with MPP disabled (see below).
Known limitation: mppx CLI and Stripe SPT creation
The mppx CLI creates shared payment tokens via Stripe's test helper API. Some Stripe accounts return a 404 on that route until the Agentic Commerce / shared-payment-token capability is enabled. If you see Unrecognized request URL (POST: /v1/test_helpers/shared_payment/granted_tokens), check your Stripe account's feature access. The Worker-side 402 behavior is valid regardless — you can verify it with curl.
Live evidence
Health endpoint
curl -s https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/health | python3 -m json.tool{
"ok": true,
"service": "acp-peptide-pharmacy-backend",
"version": "0.1.0",
"mpp_demo_billing": {
"mpp_enabled": true,
"stripe_billing_mode": "test_only",
"live_stripe_keys_rejected": true,
"summary": "MPP uses Stripe test mode only (e.g. $0.01 demo charges). sk_live_ keys are rejected; no real-money card charges on this Worker."
}
}MCP discovery — free (HTTP 200)
curl -s -o /dev/null -w "%{http_code}" -X POST \
https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/mcp \
-H "content-type: application/json" \
-H "accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# → 200MCP tools/call — paid (HTTP 402 without payment)
curl -s -D - -o /dev/null -X POST \
https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/mcp \
-H "content-type: application/json" \
-H "accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_products","arguments":{}}}'Response (abbreviated):
HTTP/2 402
content-type: application/problem+json
www-authenticate: Payment id="...", realm="acp-peptide-pharmacy-backend.tech-sumit.workers.dev", method="stripe", ...
x-mpp-stripe-mode: test
x-mpp-demo-billing: stripe-test-only-no-live-charges{
"type": "https://paymentauth.org/problems/payment-required",
"title": "Payment Required",
"status": 402,
"detail": "Payment is required (MCP tool access (demo, Stripe test mode)).",
"challengeId": "..."
}Local testing (MPP off)
The Vitest env.test Wrangler profile sets MPP_DISABLED=true, so tools/call runs end-to-end without payment. This verifies the MCP + ACP tool chain independently of MPP:
✓ test/mcp.spec.ts (2 tests)
✓ exposes the peptide commerce tools to MCP clients
✓ creates and completes a demo peptide order through MCP toolsRun with: cd backend && npm run test:mcp-order
Try it
- Source code: github.com/tech-sumit/acp-peptide-pharmacy — README covers
wrangler secret putforSTRIPE_SECRET_KEYandMPP_SECRET_KEY. - Storefront: tech-sumit.github.io/acp-peptide-pharmacy — home page includes MPP in the active stack and protocol stack sections, with a dedicated MPP demo page.
- Live Worker: acp-peptide-pharmacy-backend.tech-sumit.workers.dev — root JSON shows
mpp_demo_billingmetadata and all endpoints.
Security notes
- Payment credentials are secrets. Never log
Authorization: Paymentheader values or echo them in error responses. - Challenges are time-limited. The
expiresfield in theWWW-Authenticateheader bounds the challenge window;mppxhandles challenge binding withMPP_SECRET_KEY. - Separate concerns. MPP charges for MCP tool access; ACP (or your PSP) handles merchant checkout. Avoid double-charging for the same economic event.
Closing
MPP gives you a standards-based way to charge for agent-facing tool access at the HTTP layer. MCP keeps tool integrations portable across clients. ACP structures the merchant order flow. Stacking all three on one Worker demonstrates that these concerns compose cleanly without conflating "paid API access" with "merchant payment for an order."
Use Flow A to browse the storefront and complete a demo order with no per-call billing. Use Flow B to exercise paid MCP tools — with mppx or a custom MPP-aware client — once your Stripe account supports shared payment token creation.