# Show HN: MCPay – spend authorization and per-call billing for MCP tools

> Source: <https://github.com/yiaany/MCPay>
> Published: 2026-09-02 17:37:35+00:00

**Stripe for AI agents and paid MCP tools.**

MCPay is building a Stripe-like payment layer for MCP: bounded agent budgets, per-call charging, and settlement for tool creators.

MCPay is building a shared payment layer where AI agents receive explicit spending limits, paid MCP calls carry verifiable spend authority, and tool creators can price usage and receive settlement through one integration.

The goal is to give agents one payment interface across paid MCP tools while regulated payment providers handle deposits, custody, payouts, refunds, and other real-money operations.

**Status as of August 31, 2026: test credits only. No real funds are accepted, held, transferred, or paid out.** Test top-ups create repository-local ledger entries with no cash value. Stripe deposits, bank transfers, creator payouts, KYC/AML, sanctions screening, disputes, refunds, tax handling, and regulated custody are not implemented.

The repository currently contains:

- a Go API, gateway, settlement worker, and PostgreSQL migrations;
- a dashboard for beta accounts, wallets, servers, actions, receipts, and test credits;
- JavaScript and Python SDK source for repository-local development;
- a Docker Compose stack and integration tests.

The beta is for controlled development and failure testing. It is not ready to hold customer funds or support financial commitments. See [Known Limitations](/yiaany/MCPay/blob/main/KNOWN_LIMITATIONS.md).

Future work is expected to include automated key management, operational monitoring, tested backup recovery, reconciliation tooling, incident response, and external security review. Real-money integrations would additionally require legal, compliance, custody, payout, dispute, refund, and tax work. None of those items should be inferred from the current ledger or UI.

| Area | Design goal | Current status |
|---|---|---|
| Spend scope | Bind server, environment, actions, prices, budget, expiry, and nonce range into a signed grant | Implemented for the beta; tokens are signed, not encrypted |
| Replay control | Coordinate claims across gateway instances | PostgreSQL claim state is implemented; this does not provide exactly-once tool delivery |
| Price stability | Use the price snapshot authorized for the session | Implemented with integer minor units |
| Usage durability | Retain accepted chargeable usage until upload is acknowledged | A persistent bbolt gateway state file is supported and tested across restart after durable preparation |
| Settlement | Make repeated usage ingestion and settlement safe to retry | Idempotency is implemented and tested for covered paths; exactly-once charging is not claimed |
| Money movement | Accept deposits and pay creators | Not implemented; test credits have no real-world value |
| SDK distribution | Install SDKs from public registries | Not available; npm and PyPI packages are unpublished |

```
sequenceDiagram
    participant A as Agent
    participant C as MCPay API
    participant G as MCPay Gateway
    participant P as PostgreSQL
    participant T as MCP Tool
    participant W as Settlement Worker

    A->>C: Create spend session
    C->>P: Reserve test-credit budget and store price snapshot
    C-->>A: Signed spend token
    A->>G: tools/call + token + nonce
    G->>G: Verify signed policy
    G->>P: Claim nonce and logical call
    G->>T: Dispatch tool request
    T-->>G: Return successful result
    G->>G: Durable PrepareUsage acceptance
    G-->>A: Attempt response delivery
    G->>G: Queue prepared usage
    G->>C: Upload usage batch
    C->>P: Insert idempotent usage record
    W->>P: Settle test-credit ledger entries
```

The gateway marks a call dispatched before contacting the upstream tool. If the process or network fails after dispatch, the upstream may have executed while the caller receives an error, and the nonce remains unavailable for replay. For a chargeable success, durable `PrepareUsage`

acceptance happens before downstream delivery and is the beta billing boundary. A crash after preparation may therefore settle even when response delivery is partial or uncertain. MCPay does not claim exactly-once delivery or exactly-once charging.

The beta rejects metered `2xx text/event-stream`

responses before forwarding upstream success headers or body bytes and creates no usage for them, avoiding indefinite paid SSE buffering. Unmetered MCP traffic can still stream SSE through the gateway.

Spend tokens contain readable claims protected by Ed25519 signatures. They are not encrypted. The API holds the active signing private key; gateways receive a public verification keyring and select keys by the protected JWT `kid`

header.

The beta also uses:

`HttpOnly`

,`SameSite=Strict`

browser cookies;- bcrypt password hashes;
- hashed invite and session tokens in PostgreSQL;
- server-scoped, versioned gateway credentials;
- HTTPS outside explicit local-development mode;
- integer minor units and database transactions;
- redirect blocking, header stripping, and request size/time limits in the gateway.

Database rows are not application-level encrypted. Protect PostgreSQL storage, backups, signing keys, gateway secrets, and deployment environment files with operator-controlled encryption and access controls.

