{"id":2912,"date":"2026-05-21T10:00:00","date_gmt":"2026-05-21T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=2912"},"modified":"2026-05-03T14:25:04","modified_gmt":"2026-05-03T14:25:04","slug":"odds-api-mcp-server-claude-cursor","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/","title":{"rendered":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &#038; Cline (Python)"},"content":{"rendered":"<p>Your AI assistant can&#8217;t see live odds. Ask Claude or Cursor &#8220;what&#8217;s the best price on Liverpool tonight?&#8221; and you&#8217;ll get a wall of caveats \u2014 it has no live data, no API access, no way to fetch a quote at runtime. The fix is an <strong>MCP server<\/strong>: a tiny Python process that exposes a few tools to any MCP-compatible client (Claude Desktop, Cursor, Cline, Continue) and lets the model call real APIs on your behalf.<\/p>\n<p>This post walks you through a working OddsPapi MCP server in roughly 80 lines of Python. By the end, your agent can list sports, scan upcoming fixtures, and find the best price on a market across 350+ bookmakers \u2014 without you copy-pasting JSON into chat.<\/p>\n<h2>Why an MCP Server Beats Paste-and-Pray<\/h2>\n<p>Before MCP existed, getting live data into Claude or Cursor meant one of three workflows, all bad:<\/p>\n<ol>\n<li><strong>Paste JSON into the chat.<\/strong> Works once. Stale 90 seconds later.<\/li>\n<li><strong>Hand the model your API key and tell it to write requests in code.<\/strong> The code runs in a sandbox that often can&#8217;t reach the internet, or you&#8217;re shipping the key into a tool you don&#8217;t fully control.<\/li>\n<li><strong>Scrape and mirror to a local file.<\/strong> Now you&#8217;re maintaining a sync layer instead of writing your strategy.<\/li>\n<\/ol>\n<p>An MCP server flips this. You run a small process locally, it holds the API key, and the LLM client calls it through the Model Context Protocol \u2014 a stdio JSON-RPC handshake that every major AI dev tool now supports. The model never sees the key. You don&#8217;t paste anything. The data is live every call.<\/p>\n<p>OddsPapi is unusually good as the backend for this:<\/p>\n<ul>\n<li><strong>350+ bookmakers<\/strong> on a single endpoint \u2014 Pinnacle, Bet365, DraftKings, Polymarket, Betfair Exchange, and 357 more. The agent gets sharp and soft prices from one tool call.<\/li>\n<li><strong>Free tier with historical odds.<\/strong> Most odds APIs paywall historical data behind a $300\/month plan. OddsPapi gives you backtest-quality price history on the free tier \u2014 you can build agents that justify their picks against last week&#8217;s data.<\/li>\n<li><strong>Clean JSON, no schema gymnastics.<\/strong> The response shape is consistent across sports. Agents handle it well without prompt engineering.<\/li>\n<li><strong>Query-string auth.<\/strong> No header gymnastics, no OAuth dance. Drop a key in an env var and you&#8217;re live.<\/li>\n<\/ul>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Approach<\/th>\n<th>Latency<\/th>\n<th>Coverage<\/th>\n<th>Setup<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Paste odds into chat<\/td>\n<td>Stale on arrival<\/td>\n<td>Whatever you pasted<\/td>\n<td>30 seconds<\/td>\n<\/tr>\n<tr>\n<td>Browser tool \/ web search<\/td>\n<td>5\u201315s per query<\/td>\n<td>1\u20132 books, blocked often<\/td>\n<td>Built-in<\/td>\n<\/tr>\n<tr>\n<td>Custom function-calling code<\/td>\n<td>~1s<\/td>\n<td>Whatever you wire<\/td>\n<td>Hours, per-tool retry logic<\/td>\n<\/tr>\n<tr>\n<td><strong>OddsPapi MCP server<\/strong><\/td>\n<td><strong>~300ms<\/strong><\/td>\n<td><strong>350+ books, 69 sports<\/strong><\/td>\n<td><strong>~10 minutes<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>Step 1: Install the MCP SDK<\/h2>\n<p>Spin up a clean virtualenv. The MCP Python SDK pulls in pydantic and a tiny stdio runtime \u2014 nothing else.<\/p>\n<pre class=\"wp-block-code\"><code>python3 -m venv .venv\nsource .venv\/bin\/activate\npip install \"mcp[cli]>=1.0\" requests<\/code><\/pre>\n<p>Get a free OddsPapi key from <a href=\"https:\/\/oddspapi.io\/\">oddspapi.io<\/a> if you don&#8217;t have one. Keep it in an env var; never hard-code it.<\/p>\n<pre class=\"wp-block-code\"><code>export ODDSPAPI_API_KEY=\"your-key-here\"<\/code><\/pre>\n<h3>Smoke-test the API<\/h3>\n<p>Before wiring anything up to MCP, confirm the key works. The auth pattern for OddsPapi is a query parameter \u2014 <em>not<\/em> a header \u2014 which trips up devs migrating from other APIs.<\/p>\n<pre class=\"wp-block-code\"><code>import os, requests\n\nAPI_KEY = os.environ[\"ODDSPAPI_API_KEY\"]\nr = requests.get(\n    \"https:\/\/api.oddspapi.io\/v4\/sports\",\n    params={\"apiKey\": API_KEY},\n    timeout=10,\n)\nprint(r.status_code, len(r.json()), \"sports\")\n# 200 69 sports<\/code><\/pre>\n<p>69 sports, 367 bookmakers, every market type from 1X2 to Asian Handicap to player props. Now we wrap it.<\/p>\n<h2>Step 2: The MCP Server (80 Lines)<\/h2>\n<p>FastMCP \u2014 the high-level server class shipped with the SDK \u2014 turns each Python function into an MCP tool with a docstring-derived schema. Save the file as <code>oddspapi_mcp_server.py<\/code>:<\/p>\n<pre class=\"wp-block-code\"><code>\"\"\"OddsPapi MCP Server.\n\nExposes OddsPapi REST endpoints as MCP tools so any MCP client\n(Claude Desktop, Cursor, Cline, Continue) can query live odds.\n\"\"\"\n\nimport os\nfrom datetime import datetime, timedelta, timezone\n\nimport requests\nfrom mcp.server.fastmcp import FastMCP\n\nAPI_KEY = os.environ.get(\"ODDSPAPI_API_KEY\")\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\nif not API_KEY:\n    raise RuntimeError(\"Set ODDSPAPI_API_KEY in your MCP client config.\")\n\nmcp = FastMCP(\"oddspapi\")\n\n\ndef _get(path: str, **params):\n    params[\"apiKey\"] = API_KEY\n    r = requests.get(f\"{BASE_URL}{path}\", params=params, timeout=15)\n    r.raise_for_status()\n    return r.json()\n\n\n@mcp.tool()\ndef list_sports() -&gt; list[dict]:\n    \"\"\"Return every sport OddsPapi covers (id, slug, name).\"\"\"\n    return [\n        {\"sportId\": s[\"sportId\"], \"slug\": s[\"slug\"], \"name\": s[\"sportName\"]}\n        for s in _get(\"\/sports\")\n    ]\n\n\n@mcp.tool()\ndef list_bookmakers(sharps_only: bool = False) -&gt; list[dict]:\n    \"\"\"Return all 350+ bookmakers. Set sharps_only=True for Pinnacle, Singbet, SBOBET.\"\"\"\n    sharp_slugs = {\"pinnacle\", \"singbet\", \"sbobet\"}\n    rows = _get(\"\/bookmakers\")\n    if sharps_only:\n        rows = [b for b in rows if b[\"slug\"] in sharp_slugs]\n    return [{\"slug\": b[\"slug\"], \"name\": b[\"bookmakerName\"]} for b in rows]\n\n\n@mcp.tool()\ndef upcoming_fixtures(sport_id: int, days: int = 2, limit: int = 25) -&gt; list[dict]:\n    \"\"\"List upcoming pre-game fixtures with odds for a sport. Default: next 2 days.\"\"\"\n    today = datetime.now(timezone.utc).strftime(\"%Y-%m-%d\")\n    end = (datetime.now(timezone.utc) + timedelta(days=days)).strftime(\"%Y-%m-%d\")\n    fixtures = _get(\"\/fixtures\", sportId=sport_id, **{\"from\": today, \"to\": end})\n    out = []\n    for f in fixtures:\n        if not f.get(\"hasOdds\") or f.get(\"statusName\") != \"Pre-Game\":\n            continue\n        out.append({\n            \"fixtureId\": f[\"fixtureId\"],\n            \"home\": f.get(\"participant1Name\"),\n            \"away\": f.get(\"participant2Name\"),\n            \"tournament\": f.get(\"tournamentName\"),\n            \"country\": f.get(\"categoryName\"),\n            \"startTime\": f.get(\"startTime\"),\n        })\n        if len(out) &gt;= limit:\n            break\n    return out\n\n\n@mcp.tool()\ndef best_price(fixture_id: str, market_id: int = 101, outcome_id: int = 101) -&gt; dict:\n    \"\"\"Best decimal price across all books for a given outcome. Default: 1X2 home win.\"\"\"\n    data = _get(\"\/odds\", fixtureId=fixture_id)\n    bo = data.get(\"bookmakerOdds\") or {}\n    best_book, best = None, 0.0\n    quotes = []\n    for slug, body in bo.items():\n        outcome = (\n            body.get(\"markets\", {})\n            .get(str(market_id), {})\n            .get(\"outcomes\", {})\n            .get(str(outcome_id), {})\n        )\n        price_obj = outcome.get(\"players\", {}).get(\"0\") or {}\n        if not price_obj.get(\"active\"):\n            continue\n        price = price_obj.get(\"price\")\n        if price and price &gt; best:\n            best, best_book = price, slug\n        if price:\n            quotes.append({\"book\": slug, \"price\": price})\n    quotes.sort(key=lambda x: x[\"price\"], reverse=True)\n    return {\n        \"fixtureId\": fixture_id,\n        \"marketId\": market_id,\n        \"outcomeId\": outcome_id,\n        \"bookCount\": len(quotes),\n        \"best\": {\"book\": best_book, \"price\": best},\n        \"topFive\": quotes[:5],\n    }\n\n\nif __name__ == \"__main__\":\n    mcp.run(transport=\"stdio\")<\/code><\/pre>\n<p>That&#8217;s the entire server. Four tools, ~80 lines, works against the live API. A few notes on what&#8217;s happening:<\/p>\n<ul>\n<li><strong>The <code>active<\/code> guard in <code>best_price<\/code> is mandatory.<\/strong> OddsPapi ships outcomes that are listed but suspended (mid-game stoppage, low limits, market closed). Iterating naively will return ghost prices that don&#8217;t trade. Always filter on <code>players[\"0\"][\"active\"] == True<\/code>.<\/li>\n<li><strong>Hardcoded market 101 = Full Time 1X2.<\/strong> Outcome 101 = Home, 102 = Draw, 103 = Away. For Asian Handicap, totals, BTTS, or player props, query <code>\/v4\/markets?sportId=10<\/code> and let the agent build its own lookup. We unpack a richer market catalog in the FAQ below.<\/li>\n<li><strong>The <code>_get<\/code> helper centralises auth.<\/strong> If you spin up a Pro plan and switch to WebSocket, only this function changes.<\/li>\n<\/ul>\n<h3>Run it once standalone to make sure it boots<\/h3>\n<pre class=\"wp-block-code\"><code>python oddspapi_mcp_server.py\n# (no output \u2014 it's now reading JSON-RPC on stdin)\n# Ctrl-C to exit.<\/code><\/pre>\n<p>If it raises <code>RuntimeError: Set ODDSPAPI_API_KEY<\/code>, the env var didn&#8217;t propagate. On Windows PowerShell use <code>$env:ODDSPAPI_API_KEY = \"...\"<\/code>; on macOS\/Linux it&#8217;s <code>export<\/code>.<\/p>\n<h2>Step 3: Wire It Into Claude Desktop<\/h2>\n<p>Claude Desktop reads MCP servers from <code>claude_desktop_config.json<\/code>. Locations:<\/p>\n<ul>\n<li><strong>macOS:<\/strong> <code>~\/Library\/Application Support\/Claude\/claude_desktop_config.json<\/code><\/li>\n<li><strong>Windows:<\/strong> <code>%APPDATA%\\Claude\\claude_desktop_config.json<\/code><\/li>\n<\/ul>\n<p>Add the OddsPapi entry inside <code>mcpServers<\/code>:<\/p>\n<pre class=\"wp-block-code\"><code>{\n  \"mcpServers\": {\n    \"oddspapi\": {\n      \"command\": \"\/absolute\/path\/to\/.venv\/bin\/python\",\n      \"args\": [\"\/absolute\/path\/to\/oddspapi_mcp_server.py\"],\n      \"env\": {\n        \"ODDSPAPI_API_KEY\": \"your-key-here\"\n      }\n    }\n  }\n}<\/code><\/pre>\n<p>Use <strong>absolute paths<\/strong> for both <code>command<\/code> and the script \u2014 Claude Desktop doesn&#8217;t inherit your shell PATH. Restart the app. You should see &#8220;oddspapi&#8221; listed in the MCP tools indicator at the bottom of the chat input. If it doesn&#8217;t appear, check Claude Desktop&#8217;s MCP log: <code>~\/Library\/Logs\/Claude\/mcp-server-oddspapi.log<\/code> on macOS.<\/p>\n<h3>Cursor &amp; Cline<\/h3>\n<p>Cursor uses the same JSON shape under <code>~\/.cursor\/mcp.json<\/code>. Cline (VS Code extension) configures via the extension UI but stores the same config in <code>~\/.config\/cline\/cline_mcp_settings.json<\/code>. The OddsPapi entry above works unchanged in all three \u2014 that&#8217;s the whole point of MCP.<\/p>\n<h2>Step 4: Talk to Your Agent<\/h2>\n<p>Open Claude Desktop and ask something the model couldn&#8217;t possibly answer from training data:<\/p>\n<blockquote>\n<p>&#8220;Use the oddspapi tools to find the best price on Liverpool to beat Manchester United today. Show me the top five books.&#8221;<\/p>\n<\/blockquote>\n<p>Claude calls <code>upcoming_fixtures(sport_id=10, days=1)<\/code>, finds the fixture, calls <code>best_price(fixture_id=\"id1000001761301215\", market_id=101, outcome_id=103)<\/code>, and returns:<\/p>\n<pre class=\"wp-block-code\"><code>{\n  \"fixtureId\": \"id1000001761301215\",\n  \"marketId\": 101,\n  \"outcomeId\": 103,\n  \"bookCount\": 106,\n  \"best\": { \"book\": \"hardrockbet\", \"price\": 3.0 },\n  \"topFive\": [\n    { \"book\": \"hardrockbet\", \"price\": 3.0   },\n    { \"book\": \"kalshi\",      \"price\": 2.941 },\n    { \"book\": \"polymarket\",  \"price\": 2.941 },\n    { \"book\": \"betfair-ex\",  \"price\": 2.94  },\n    { \"book\": \"1xbet\",       \"price\": 2.904 }\n  ]\n}<\/code><\/pre>\n<p>That&#8217;s a real call against 106 active US-and-global books captured at kickoff: Hard Rock at 3.00 is +2.0% over the Pinnacle line of 2.85, with Kalshi and Polymarket effectively tied for second on the prediction-market side. If you saw that in a value-betting scanner you&#8217;d act on it \u2014 but instead of writing the scanner, you just asked.<\/p>\n<h2>Step 5: Stack More Tools (When You Outgrow the Basics)<\/h2>\n<p>The server above gets you running, but four tools is just the floor. The pattern scales \u2014 every additional <code>@mcp.tool()<\/code> is one more capability your agent gets without touching client code. Stuff that&#8217;s worth wiring next:<\/p>\n<ul>\n<li><strong>Historical odds<\/strong> \u2014 wrap <code>\/v4\/historical-odds<\/code> with a <code>fixture_id, bookmakers<\/code> signature (max 3 books per call). Now your agent can backtest a closing-line claim against last week&#8217;s prices. We dig into this in our <a href=\"https:\/\/oddspapi.io\/blog\/historical-odds-csv-excel-backtesting\/\">historical odds guide<\/a>.<\/li>\n<li><strong>Market catalog<\/strong> \u2014 wrap <code>\/v4\/markets?sportId=X<\/code> so the agent can discover Asian Handicap, BTTS, totals, or player-prop market IDs at runtime instead of hardcoding them. Soccer alone has 32,814 market-handicap-period combinations.<\/li>\n<li><strong>Arbitrage scan<\/strong> \u2014 copy the cross-book sum logic from our <a href=\"https:\/\/oddspapi.io\/blog\/arbitrage-betting-bot-python\/\">arb bot tutorial<\/a>, drop it behind <code>@mcp.tool()<\/code>, and your agent can answer &#8220;any 2%+ arbs in the EPL today?&#8221; with a single tool call.<\/li>\n<li><strong>Steam-move detection<\/strong> \u2014 surface <code>changedAt<\/code> timestamps from the odds payload to flag Pinnacle line moves in real time. Same pattern as our <a href=\"https:\/\/oddspapi.io\/blog\/steam-move-detector-python\/\">steam detector<\/a> but exposed as an agent tool.<\/li>\n<\/ul>\n<p>Be deliberate about token cost. <code>list_bookmakers()<\/code> without a filter returns 367 rows \u2014 every call burns ~3,000 tokens of context. Add a <code>search<\/code> parameter or paginate before you wire it into a hot path.<\/p>\n<h2>Common Pitfalls<\/h2>\n<ul>\n<li><strong>Server shows up in the client but tools fail silently.<\/strong> 90% of the time this is the env var. <code>os.environ.get(\"ODDSPAPI_API_KEY\")<\/code> returns <code>None<\/code> because the MCP client didn&#8217;t pass it through. Pass it explicitly via the <code>env<\/code> block in the config (shown above) \u2014 don&#8217;t rely on inheritance.<\/li>\n<li><strong>Tools listed but Claude refuses to call them.<\/strong> Tool descriptions matter. The docstring is the model&#8217;s only signal about <em>when<\/em> to use the tool. &#8220;List sports&#8221; is fine; &#8220;List sports OddsPapi covers including soccer (10), basketball (11), tennis (13)&#8221; gives the agent enough context to pick correctly without an explicit sportId from the user.<\/li>\n<li><strong>Claude calls the tool but the JSON is huge.<\/strong> MCP responses get encoded into context. <code>list_bookmakers<\/code> = 367 rows \u2248 3,000 tokens. Use <code>sharps_only<\/code> or add a <code>limit<\/code> param. Same applies to fixtures \u2014 never return more than 25 unless asked.<\/li>\n<li><strong>Polymarket prices look wrong.<\/strong> They&#8217;re not. OddsPapi converts Polymarket&#8217;s native 0\u20131 share price to decimal odds for you, and ships the lay side under <code>exchangeMeta<\/code>. If you want order-book depth, that&#8217;s where it lives.<\/li>\n<\/ul>\n<h2>What This Unlocks<\/h2>\n<p>Once your agent has a tool layer for live odds, the workflow shifts. You stop writing one-off scripts to answer questions like &#8220;is the Liverpool line moving?&#8221; and start asking the agent. Things that work surprisingly well as natural-language queries:<\/p>\n<ul>\n<li>&#8220;Pull tonight&#8217;s MLS card and flag any games where DraftKings is more than 3% off Pinnacle.&#8221;<\/li>\n<li>&#8220;Compare the closing line on tomorrow&#8217;s Lakers game across Bovada, BetMGM, and Pinnacle. Which is sharpest?&#8221;<\/li>\n<li>&#8220;List all Champions League fixtures this week with O\/U 2.5 priced under 2.0 anywhere.&#8221;<\/li>\n<li>&#8220;Build a Python script that scans 100 fixtures for arbitrages, using my arb-detection logic.&#8221;<\/li>\n<\/ul>\n<p>The last one is the meta-move: the agent can call your odds tool <em>while writing the script that uses your odds API<\/em>. It tests its own output against live data before handing you code. That&#8217;s the unlock.<\/p>\n<h2>FAQ<\/h2>\n<h3>Do I need a paid OddsPapi plan?<\/h3>\n<p>No. The free tier covers everything in this tutorial \u2014 350+ bookmakers, 69 sports, free historical odds. Upgrade only if you need WebSockets (real-time push) or higher request quotas.<\/p>\n<h3>Does this work with Cursor and Cline, or just Claude Desktop?<\/h3>\n<p>Any MCP-compatible client works. The same JSON config block (with paths adjusted) drops into Cursor&#8217;s <code>~\/.cursor\/mcp.json<\/code>, Cline&#8217;s settings file, and Continue&#8217;s config. The protocol is identical across clients.<\/p>\n<h3>Is my API key exposed to the model?<\/h3>\n<p>No. The key lives in the MCP server process as an environment variable. The client (Claude\/Cursor) only sends tool calls \u2014 function name and arguments \u2014 over the stdio JSON-RPC channel. The model never sees the key.<\/p>\n<h3>What&#8217;s the latency like?<\/h3>\n<p>OddsPapi&#8217;s REST endpoints respond in 200\u2013400ms typically. Add ~50ms for MCP serialisation. End-to-end, expect ~300ms per tool call from the model&#8217;s perspective. For sub-second push updates you need the WebSocket endpoint (paid plan).<\/p>\n<h3>Can I add more tools later?<\/h3>\n<p>Yes \u2014 every additional <code>@mcp.tool()<\/code> decorator adds a new capability. Restart the client to pick up changes. There&#8217;s no per-tool fee or registration; the SDK reflects the function signature and docstring into a schema automatically.<\/p>\n<h3>Why is my server appearing in the client but tools error out?<\/h3>\n<p>Almost always the API key isn&#8217;t being passed through. Add an explicit <code>\"env\": {\"ODDSPAPI_API_KEY\": \"...\"}<\/code> block in your MCP client config \u2014 don&#8217;t rely on shell-level inheritance, MCP clients spawn the server with a clean environment.<\/p>\n<h2>Stop Pasting JSON Into Chat<\/h2>\n<p>Once your agent can call live odds, you&#8217;ll wonder how you ever shipped without it. <a href=\"https:\/\/oddspapi.io\/\">Get a free OddsPapi API key<\/a>, drop in the 80 lines above, and your next &#8220;what&#8217;s the best price on\u2026&#8221; question gets a real answer instead of a &#8220;I can&#8217;t access live data&#8221; stall.<\/p>\n<p>If you&#8217;re building further: our <a href=\"https:\/\/oddspapi.io\/blog\/free-odds-api-350-bookmakers\/\">free odds API guide<\/a> covers the underlying endpoints in depth, the <a href=\"https:\/\/oddspapi.io\/blog\/live-betting-api-real-time-in-play-odds\/\">live betting API<\/a> post explains how to scope in-play queries, and <a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">line shopping in Python<\/a> shows the cross-book scanning logic that <code>best_price<\/code> is the simplest version of.<\/p>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Do I need a paid OddsPapi plan to build an MCP server?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"No. The free tier covers 350+ bookmakers, 69 sports, and free historical odds \u2014 everything you need for an MCP server. Upgrade only if you need WebSockets or higher request quotas.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Does the OddsPapi MCP server work with Cursor and Cline?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes. Any MCP-compatible client works. The same JSON config block drops into Cursor's mcp.json, Cline's settings, Claude Desktop, and Continue. The protocol is identical across clients.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is my API key exposed to Claude or Cursor?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"No. The API key lives in the MCP server process as an environment variable. The model only sees tool calls \u2014 function name and arguments \u2014 over the stdio JSON-RPC channel. The key never enters the chat context.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"What's the latency of an MCP tool call?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"OddsPapi REST endpoints respond in 200-400ms. Add ~50ms for MCP serialisation. Expect roughly 300ms per tool call end-to-end. For sub-second push updates use the WebSocket endpoint on the Pro plan.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why does my MCP server appear in the client but tool calls fail?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Almost always the API key isn't being passed through. MCP clients spawn the server with a clean environment, so add an explicit env block in your MCP client config: '\\\"env\\\": {\\\"ODDSPAPI_API_KEY\\\": \\\"...\\\"}'.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: odds api mcp server\nSEO Title: Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor & Cline (Python)\nMeta Description: Wire OddsPapi into Claude Desktop, Cursor, or Cline so AI agents can query live odds from 350+ bookmakers. 80-line Python tutorial. Free tier.\nSlug: odds-api-mcp-server-claude-cursor\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wire OddsPapi into Claude Desktop, Cursor, or Cline so AI agents can query live odds from 350+ bookmakers. 80-line Python tutorial. Free tier.<\/p>\n","protected":false},"author":2,"featured_media":2913,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[64,8,63,9,11],"class_list":["post-2912","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-ai-agents","tag-free-api","tag-mcp","tag-odds-api","tag-python"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &amp; Cline (Python) | OddsPapi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &amp; Cline (Python) | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"Wire OddsPapi into Claude Desktop, Cursor, or Cline so AI agents can query live odds from 350+ bookmakers. 80-line Python tutorial. Free tier.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-21T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1429\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Odds API Writer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/oddspapi.io\/logo-v2.webp\" \/>\n<meta name=\"twitter:creator\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:site\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Odds API Writer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &#038; Cline (Python)\",\"datePublished\":\"2026-05-21T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\"},\"wordCount\":1750,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp\",\"keywords\":[\"AI Agents\",\"Free API\",\"MCP\",\"Odds API\",\"Python\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\",\"name\":\"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor & Cline (Python) | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp\",\"datePublished\":\"2026-05-21T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"Build an MCP Server - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &#038; Cline (Python)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"name\":\"OddsPapi\",\"description\":\"Sports Odds API Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"alternateName\":\"Odds Papi\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/oddspapi.io\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\",\"name\":\"OddsPapi\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"width\":135,\"height\":135,\"caption\":\"OddsPapi\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/oddspapiapi\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\",\"name\":\"Odds API Writer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"caption\":\"Odds API Writer\"},\"url\":\"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor & Cline (Python) | OddsPapi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/","og_locale":"en_US","og_type":"article","og_title":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor & Cline (Python) | OddsPapi Blog","og_description":"Wire OddsPapi into Claude Desktop, Cursor, or Cline so AI agents can query live odds from 350+ bookmakers. 80-line Python tutorial. Free tier.","og_url":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-05-21T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp","type":"image\/webp"}],"author":"Odds API Writer","twitter_card":"summary_large_image","twitter_image":"https:\/\/oddspapi.io\/logo-v2.webp","twitter_creator":"@oddspapiapi","twitter_site":"@oddspapiapi","twitter_misc":{"Written by":"Odds API Writer","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &#038; Cline (Python)","datePublished":"2026-05-21T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/"},"wordCount":1750,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp","keywords":["AI Agents","Free API","MCP","Odds API","Python"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/","url":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/","name":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor & Cline (Python) | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp","datePublished":"2026-05-21T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/05\/odds-api-mcp-server-claude-cursor-scaled.webp","width":2560,"height":1429,"caption":"Build an MCP Server - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/odds-api-mcp-server-claude-cursor\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"Build an OddsPapi MCP Server: Plug 350+ Bookmakers Into Claude, Cursor &#038; Cline (Python)"}]},{"@type":"WebSite","@id":"https:\/\/oddspapi.io\/blog\/#website","url":"https:\/\/oddspapi.io\/blog\/","name":"OddsPapi","description":"Sports Odds API Tutorials &amp; Guides","publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"alternateName":"Odds Papi","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/oddspapi.io\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/oddspapi.io\/blog\/#organization","name":"OddsPapi","url":"https:\/\/oddspapi.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","width":135,"height":135,"caption":"OddsPapi"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/oddspapiapi"]},{"@type":"Person","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13","name":"Odds API Writer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","caption":"Odds API Writer"},"url":"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/"}]}},"_links":{"self":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2912","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/comments?post=2912"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2912\/revisions"}],"predecessor-version":[{"id":2914,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/2912\/revisions\/2914"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/2913"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=2912"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=2912"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=2912"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}