@zeam-labs/x402-mcp-bridge
Officialby zeam-labs
README.md
# x402-mcp-bridge
[](https://glama.ai/mcp/connectors/com.zeamprism/prism-mcp)
`@zeam-labs/x402-mcp-bridge` 3.2.2 on npm. Source: https://github.com/zeam-labs/x402-mcp-bridge
A wallet in front of a paid MCP server. It pays per call, or buys time and rides a ZEAM :: Pass line. It works with
ZEAM Prism and with any ZEAM :: Pass seller.
## Run it
`--help` and `--version` print and exit; neither contacts a server.
It needs Node.js 20 or later. Export your key as `X402_PRIVATE_KEY`. It signs locally and is never sent.
npx -y @zeam-labs/x402-mcp-bridge --tools
npx -y @zeam-labs/x402-mcp-bridge --call call_rpc \
'{"chain":"base","method":"eth_blockNumber","params":[]}'
X402_MCP_URL=https://seller.example/agents/mcp \
npx -y @zeam-labs/x402-mcp-bridge --call add '{"a":1,"b":2}'
`--times N` repeats a `--call` in one process. With no arguments the bridge is an MCP stdio server:
```json
{
"mcpServers": {
"prism": {
"command": "npx",
"args": ["-y", "@zeam-labs/x402-mcp-bridge@3.2.2"],
"env": { "X402_PRIVATE_KEY": "0x..." }
}
}
}
```
Without a key it serves `tools/list` and the free tools; a paid call returns the seller's terms.
The seller's instructions reach your client, under a note that the bridge is paying.
Results pass through whole: `content`, `structuredContent`, `isError` and `_meta`.
## Paying per call
1. The bridge reads the terms once from `/.well-known/x402`, or from the seller's first 402.
2. The first paid call deposits into a batch-settlement channel: price × `X402_DEPOSIT_MULTIPLIER` (default 40,
minimum 3), raised to the seller's floor (the 402's `deposit` line, or `neededMicroUSD`). On Prism: 250 µUSD × 40 =
$0.01.
3. Later calls sign vouchers against that deposit. No gas, no round trip to ask the price.
The deposit sits in x402's batch-settlement escrow `0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003`, hardcoded in
`@x402/evm`. No owner, no pause, no upgrade. Only your key can withdraw it.
## Line time
A Pass seller that sells time lists `buy_time` and `line`, and tags its time tools `{"per":"time"}`. Prism:
1 µUSD per ms. A paid call without a line costs $0.00025 and runs at most 250 ms. On a line a call costs the
milliseconds it runs; calls at once burn once.
1. **Buy.** `buy_time {"ms": N}` pays for N milliseconds from the channel. The bridge buys
`X402_LINE_AHEAD_MS` (default 2000 ms), no more than the channel's collateral covers and never less than
250 ms. A seller on an older ZEAM :: Pass that sells time in blocks is asked for blocks.
2. **Open.** `POST <base>/line {"op":"open","channelId"}` returns a message. The bridge signs it (EIP-191) with the
payer key and posts `{"op":"prove","channelId","nonce","signature"}`; the answer carries the credential.
3. **Ride.** Each time-tool call carries the credential in `_meta["zeam-pass/line"]`; no payment per call. The answer's
`_meta["zeam-pass/meter"]` states `msRemaining`.
4. **Meter.** After `X402_LINE_IDLE_MS` (default 1000) with no call the bridge sends `{"op":"off"}`; the next call
sends `{"op":"on"}`. `meter_off` is switched on and called again; `out_of_time` buys twice the time and calls
again; `line_unknown` opens a new line.
5. **Exit.** On exit the bridge sends `off`, then `close`. Unburned time comes back with a refund.
`X402_LINE`:
- `auto` (default): per call until 2 time-tool calls arrive within 10 s
(`X402_AUTO_FAST_RUN`, `X402_AUTO_GAP_MS`), then a line while it holds time.
A call cut for running past what one call buys (`out_of_time`) is called again on a line.
When the seller says how long the call needs (`needsMs`), the bridge buys that much, plus a quarter, before it
calls again.
- `on`: every time-tool call rides a line.
- `off`: per call only.
Tools priced per call never ride a line.
## Refunds
npx -y @zeam-labs/x402-mcp-bridge --refund
1. The bridge posts `{channelId, issued, signature}` to the refund route the seller names (its 402 or
`/.well-known/x402`), else `<base>/refund`. The key signs:
ZEAM Pass refund
channel: <channel id, lowercase>
issued: <ISO time>
2. When the channel's fees cover the gas, the seller sends the balance and the unburned time: `returnedMicroUSD`,
`timeReturnedMs`, `gasMicroUSD: 0`.
3. When they do not, the seller answers 409 `refund_quote` with the exact gas. The bridge signs a gasless USDC payment
of it and posts again; one transaction returns the rest.
4. When the gas is more than what is left: `nothing_to_return` with the numbers.
`--refund --self-send` asks for a signed refund of all of it and sends it from your key, at your gas, if the key holds
ETH on Base. Otherwise it prints the transaction for any wallet to send.
No answer from the seller: `initiateWithdraw`, then `finalizeWithdraw` after the channel's `withdrawDelay`.
## Gates and grants
A Pass gate admits listed keys by a zero-value payment: nothing moves. `X402_GRANT` is sent as the `x-grant` header on
every request, over MCP and HTTP, so a key admitted by grant passes the gate.
## Any x402 URL
`x402_fetch` is offered beside the seller's tools. It calls a URL and pays a 402 under the x402 `exact` scheme.
npx -y @zeam-labs/x402-mcp-bridge --call x402_fetch \
'{"url":"https://api.example.com/v1/quote","body":{"symbol":"ETH"}}'
- `pay: false` returns the terms without paying.
- `maxAmount` (base units) refuses a larger quote before signing.
- USDC counts toward `X402_MAX_SPEND`. Another asset is paid only with `maxAmount`.
- A zero-value gate: signed, admitted, `paid: false`.
## Chain clients
```js
import { createPublicClient } from 'viem'
import { base } from 'viem/chains'
import { prism } from '@zeam-labs/x402-mcp-bridge/viem'
const client = createPublicClient({
chain: base,
transport: prism({ key: process.env.X402_PRIVATE_KEY }),
})
await client.getBlockNumber()
```
The ethers provider needs `ethers` 6 or later installed beside the bridge (`npm install ethers`).
```js
import { PrismProvider } from '@zeam-labs/x402-mcp-bridge/ethers'
const provider = new PrismProvider({ key: process.env.X402_PRIVATE_KEY })
```
1. The first request pays per call at `/rpc/base` (or `/rpc/eth`, `chain: 'eth'`) and funds the channel: 40 × the price,
at least the seller's floor.
2. Then it opens a line, buys up to `aheadMs` (2000) of time from the collateral, and sends `x-line`.
3. The meter goes off after `idleMs` (1000) idle; the line is let go after `dropAfterMs` (10000).
4. `state()`, `close()`, `refund()`. Call `close()` or `refund()` before exit.
Options: `url`, `chain`, `network`, `stateDir`, `depositMultiplier`, `asset`, `salt`, `rpcUrl`, `grant`, `aheadMs`,
`idleMs`, `dropAfterMs`, `log`. The `X402_*` variables are the defaults; the state directory is shared with the bridge.
## Configuration
- `X402_PRIVATE_KEY` (no default): funds the channel and signs.
- `X402_MCP_URL` (default `https://mcp.zeamprism.com/mcp`): any x402 MCP
endpoint.
- `X402_LINE` (default `auto`): `auto`, `on`, `off`.
- `X402_LINE_AHEAD_MS` (default `2000`): time bought per `buy_time`.
- `X402_LINE_IDLE_MS` (default `1000`): meter off after this idle.
- `X402_MAX_SPEND` (default `10000000`, $10): ceiling for this run, µUSD; `0`
removes it.
- `X402_DEPOSIT_MULTIPLIER` (default `40`): deposit = price × this, at least
the seller's floor; minimum 3.
- `X402_GRANT` (no default): `x-grant` on every request.
- `X402_RPC_URL` (default the chain's public RPC): your node for chain reads.
- `X402_STATE_DIR` (default `~/.x402-mcp-bridge/<host>/<address>`): channel
state; keep it.
- `X402_SALT` (default the scheme's): a distinct channel.
- `X402_ASSET` (default first quoted): address or symbol.
- `X402_NETWORK` (default `eip155:8453`): CAIP-2.
USDT, DAI and WETH settle through Permit2: approve `0x000000000022D473030F116dDEE9F6B43aC78BA3` once. USDC needs no
approval.
## Limits
- It exits when stdin closes, and lets its line go.
- It stops at `X402_MAX_SPEND`: further calls return `x402_bridge_spend_cap_reached`.
- On `--refund`, when the seller asks for the refund's gas in USDC, it signs only a payment to the relay's own gas
wallet, for the amount quoted, no more than twice what the relay prices that gas at, less than the refund and
within `X402_MAX_SPEND`. Otherwise it signs nothing and says why; `--self-send` always works. The relay is
ZEAM's (`https://api.zeampass.com/relay`); `X402_RELAY_URL` names another.
- Lost state costs one probe to resync, then one deposit.
## Verify before you run it
The versions are pinned exactly.
npm view @zeam-labs/x402-mcp-bridge@3.2.2 version dist.integrity
npm pack @zeam-labs/x402-mcp-bridge@3.2.2
less package/index.mjs
MIT. Patent pending: ZEAM :: Pass, which this bridge pays through, is the subject of a pending United States patent
application.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSlow