🎾 tennis-mcp
Zero-clone Model Context Protocol (MCP) server for Open Era ATP tennis.
Query 200,105 ATP matches (1968–2026), 7,622 player careers, 113,744 surface-split head-to-heads, 7,663 Match Charting Project shot/rally breakdowns, and curated dominance/drama indices (GSDI, NBI, Race to Greatness, Young Guns) directly inside Claude, Cursor, Antigravity, or VS Code — without cloning the 265 MB data repo.
⚡ Quick Start (Zero Clone)
tennis-mcp runs via uvx (or pip) and lazily caches only the Parquet/JSON tables your questions need into ~/.cache/tennis-mcp/.
Claude Desktop / Cursor / Antigravity (mcpServers)
{
"mcpServers": {
"tennis-mcp": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/sorukumar/tennis-mcp",
"tennis-mcp"
]
}
}
}
Claude Code (CLI)
claude mcp add tennis-mcp -- uvx --from git+https://github.com/sorukumar/tennis-mcp tennis-mcp
VS Code (.vscode/mcp.json)
{
"servers": {
"tennis-mcp": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/sorukumar/tennis-mcp",
"tennis-mcp"
]
}
}
}
Local Development / Offline tml-data Override
If you already cloned sorukumar/tml-data, point TML_DATA_DIR at it to skip HTTPS downloads completely:
pip install -e ".[dev]"
TML_DATA_DIR=/path/to/tml-data/data tennis-mcp
🛠 Available MCP Capabilities
15 Tools (Powered by DuckDB + Parquet + Story JSONs)
| Category | Tool | What It Queries |
|---|---|---|
| Warehouse | get_dataset_overview |
Live row counts, date window, charting counts, and licenses |
| Players | search_players |
Filter 7,622 ATP careers by name, country IOC code, or Slam champion status |
| Players | get_player_profile |
Career W-L, surface splits, Top 10 win%, recent matches, and MCP charting profile |
| Rivalries | get_head_to_head |
Surface-by-surface H2H breakdown (113,744 pairs) + individual match logs |
| Matches | search_matches |
Parameterized SQL search over 200,105 enriched ATP matches |
| Shot / Rally | get_charting_profile |
475 players' serve/return, rally length (1–3 / 4–6 / 7–9 / 10+), UF rate, Serve+1, and surface splits |
| Shot / Rally | get_match_charting_stats |
Per-match winners, unforced errors, rally distributions across 7,663 charted matches |
| Compare | compare_players |
Side-by-side comparison of 2–6 players across career stats, charting, and age snapshots |
| Indices | get_gsdi_rankings |
Grand Slam Dominance Index (231 title runs) |
| Indices | get_nail_biters |
Nail-Biter Index (687 Grand Slam Finals & Semifinals) |
| Indices | get_greatness_race |
Age-for-age title & Slam pace: Big 3, Alcaraz, Sinner, Borg, Sampras, McEnroe, Lendl, Agassi |
| Indices | get_young_guns_race |
Fonseca, Mensik, Tien, Jodar benchmarked against Alcaraz & Sinner |
| Indices | get_gs_breakthrough |
Career age, matches, and years before first Grand Slam title across 59 champions |
| Geography | get_country_profile |
Top 100 / Top 10 ATP evolution across 50 years by IOC code or snapshot year |
| India | get_indian_tennis_stats |
Open Era Indian ATP singles milestones & histories |
7 Resources (tennis://*)
tennis://overview,tennis://gsdi/top,tennis://nbi/top,tennis://greatness/summary,tennis://young-guns/summary,tennis://global/timeline,tennis://indian/notable
3 Prompt Templates
scouting_report(player_name)rivalry_breakdown(player1, player2)slam_campaign_audit(player_name, tournament)
💬 Example Questions You Can Ask Your AI
- "Compare Jannik Sinner and Carlos Alcaraz on 1st-serve won%, unforced error rate, and Clay charting metrics."
- "Show me Novak Djokovic vs Rafael Nadal head-to-head by surface, plus their highest Nail-Biter Index Slam matches."
- "Which players won a Grand Slam with the fewest tour matches before their first major?"
- "How does Joao Fonseca at age 18–20 track against Carlos Alcaraz in ATP wins and Top 50 wins?"
- "List the top 5 Grass-court Grand Slam comebacks since 2000 sorted by comeback score and duration."
🏗 Architecture
Claude / Cursor / Antigravity / VS Code
│ (stdio MCP)
▼
tennis-mcp (Python + FastMCP/MCPServer + DuckDB)
│
├── TML_DATA_DIR set? ──▶ Local tml-data/data/*.parquet + *.json
│
└── Otherwise ──────────▶ Lazy cache (~/.cache/tennis-mcp/, 7-day TTL)
fetched via HTTPS from sorukumar/tml-data
📄 License & Data Attribution
- Code: MIT License (LICENSE)
- ATP Match & Career Warehouse (
sorukumar/tml-data): Built on Tennismylife / TML-Database and Jeff Sackmann's ATP archive (MIT). - Match Charting Project Tables (
mcp_*.parquet): Derived from Jeff Sackmann's Match Charting Project, licensed under CC BY-NC-SA 4.0 (attribution required; non-commercial share-alike for charting tables).
Metadata
Release files for tennis-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tennis_mcp-0.1.0.tar.gz | 22.2 kB | With provenance | Details for tennis_mcp-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tennis_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for tennis_mcp-0.1.0-py3-none-any.whl |
Total release size: 41.0 kB
Release files / tennis_mcp-0.1.0.tar.gz
| Download URL | tennis_mcp-0.1.0.tar.gz |
|---|---|
| Size | 22.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6c01e64ac26d7444cc2f4adc48c0df2e3ed0ba99d6d82464a3518a3d73967476
|
|
BLAKE2b-256 checksum How to use checksums |
4e608b9b380c610eacbb83dea5493a86c8fdc1d14459efc7c3c01aa116438a81
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logRelease files / tennis_mcp-0.1.0-py3-none-any.whl
| Download URL | tennis_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f3c308486a0952b744e19e28e8735c219447e911977138866d1d279e7920aac1
|
|
BLAKE2b-256 checksum How to use checksums |
9309c5be1d40dedf7c14b5b63ee0c333cc457bde7a482b6004f384fee1aa2379
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logSecurity for tennis-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for tennis_mcp-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.