Exposes the Magic Markets API as MCP tools over stdio or streamable HTTP transport, allowing LLM agents to read prices and manage orders on the Magic Markets betting exchange.
Strong foundation with 19 well-named tools following verb_noun convention. All tools have descriptions (avg 156 chars, within 10-1024 baseline). Input schemas present for 16/19 tools with typed parameters. Key gaps: 3 tools (get_balance, get_exchange_rates, list_events, list_heartbeats) lack input schemas entirely; parameter descriptions are minimal (avg 40 chars vs 72 baseline); output schemas undocumented; error handling guidance absent. Risk annotations (READ_ONLY, WRITE, DESTRUCTIVE) are present and valuable. Composition is clean, each tool has single responsibility. Naming is clear and action-oriented (get_, list_, create_, place_, close_). Missing: pagination guidance for list_* tools, recovery hints in descriptions, and structured error response documentation.
Cancel a heartbeat, stopping it from keeping orders open.
Close all open orders. Cancels any unmatched portions and cashes out any matched portions at the current market price.
Close one order by ID. Cancels any unmatched portion and cashes out any matched portion at the current market price.
Create a betslip: register interest in one selection so it gets quoted. This is step one of two — a betslip costs nothing and commits nothing, but an order needs one. Take bet_type verbatim from list_event_offers. Betslips are short-lived and carry no price at creation, so set wait_seconds to poll for the quote.
Create a heartbeat to keep orders open across a disconnect. A heartbeat is a server-side timer that keeps all orders open for its duration, even if the client disconnects. Heartbeats are useful for long-running agents that may lose connectivity.
Four tools lack input schemas entirely (get_balance, get_exchange_rates, list_events, list_betslips, close_all_orders, list_heartbeats).
Parameter descriptions are minimal (avg 40 chars vs 72 baseline). Examples: 'Sport code' (11 chars), 'Event ID' (8 chars), 'Betslip ID' (10 chars). LLMs cannot infer meaning from bare names, descriptions must explain what values are valid and when to use each parameter.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 71 | 2026-07-28+ | v2 |
Get the account balance, the stake committed to open bets, and smart credit. All amounts are USDT.
Get a betslip and its current price list. Quotes arrive asynchronously after creation, so a fresh betslip is normally unpriced — set wait_seconds to poll until a price lands.
Get exchange rates to USDT. Also the cheapest way to verify the API key works.
Get one order by ID, or by the request_uuid it was created with. Looking up by request_uuid works for six hours after placement and is the safe way to find out whether a timed-out placement actually succeeded.
Get the aggregate profit/loss position over the matching orders, including a payoff grid per scoreline. Narrow it to one event for a readable result. Cashout valuations are offered on football only.
List the IDs of currently open betslips. Betslips are short-lived.
List the priced bet types on one event, with the stake available at each price. Opens the WebSocket, registers the event, reads the offer snapshot and disconnects. Each offer covers one (sport, event_id, bet_type) triple; back and lay on the same selection are separate offers. Pass a returned bet_type verbatim to create_betslip — never construct one by hand. Prices are ordered best first and are already on the tick schedule.
List the events that currently have live prices. The REST API has no event-listing endpoint, so this opens the WebSocket, reads the initial snapshot and disconnects — it takes a few seconds. The snapshot is not the full fixture list: it holds only events the feed is pricing right now. Use the returned sport and event_id with list_event_offers to see bet types and prices.
List all active heartbeats.
List orders, optionally filtered. Amounts are USDT.
Place an order against a betslip. THIS SPENDS REAL MONEY. Requires an existing betslip from create_betslip. The price is snapped onto the tick schedule
Refresh an existing heartbeat to extend its expiry time.
Snap a decimal price onto the API's tick schedule and report the tick size and implied probability. Runs locally with no API call. Off-tick order prices are rounded so they never tighten your limit: down for back ('for') orders, up for lay ('against') orders. Use this to know the price an order will actually run with.
Validate a bet_type string against a sport and get its human-readable description plus win/loss grid. An error means the string did not parse. Prefer copying bet_type values verbatim from list_event_offers rather than constructing them. Grammar: the first token is the direction ('for' to back, 'against' to lay), then the market and its arguments. Examples: 'for,h' home win, 'for,over,2.5' over 2.5 goals, 'for,ah,h,-4' Asian handicap home -1.0 (Asian lines are integers equal to 4x the real line), 'for,cs,2,1' correct score 2-1. Handicaps always refer to the home team.
Output schemas are not documented. Tool descriptions state what is returned (e.g., 'Get the account balance...') but do not specify the response structure, field names, or types. LLMs need explicit output schemas to plan downstream tool calls and extract data correctly.
No error handling guidance. Descriptions do not explain what errors can occur, how to recover, or what the LLM should do next. Example: place_order says 'THIS SPENDS REAL MONEY' but does not document failure modes (insufficient balance, invalid price, timeout) or recovery paths.
List tools (list_orders, list_events, list_event_offers, list_betslips, list_heartbeats) lack pagination parameters and limits. Descriptions do not state result caps or whether pagination is supported. Without pagination guidance, LLMs cannot handle large result sets safely.