---
title: "Stacking MPP, MCP, and ACP for Agent Commerce"
date: 2026-03-28T21:30:00.000Z
description: "How Machine Payments Protocol, Model Context Protocol, and Agentic Commerce Protocol fit together on one Cloudflare Worker — with two distinct transaction flows, Stripe test mode, and live evidence."
tags: ["mpp", "mcp", "acp", "agentic-commerce", "stripe", "cloudflare-workers", "ai-agents", "machine-payments"]
tokens: 1671
content-signal: search=yes, ai-input=yes, ai-train=no
---


![Three protocol layers: MPP payment gate, MCP tools, and ACP checkout around a peptide vial motif](/images/posts/machine-payments-protocol-mcp-acp/hero.png)

## 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`](https://www.npmjs.com/package/mppx) and [Stripe MPP](https://docs.stripe.com/payments/machine/mpp). ACP checkout uses simulated payment tokens.
4. **Shipped.** Code on [`main`](https://github.com/tech-sumit/acp-peptide-pharmacy), live Worker at [acp-peptide-pharmacy-backend.tech-sumit.workers.dev](https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/), and the [storefront](https://tech-sumit.github.io/acp-peptide-pharmacy/) 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](https://tech-sumit.github.io/acp-peptide-pharmacy/) 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](https://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`](https://github.com/tech-sumit/acp-peptide-pharmacy/blob/main/backend/src/mpp/mcp-methods.ts). |
| **MCP** ([modelcontextprotocol.io](https://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

```mermaid
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 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/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](https://www.rfc-editor.org/rfc/rfc9457) (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](https://www.npmjs.com/package/mppx), [Stripe MPP docs](https://docs.stripe.com/payments/machine/mpp)), 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

```bash
curl -s https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/health | python3 -m json.tool
```

```json
{
    "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)

```bash
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)

```bash
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):

```text
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
```

```json
{
    "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:

```text
✓ 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

- **Source code**: [github.com/tech-sumit/acp-peptide-pharmacy](https://github.com/tech-sumit/acp-peptide-pharmacy) — README covers `wrangler secret put` for `STRIPE_SECRET_KEY` and `MPP_SECRET_KEY`.
- **Storefront**: [tech-sumit.github.io/acp-peptide-pharmacy](https://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](https://tech-sumit.github.io/acp-peptide-pharmacy/mpp-demo.html).
- **Live Worker**: [acp-peptide-pharmacy-backend.tech-sumit.workers.dev](https://acp-peptide-pharmacy-backend.tech-sumit.workers.dev/) — root JSON shows `mpp_demo_billing` metadata and all endpoints.

---

## 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.
