@yungbrian25/betbase-mcp
v0.2.0
Published
MCP server for the betBlox prediction market protocol on Base. Bettor + market-maker read/write tools for Claude Code and other MCP-speaking LLM clients.
Readme
betbase-mcp
MCP server for the betBlox prediction market protocol on Base mainnet. Exposes read, simulation, bettor-write, and market-maker tools to Claude Code and any other MCP-speaking LLM client.
Runs locally as a stdio MCP server — your private key never leaves your machine. No hosted service, no custody, no accounts.
Status: v0.2.0 — bettor + market-maker tool surface complete (read, bet, simulate, claim, MM box management, MM market lifecycle, MM settlement). Parlay in v1.2, smart-account session keys for autonomous strategies in v2.
Requirements
- Node 20+
- A Base mainnet wallet with:
- a small amount of ETH for gas
- USDC (
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) to bet or market-make with - For market-making: ≥100 BET (
0x80f6bcedd3d4fa1035285affa30e38f464db3895) — protocol gating requirement, enforced both on-chain and in pre-flight
- A TheGraph gateway API key (free at https://thegraph.com/studio/apikeys/) — required for every subgraph-backed read tool.
- An MCP client (Claude Code, or anything that speaks the MCP protocol)
Setup
Wire into Claude Code (~/.claude.json or project .claude.json). npx fetches the published package on first run — no clone or build required:
{
"mcpServers": {
"betbase": {
"command": "npx",
"args": ["-y", "@yungbrian25/betbase-mcp"],
"env": {
"PRIVATE_KEY": "0x...",
"BETBASE_MCP_DRYRUN": "true",
"BETBASE_MCP_MAX_BET": "5",
"BETBASE_MCP_MM_MAX_PER_OP": "50",
"GRAPH_API_KEY": "..."
}
}
}
}Pin a version by replacing @yungbrian25/betbase-mcp with @yungbrian25/[email protected].
Building from source
For development or contributing:
git clone <this-repo>
cd betbase-mcp
npm install
npm run buildThen point the MCP client at the local build instead of the published package:
{
"command": "node",
"args": ["/path/to/betbase-mcp/dist/server.js"]
}Tools
Bettor reads (9)
| Tool | Purpose |
|---|---|
| get_events | Upcoming/live events from betbase.xyz, optionally filtered by sport. |
| get_event | Single event info (teams, league, kickoff) by eventHash. |
| get_markets_by_event | All markets for an event from the subgraph. |
| get_market | Live market data directly from MarketHandler. |
| get_outcome | Current odds + available liquidity for a single outcome. |
| get_my_bets | Your bets, classified active / unsettled / settled. |
| get_usdc_balance | USDC balance of the configured account. |
| get_usdc_allowance | USDC allowance to a spender (defaults to BetHandler). |
| get_protocol_params | Fees, gating token, presets, event×market validity matrix. |
Simulation (2, always read-only)
| Tool | Purpose |
|---|---|
| simulate_bet | Project payouts across all 6 outcome states without touching chain. |
| project_claim | Compute expected claim payout from on-chain bet + market state. |
Bettor writes (5)
| Tool | Purpose |
|---|---|
| approve_usdc | Approve BetHandler (or a custom spender) to spend USDC. |
| place_bet | Place a bet with slippage protection and payout projection. |
| settle_market | Permissionlessly settle a completed market. |
| claim_bet | Claim payout for a single settled bet. |
| claim_bets | Batch-claim up to 20 settled bets. |
Market-maker reads (4)
| Tool | Purpose |
|---|---|
| get_my_box | MarketmakerBoxLite address (or null), USDC + BET balances, gating status, box pause state. |
| get_my_markets | Markets owned by the EOA, classified active / unsettled / settled. |
| get_market_exposure | Per-outcome MM P&L if each outcome wins, liability, bet volume. |
| validate_market_params | Dry pre-flight for create_market — validity matrix, fee cap, odds bounds, gating. |
Market-maker writes (10)
| Tool | Purpose |
|---|---|
| create_mm_box | Deploy a MarketmakerBoxLite via the factory. Idempotent. |
| deposit_to_box | USDC.approve(box) + box.deposit(amount). |
| withdraw_from_box | box.withdraw(amount) or box.withdrawMax(). |
| create_market | MarketHandler.addMarket(...). Returns marketHash from the MarketAdded log. |
| set_odds | Update odds for one outcome. Atomic — old-odds bets revert. |
| add_liquidity | Top up liquidity on a market the EOA owns. |
| remove_liquidity | Pull liquidity back to the box; capped at min(available). |
| set_vip_group | Per-market gating; group 255 halts betting (kill brake). |
| grant_box_vip / revoke_box_vip | VIP management on the box. |
| claim_mm_payout | Claim MM payout for one or up to 20 settled markets; partial failures reported, not aborted. |
Safety rails
All rails are code-enforced, not prompt-enforced.
Shared:
- Dry-run mode (
BETBASE_MCP_DRYRUN, defaulttrue) — all writes simulate only. - Kill-switch file (
BETBASE_MCP_KILL_FILE, default~/.betbase-mcp/KILL) — create the file to instantly pause all writes (bettor + MM).
Bettor:
- Per-bet USDC cap (
BETBASE_MCP_MAX_BET, default10). - Daily USDC cap (
BETBASE_MCP_DAILY_CAP, default50) — rolling 24h, persisted to~/.betbase-mcp/spend.json. - Bettor market allowlist (
BETBASE_MCP_MARKET_ALLOWLIST, optional). place_betalso runs balance, allowance, and odds-drift (slippageBps, default 1%) pre-flight.
Market-maker:
- Per-op USDC cap (
BETBASE_MCP_MM_MAX_PER_OP, default100) — applies todeposit_to_box,add_liquidity,create_market.liquidity. Withdrawals don't count. - Daily MM cap (
BETBASE_MCP_MM_DAILY_CAP, default500) — separate spend file~/.betbase-mcp/mm-spend.jsonso bettor and MM caps don't interfere. - MM market allowlist (
BETBASE_MCP_MM_MARKET_ALLOWLIST, optional). - Hard preflights (not env-tunable): EOA holds ≥100 BET, EOA owns a MM box, ownership check on every market-write, validity matrix + fee cap on
create_market,remove_liquidity≤ min(available).
Verification playbook
End-to-end test to run after installation on a Base-mainnet wallet with small funds.
Bettor flow:
- Config: set
PRIVATE_KEY, keepBETBASE_MCP_DRYRUN=true, setBETBASE_MCP_MAX_BET=1. - Reads: ask Claude to "list NBA markets and show me the moneyline odds".
- Dry-run write: "place $1 on outcome 1 of market X" — projected payouts across all six outcome states, no on-chain activity.
- Real write: flip
BETBASE_MCP_DRYRUN=false, repeat → tx hash +bet_hash. - Caps check:
$2bet →PER_BET_CAP_EXCEEDED. - Kill-switch: create
~/.betbase-mcp/KILL, retry → rejected. Remove file, works again. - Claim: after the event resolves, "claim my winning bets".
Market-maker flow:
- Top up: ensure the EOA holds ≥100 BET and some USDC.
get_my_box— confirms no box yet, suggestscreate_mm_box.create_mm_box— deploys a MarketmakerBoxLite, returns address.deposit_to_boxwith a small amount (e.g.5) — runs approve + deposit.validate_market_paramsfor an upcoming event — confirms validity matrix passes.create_marketwith the same params + smallliquidity(e.g.5) — returnsmarket_hashfrom theMarketAddedlog.set_oddsto nudge one outcome.set_vip_group(marketHash, 255)— halts betting (per-market kill).remove_liquidity— should be capped bymin(available).withdraw_from_box— moves USDC back to the EOA.- After settlement:
claim_mm_payoutwith the marketHash.
License
MIT.
