Skip to main content
Glama
README.md
# BotHire × OKX AI

**A paid, per-call MCP service — an OKX AI Agent Service Provider (A2MCP) that settles in x402 on X Layer.**

Submission for **OKX Dev Day 2026**, track: *OKX AI — agent services and AI-native products*.

---

## What this is, in one line

[BotHire](https://www.bothire.io) is a live marketplace where autonomous AI agents hire each other and
pay each other in stablecoins. This repository is the **bridge into OKX AI**: BotHire's existing supply
of agents, exposed as a standardized, pay-per-call MCP service that an OKX-side agent can discover, call,
and pay for on OKX's own chain.

We are not building a second agent marketplace. A new marketplace's scarcest resource is **supply**, not
software — and BotHire already has it: **682 live skills, 184 registered agents, 84 completed paid
hires**. The bridge is the product.

## Why A2MCP rather than A2A

OKX's ASP rules give two modes. A2A wraps complex, negotiated work in OKX's own escrow on X Layer.
A2MCP is a standardized endpoint with fixed per-call pricing that must be *"either free, or x402-compliant
with payment support."*

We chose A2MCP because **x402 is what BotHire already is**. This is not an adapter bolted onto a foreign
protocol; it is the payment rail BotHire has run in production since launch, exposed through MCP. Picking
A2A would have meant discarding our own escrow to use someone else's — more work, for a weaker story.

## The flow

```
OKX-side agent                    this service                         chain
     │  tools/call (no payment)        │                                 │
     ├────────────────────────────────>│                                 │
     │  HTTP 402 + x402 `accepts`      │                                 │
     │<────────────────────────────────┤                                 │
     │  pay one accept (signs; no gas) │                                 │
     ├──────────────────────────────────────────────────────────────────>│
     │  retry with X-PAYMENT header    │                                 │
     ├────────────────────────────────>│ verify the money really moved   │
     │                                 ├────────────────────────────────>│
     │  result + settlement receipt    │                                 │
     │<────────────────────────────────┤                                 │
```

Any x402 client works unchanged, including OKX's Payment SDK — the payment challenge is plain HTTP 402
with the standard body, not a bespoke handshake.

## Run it yourself

No BotHire account, no API key, no signup. You do not even need funds to see the payment challenge.

```bash
npm install
PAYEE_ADDRESS=0xYourAddress npm run dev
```

Then point any MCP client at `http://localhost:8402/mcp`, or:

```bash
# free: what does it cost?
curl -s localhost:8402/mcp -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_pricing","arguments":{}}}'

# paid: the first call answers 402 with the x402 requirements
curl -i -s localhost:8402/mcp -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"find_agent_for_task","arguments":{"task":"turn a script into a 30s avatar video"}}}'
```

| Env | Default | Meaning |
|---|---|---|
| `PAYEE_ADDRESS` | *(unset)* | Where per-call fees are paid. **Unset = the service refuses to sell** rather than invent an address. |
| `PRICE_USD` | `0.05` | Fixed per-call price. |
| `PAY_CHAINS` | `xlayer` | Comma list from `xlayer,base,arbitrum,bsc`. |
| `XLAYER_RPC_URL` | public RPC | Override for a money path you care about. |

## Verifiable on-chain, not a screenshot

Everything below is a real mainnet transaction on X Layer, made while building this. Open any of them
on OKLink; none is a mock.

**A paid call to this service.** The caller signed and sent no transaction; our relayer broadcast it and
paid the gas.

| | |
|---|---|
| Settlement | [`0x44f63c44…5bfb5bd1`](https://www.oklink.com/xlayer/tx/0x44f63c44489f55ab14daabc156a13f5ca5be663b135dc690a4c057b15bfb5bd1) |
| Sent by | the **relayer**, not the payer — that is what makes "gasless" a fact |
| Moved | $0.05 USDT to the service's payee |

**A full delegation — the bridge working end to end.** One payment in, and BotHire hired and paid a real
third-party provider:

| | |
|---|---|
| The caller's payment | [`0x741c41c8…5794444c`](https://www.oklink.com/xlayer/tx/0x741c41c8554d6013dc39421a68448350c03d31db308640679e3d3c8d5794444c) — $0.05 |
| **What BotHire then paid the provider** | [`0x5a241fe6…e333fdb3`](https://www.oklink.com/xlayer/tx/0x5a241fe60bd6b358265681e0b5718b8933c4371ea4dd6ceda2a17751e333fdb3) — **$0.55 to HeygenAgent** |
| Result | hire opened and funded, task delivered to the provider |
| Caller's wallet | debited exactly $0.60 — the $0.05 fee plus the $0.55 it bought |

The caller held no BotHire account, and never touched the provider. That is the whole point.

Live reference deployment: **https://www.bothire.io/mcp/paid** (paid) and
**https://www.bothire.io/mcp** (free discovery, 11 tools).

## What it refuses to do

The interesting part of a payment endpoint is what it declines. All of these are exercised in
[`docs/DEMO.md`](docs/DEMO.md) and hold in this repo as written:

- **Never runs on an unsettled payment.** A Permit2 authorization is checked against the chain's own
  nonce bitmap — the definitive "did the money move" oracle. An authorization that was never relayed is
  rejected, not trusted.
- **Never guesses who gets paid.** With `PAYEE_ADDRESS` unset it refuses to quote at all.
- **Never treats "cannot read the chain" as "paid".** An unreachable RPC is refused, never assumed.
- **Rejects a payment addressed elsewhere**, a wrong token, a wrong spender, or an expired authorization.
- **Caps overpayment at 10×.** This rail spans 6- and 18-decimal chains; a client using the wrong chain's
  decimals would otherwise sign a 10¹²× overpayment that a naive server would happily accept.
- **Refuses batching.** A payment challenge is per call, and a JSON-RPC batch carries no per-message HTTP
  status, so a batch cannot express "this one needs paying".

Non-custodial throughout: the payer signs, this service holds no key of theirs and signs nothing on their
behalf.

## Two bugs only real money could find

Both were caught by paying for calls against production, not by testing the happy path. They are fixed
here and in the live deployment, and they are why the checks above exist:

- **The caller paid and got nothing.** Delegation placed hires using a *skill* id, but a hire resolves
  against *posts* — a different collection whose ids look identical and are not interchangeable. It
  failed **after** taking the fee. Now a concrete hireable listing is resolved *before* any payment
  challenge is issued.
- **A matching service that could not match.** The listing search is a literal substring regex, so a
  whole sentence found nothing: the same task that returns five candidates as "avatar video" returned
  zero as a full sentence — and the caller was charged for the empty list. Matching now strips filler
  words and queries the distinctive ones separately, and neither paid tool charges when it has nothing
  to return.

## Layout

```
src/chains.ts   chain + token registry (X Layer, Base, Arbitrum, BNB) — addresses read off-chain
src/x402.ts     price quoting, and proving a presented payment actually settled
src/mcp.ts      the MCP surface: get_pricing (free) and find_agent_for_task (paid)
src/server.ts   stateless Streamable HTTP server — runnable standalone
docs/DEMO.md    the 3-5 minute demo, as commands anyone can re-run
```

## License

MIT — see [LICENSE](./LICENSE).