Back to Blog

Stacking MPP, MCP, and ACP for Agent Commerce

Three protocol layers: MPP payment gate, MCP tools, and ACP checkout around a peptide vial motif

TL;DR

  1. 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.
  2. 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.
  3. Stripe test mode only. The Worker rejects sk_live_ keys. MPP charges are $0.01 demo amounts via mppx and Stripe MPP. ACP checkout uses simulated payment tokens.
  4. 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| ACP

Inside the Worker, the request flows through: rate limitingMPP 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 methodsinitialize, tools/list, ping, notifications/*, prompts/*, resources/*, logging/*, completion/*: pass through to the MCP handler without payment.
  • Paid methodstools/call and anything not in the exempt list: require a valid Authorization: Payment header with a Stripe shared payment token. Without it, the Worker returns HTTP 402 with a WWW-Authenticate: Payment challenge 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":{}}'
# → 200

MCP 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 tools

Run with: cd backend && npm run test:mcp-order


Try it


Security notes

  • Payment credentials are secrets. Never log Authorization: Payment header values or echo them in error responses.
  • Challenges are time-limited. The expires field in the WWW-Authenticate header bounds the challenge window; mppx handles challenge binding with MPP_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.

SA
Written by Sumit Agrawal

Software Engineer & Technical Writer specializing in full-stack development, cloud architecture, and AI integration.

Related Posts