Read [Security Policy](/yiaany/MCPay/blob/main/SECURITY.md) and [Threat Model](/yiaany/MCPay/blob/main/docs/threat-model.md) before exposing a deployment.

Requirements: Docker Engine with Compose v2, Go 1.25+, and 4 GB of available memory.

```
cp deploy/.env.beta.example deploy/.env.beta
go run ./cmd/mcpay-keygen --key-id beta-2026-08
```

Put the generated keys in `deploy/.env.beta`

, replace every `replace-*`

value, and start the stack:

```
docker compose --env-file deploy/.env.beta -f deploy/compose.beta.yml config
docker compose --env-file deploy/.env.beta -f deploy/compose.beta.yml build
docker compose --env-file deploy/.env.beta -f deploy/compose.beta.yml up -d
docker compose --env-file deploy/.env.beta -f deploy/compose.beta.yml ps
```

Open `http://localhost:8080`

. Any top-up is a test credit with no cash value.

Verify the stack:

```
MCPAY_BETA_URL=http://localhost:8080 ./scripts/verify-central-beta.sh
./scripts/verify-central-beta.ps1 -BaseUrl http://localhost:8080
```

See [Central Beta Runbook](/yiaany/MCPay/blob/main/docs/central-beta-runbook.md), [Deployment](/yiaany/MCPay/blob/main/docs/beta-deployment.md), and [Backup/Restore Drill](/yiaany/MCPay/blob/main/docs/backup-restore-drill.md).

Create a server and action in the dashboard, issue a server-scoped gateway credential, and run the gateway beside the MCP server. Use persistent local storage for `--state-file`

and do not share one state file between processes.

```
go run ./cmd/mcpay-gateway \
  --target https://your-mcp-server.example \
  --mcp-path /mcp \
  --server-id srv_example \
  --environment beta \
  --token-issuer mcpay.beta \
  --control-plane-api https://api.example/v1/gateway/servers/srv_example \
  --nonce-claim-api https://api.example/v1/gateway/nonces/claim \
  --usage-api https://api.example/v1/usage-records \
  --usage-api-token "$MCPAY_GATEWAY_API_TOKEN" \
  --state-file ./mcpay-gateway.db
```

Paid requests carry `Authorization: Bearer <spend-token>`

and `X-MCPay-Nonce: <nonce>`

. The gateway removes both headers before forwarding upstream.

The control-plane gateway configuration supplies `verification_keys`

. For a standalone gateway without `--control-plane-api`

, pass `--verification-keys "$MCPAY_VERIFICATION_KEYS"`

.

The JavaScript and Python SDKs are **not published to npm or PyPI as of August 31, 2026**. Install them from this repository only.

```
npm install
npm run build --workspace=@mcpay/sdk-js
```

Workspace code can then import `@mcpay/sdk-js`

. For use from another local Node project, install the repository path after building:

```
npm install ../MCPay/packages/sdk-js
```

Install the Python SDK in editable mode from the repository root:

```
python -m pip install -e ./packages/sdk-python
```

See [JavaScript SDK](/yiaany/MCPay/blob/main/packages/sdk-js/README.md) and [Python SDK](/yiaany/MCPay/blob/main/packages/sdk-python/README.md). Direct SDK wrappers use volatile process state in development; the persistent gateway is the supported beta path for crash recovery.

```
go test ./...
go test -race ./...
go vet ./...
go build ./cmd/...
npm ci
npm run build
npm run test
python -m pip install build
python -m build packages/sdk-python
python -m unittest discover -s packages/sdk-python/tests
```

PostgreSQL tests require a disposable migrated database in `MCPAY_TEST_DATABASE_URL`

. They truncate application tables; never point them at retained data.

| Path | Purpose |
|---|---|
`apps/api` |
HTTP control-plane handlers and authentication |
`apps/dashboard` |
Beta dashboard |
`cmd/mcpay-api` |
API process |
`cmd/mcpay-gateway` |
MCP and HTTP authorization proxy |
`cmd/mcpay-worker` |
Settlement, retry, reconciliation, and expiry loop |
`internal/controlplane` |
PostgreSQL ledger and usage transactions |
`internal/gateway` |
Authorization proxy and persistent gateway state |
`internal/sessions` |
Spend claims and Ed25519 token code |
`packages/sdk-js` |
JavaScript SDK source |
`packages/sdk-python` |
Python SDK source |
`migrations` |
Ordered PostgreSQL schema changes through `000010` |

MCPay uses the Business Source License 1.1. It is source-available but not OSI-approved open source. The Additional Use Grant and change date are defined in [LICENSE](/yiaany/MCPay/blob/main/LICENSE). The dashboard has a separate MIT license and upstream attribution in [apps/dashboard/LICENSE](/yiaany/MCPay/blob/main/apps/dashboard/LICENSE).
