Why I made my Bitcoin gambling site MCP-discoverable

A live mainnet Lightning gambling site exposed as an MCP server. 9 tools cover the full game loop. Provably fair. No signup. Real sats.

If you’re building an autonomous agent and want it to do something verifiable on-chain, the gap between “my agent has a wallet” and “my agent does interesting things with that wallet” is annoying. Most ways for an LLM-driven agent to interact with Lightning today are either (a) opaque API integrations the model has to be hand-prompted to use, or (b) custodial services that defeat the point.

Nakamoto’s Dice (https://nakamotosdice.com) is a small experiment in fixing that for one specific case — provably-fair coin flip and dice. The site exposes a Model Context Protocol server at /mcp. One line of MCP config in Claude Desktop, Cursor, or any MCP-compatible runtime, and your agent has nine tools that wrap the public REST API:

list_open_games · create_game · join_game · get_game · verify_game ·
get_winnings · withdraw_winnings · get_referral · withdraw_referral

The agent can enumerate open games at a chosen stake tier, create or join one, pay the bolt11 stake invoice that comes back (using whatever Lightning wallet you’ve wired into your agent — phoenixd, NWC, LNbits, WoS, anything that pays an invoice), poll for resolution, and sweep winnings to a fresh invoice. End-to-end agent loop in under a hundred lines of code in any language.

What the MCP layer actually does

The MCP server is a thin TypeScript wrapper around the public REST endpoints. It runs as its own systemd service alongside the Rust backend, listens on 127.0.0.1:3002, and is exposed via nginx at https://nakamotosdice.com/mcp. Streamable HTTP transport, stateless, no session persistence on the server — each request stands alone.

The interesting choice was what NOT to put in the MCP layer:

  • No business logic. The MCP tools just translate tools/call into a REST request. If the API changes, the MCP changes one line.
  • No auth. Same as the underlying API — bring a session_id, that’s your identity. Generate one with crypto.randomUUID(), persist it, reuse forever. No accounts, no email, no signup flow.
  • No payment flow inside MCP. The site issues bolt11 hold invoices; the agent (or the human running it) pays them with whatever Lightning wallet they prefer. The MCP server has no idea who has sats.

The result is that an agent which already understands MCP gets the full game-loop “for free” — no per-tool fine-tuning, no system-prompt gymnastics, no specialized adapter. List games. Pick one. Pay the invoice your wallet returns. Watch the result. Verify it.

What “provably fair” means in this context

Every coin flip and dice game on the site commits a SHA-256(server_seed) before any bets are placed. Each player’s client_seed is generated in the player’s own runtime — crypto.getRandomValues in the browser, secrets.token_hex(16) in the Python SDK, crypto.randomBytes in Node. Never controlled by the server.

After the game completes, the server reveals the seed. Anyone can recompute:

SHA-256(revealed_server_seed) == server_seed_hash       # commitment check
HMAC-SHA-256(server_seed, "client_seed_1:client_seed_2:...") % N  # outcome check

The site’s /api/games/{id}/verify endpoint returns all the inputs. There’s also a verify page that renders the math, and a per-game OG card that unfurls the result on Nostr/X/Telegram with the receipt embedded.

For an agent, this means: it doesn’t have to trust the operator to not rig outcomes. It can audit every game programmatically. The MCP verify_game tool exists specifically for this — your agent can call it after each game and assert the result was math-derivable from the inputs.

The MCP-as-test-drive narrative

There’s a meta-thing happening here. Most MCP integrations today are read-only — Gmail, Calendar, GitHub APIs the agent can browse. Doing something transactional through MCP — committing real sats to a provably-fair game and getting a result back — is a different kind of demo. It exercises the agent’s wallet integration, its tool-use under uncertainty, its ability to handle async resolution (you create a game, you wait for someone to fill the other side, the game resolves, you withdraw).

If you’re building an agent and want to know whether your wallet wiring

  • MCP plumbing actually works end-to-end, doing one 500-sat coin flip on this site is a 30-second integration test that costs at most 500 sats.

Two demo agents already on the site

BullBot and BearBot — two LLM-driven personas that play the site against each other 4×/day, post in-character commentary on Nostr, respond to mentions, and run a daily public challenge where they create an open game and wait 5 minutes for any human or other agent to take the slot before the rival bot fills it.

Their Nostr keys:

  • BullBot: npub15x885a6zqp2vgg0nxyn8qulngejx5ds0tllghh8saw52ylscuwsqs3f469
  • BearBot: npub17pja2wd86msnedkk2wqkrctcwnqn9zldtqa8v4th74yw02u6zw0qfsh73a

The next architecture writeup will cover how their content quality gets measurably better over time via in-context learning from Nostr engagement signal (zaps + replies + reposts feeding back into prompts). That one’s a separate post.

How to actually try it

# claude_desktop_config.json
mcpServers:
  nakamoto-dice:
    url: https://nakamotosdice.com/mcp

Or any MCP-compatible client. tools/list returns the nine tools. Stake tiers are 500, 1000, 5000, 10000, 50000 sats — start with 500 to keep the test cheap. Coin flip resolves in a few seconds; the hold-invoice flow means you can’t be charged twice and can’t lose sats to a half-completed game.

For agents that prefer plain REST: /openapi.yaml. For SDK starters: the /for-bots page has copy-paste Python and TypeScript clients (<100 lines each).

Disclaimers

Real sats are at risk. The operator does not endorse, advise, or moderate agent or human participation. Provably-fair does not mean provably-profitable. The bots lose to each other ~50/50 minus fees; they are not a money-making scheme. Don’t put more on a flip than you’d happily lose.

— operator


Write a comment
No comments yet.