Live Tennis API # livetennisapi-mcp **MCP server for the [Live Tennis API](https://livetennisapi.com).** Give Claude, Cursor, Zed or any MCP client live tennis scores, players and fixtures — for ATP, WTA, Challenger, ITF and juniors. Odds, rankings, match statistics, charting and model win-probability tools are included, and require the PRO and ULTRA plans. [![CI](https://github.com/livetennisapi/livetennisapi-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/livetennisapi/livetennisapi-mcp/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/livetennisapi-mcp.svg)](https://www.npmjs.com/package/livetennisapi-mcp) [![license](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) [**Documentation**](https://docs.livetennisapi.com) · [**Get a free API key**](https://livetennisapi.com/subscribe/free)
--- ## Setup **Claude Code** ```bash claude mcp add livetennis -e LIVETENNISAPI_KEY=twjp_… -- npx -y livetennisapi-mcp ``` **Claude Desktop** — add to `claude_desktop_config.json`: ```json { "mcpServers": { "livetennis": { "command": "npx", "args": ["-y", "livetennisapi-mcp"], "env": { "LIVETENNISAPI_KEY": "twjp_…" } } } } ``` **Cursor / Zed / others** — same command, same env var. No install step; `npx` fetches it on demand. Get a **free** key (no card) at [livetennisapi.com](https://livetennisapi.com/subscribe/free), or a paid plan at [pricing](https://livetennisapi.com/#pricing). ## Try it > *"What tennis matches are live right now?"* > *"Who's winning the Alcaraz match, and what does the model give him?"* > *"Show me Sinner's ranking and recent results."* > *"What are the current odds on match 18953?"* > *"What's the all-time head-to-head between Borg and McEnroe?"* > *"List Navratilova's Grand Slam finals from the archive."* > *"Who was ATP #1 the week Alcaraz first entered the top 10?"* > *"How is Sabalenka serving in her live match — aces, hold rate, break points?"* ## Tools | Tool | Does | Plan | |---|---|:--:| | `get_live_matches` | Matches in progress, with live scores | FREE | | `get_upcoming_matches` | Matches starting soon | FREE | | `get_match` | Full detail for one match | FREE | | `get_match_score` | Current score only — the smallest payload | FREE | | `search_players` | Find players by name | FREE | | `get_player` | Profile, ranking, country, handedness | FREE | | `get_fixtures` | Forward schedule | FREE | | `search_tournaments` | Tournament catalogue — surface, location, category | FREE | | `get_tournament` | One tournament by its stable id | FREE | | `get_recent_results` | Completed matches and winners | BASIC | | `search_archive_matches` | Results archive (1968–2022) — historical results with ranks and seeds at the time | BASIC | | `get_archive_match` | One archive result, with serve stats where the era recorded them | BASIC | | `search_archive_players` | Archive bios — hand, DOB, career-high rank | BASIC | | `get_archive_career` | Career W-L, titles and serve aggregates over the archive | BASIC | | `get_h2h` | Cross-era head-to-head — archive + current, one record | BASIC | | `get_match_events` | Breaks, games, sets, momentum runs | PRO | | `get_match_odds` | Match-winner prices — bid / ask / mid | PRO | | `get_rankings` | Full published ranking table per system (ATP, WTA, ITF circuits), any week | PRO | | `player_stats` | One player's W/L by surface, level and season, set-based record, recent matches; serve/return sums on ULTRA | PRO | | `get_player_rankings` | Point-in-time ranking records for specific players, as of any date | ULTRA | | `get_match_statistics` | In-play statistics — aces, serve split, hold/break %, break points | ULTRA | | `get_charting_player` | Career shot-level profile from the Match Charting Project | ULTRA | | `get_charting_match` | One charted match, every stat family, per-set split | ULTRA | | `get_match_analysis` | Model thesis, win probability, key factors | ULTRA | | `check_api_status` | Reachability + which plan your key is on | — | The six BASIC history tools are also unlocked by any History plan, which works on top of a free key. The **results archive (1968–2022)** — ATP and WTA, main draws, qualifying and the ITF/futures tiers — ends exactly where our own results begin (2023), so `search_archive_matches` answers "Borg's Wimbledon finals" and `get_recent_results` answers "yesterday's scores"; `get_h2h` spans both in one call. ## Tier awareness The API gates endpoints by plan and returns a bare `403 {"error":"upgrade_required"}`. Handed that, a model will usually invent a reason or retry pointlessly. So every tool that can hit a tier wall returns a plain-English explanation — **as a normal result, not an error** — naming the tier required and where to upgrade. The assistant can then tell you something true and actionable: > This data requires the ULTRA plan, and the configured API key is on a lower > tier. Nothing is wrong with the key — the endpoint is simply not included in > the current plan. Upgrade in place at https://livetennisapi.com/subscribe/upgrade `check_api_status` probes upward to report which plan your key is actually on, so you can diagnose that without guessing. ## Plans | | FREE | BASIC | PRO | ULTRA | |---|:--:|:--:|:--:|:--:| | Matches, scores, players, fixtures, tournaments | ✅ | ✅ | ✅ | ✅ | | Completed-match listings (results)¹ | — | ✅ | ✅ | ✅ | | Results archive (1968–2022) + head-to-head¹ | — | ✅ | ✅ | ✅ | | Match events, odds + rankings listing | — | — | ✅ | ✅ | | Model analysis, as-of rankings, match statistics + charting | — | — | — | ✅ | | | $0 — no card | $9.99/mo | $29.99/mo | $99.99/mo | ¹ Also unlocked by any History plan, which works on top of a free key. ### Request quotas | | FREE | BASIC | PRO | ULTRA | |---|:--:|:--:|:--:|:--:| | Requests per minute | 30 | 60 | 300 | 600 | | Requests per day | 100 | 1,000 | 10,000 | 500,000 | FREE is 100 requests/day, so poll no faster than every 15 minutes on a free key; for an always-on dashboard, BASIC is the plan to recommend. Every response carries `X-RateLimit-Limit` / `-Remaining` / `-Reset` headers, and the tools relay the three distinct 429 shapes honestly — per-minute (retry shortly), daily cap (the error names the exact reset instant), and the abuse block (don't retry; fix the loop). ## Hosted endpoint Most people should use the stdio server above — your key never leaves your machine. For clients that can only speak HTTP, there is also a hosted Streamable-HTTP endpoint: ``` https://mcp.livetennisapi.com/mcp ``` Send your key as `Authorization: Bearer twjp_…`, `X-API-Key: twjp_…`, or `?token=` if your client cannot set headers. Tools are listable without a key, so directories can introspect the server; calling one needs a key. It is multi-tenant and holds **no key of its own**: every request builds its own server bound to the key that request presented, and there is deliberately no fallback to the host's environment. The endpoint applies its own transport-level limit per caller — 60 req/min anonymous, 300 keyed. That limit only protects this host process; it is **not** your API quota, which is enforced upstream per key and tier (see the quota table above). Self-hosting it: `deploy/install-http.sh` and `deploy/TUNNEL.md`. ## Use with Claude **As a connector.** In Claude, add a custom connector and paste the endpoint with your key as a query parameter — no OAuth, nothing to install: ``` https://mcp.livetennisapi.com/mcp?token=twjp_… ``` `?token=` exists for clients that cannot set request headers. The tradeoff, stated plainly: a key in a URL is not written to our logs, but it *is* visible to the CDN in front of the endpoint and is stored in the connector's configuration. Prefer `Authorization: Bearer twjp_…` wherever your client lets you set a header. **From the Messages API.** Claude can call the endpoint directly. Both halves are required — the server *and* a matching toolset entry; sending `mcp_servers` alone is rejected as a validation error: ```python client.beta.messages.create( model="claude-opus-4-8", max_tokens=4096, betas=["mcp-client-2025-11-20"], mcp_servers=[{ "type": "url", "name": "livetennisapi", "url": "https://mcp.livetennisapi.com/mcp", "authorization_token": os.environ["LIVETENNISAPI_KEY"], }], tools=[{"type": "mcp_toolset", "mcp_server_name": "livetennisapi"}], messages=[{"role": "user", "content": "What tennis is live right now?"}], ) ``` The `authorization_token` is sent as a bearer token, which is exactly what this server already accepts — no separate credential to obtain. ## Use with Codex One command: ```bash codex mcp add livetennisapi \ --url https://mcp.livetennisapi.com/mcp \ --bearer-token-env-var LIVETENNISAPI_KEY ``` Or write it to `~/.codex/config.toml` yourself — Codex shares that file across the CLI, the IDE extension and the desktop app: ```toml [mcp_servers.livetennisapi] url = "https://mcp.livetennisapi.com/mcp" bearer_token_env_var = "LIVETENNISAPI_KEY" ``` Use `bearer_token_env_var`, not `bearer_token`: it keeps the key in your environment rather than committing it to a config file. There is also a **Codex plugin**, on its own marketplace: ```bash codex plugin marketplace add livetennisapi/livetennisapi-codex-plugin ``` That registers the marketplace; install the plugin from Codex's plugin picker. Source: [livetennisapi-codex-plugin](https://github.com/livetennisapi/livetennisapi-codex-plugin). The stdio route works too, unchanged: `npx -y livetennisapi-mcp`. ## Bundled skill: Polymarket / Kalshi tennis trading data The Claude Code plugin (`.claude-plugin/plugin.json`) also ships the `polymarket-tennis` Agent Skill under [`skills/polymarket-tennis/`](skills/polymarket-tennis/). It teaches Claude the observe-only [polymarket-tennis](https://github.com/livetennisapi/polymarket-tennis) Python package (market discovery, market-to-match matching, joined price/live-score view), the free-tier budget (30 req/min, 100 requests/day), and the verbatim retirement/walkover settlement rules for Polymarket, Polymarket US and Kalshi. Canonical copy lives in the polymarket-tennis repo; this one is mirrored for plugin installs. No order execution, ever. ## Notes - **Read-only.** Every tool is a GET; nothing here can modify anything. - **Your key stays local** with the stdio server. It is read from the environment by the server process on your machine and sent only to `api.livetennisapi.com`. - Requires Node 20+. ## Development ```bash npm install npm run build LIVETENNISAPI_KEY=twjp_… node dist/index.js # speaks MCP over stdio node dist/http.js # speaks MCP over HTTP, port 8081 npm test # protocol + transport isolation + rate limiting npm run test:mutation # proves those tests fail when the code breaks ``` `test:mutation` is worth understanding before changing `src/http.ts`. It reintroduces each bug the tests claim to catch and asserts the suite goes red. It is not ceremony: the first version of the rate-limit test passed while the limiter was bucketing every caller together. Built on the official [`livetennisapi`](https://www.npmjs.com/package/livetennisapi) client. ## Related Everything in the Live Tennis API developer surface: | | Install | Source | Package | |---|---|---|---| | Python client | `pip install livetennisapi` | [repo](https://github.com/livetennisapi/livetennisapi-python) | [package](https://pypi.org/project/livetennisapi/) | | JavaScript / TypeScript client | `npm install livetennisapi` | [repo](https://github.com/livetennisapi/livetennisapi-js) | [package](https://www.npmjs.com/package/livetennisapi) | | MCP server for LLM agents **(this repo)** | `npx livetennisapi-mcp` | — | [package](https://www.npmjs.com/package/livetennisapi-mcp) | | Vercel AI SDK tools | `npm install livetennisapi-ai` | [repo](https://github.com/livetennisapi/livetennisapi-ai) | — | | Break-point starter — Python | — | [repo](https://github.com/livetennisapi/livetennisapi-starter-python) | — | | Break-point starter — Node | — | [repo](https://github.com/livetennisapi/livetennisapi-starter-node) | — | | Break-point starter — Go | — | [repo](https://github.com/livetennisapi/livetennisapi-starter-go) | — | - **API reference** — ([plain-HTML version](https://docs.livetennisapi.com/reference.html), no JavaScript required) - **OpenAPI 3.1 specification** — [livetennisapi/openapi](https://github.com/livetennisapi/openapi) - **Free API key** — (no card) - **Products** — - **Website and plans** — - **Discord** — - **GitHub org** — ## Affiliate program Know developers who need tennis data? The [affiliate program](https://affiliates.livetennisapi.com/program) pays 51% recurring commission for the life of every referred subscription — 30-day cookie, and the people you refer get 10% off. ## Licence MIT — see [LICENSE](LICENSE). Use of the API service is governed by the [Terms of Service](https://livetennisapi.com/terms).