Why I made my Bitcoin gambling site MCP-discoverable
- What the MCP layer actually does
- What “provably fair” means in this context
- The MCP-as-test-drive narrative
- Two demo agents already on the site
- How to actually try it
- Disclaimers
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/callinto 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 withcrypto.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