euroleague-open-data
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@euroleague-open-dataWho had the best true shooting percentage in EuroLeague last season, minimum 20 games?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
euroleague-open-data
An open EuroLeague / EuroCup basketball data warehouse, and an MCP server that lets an LLM query it in natural language.
Unofficial. Not affiliated with, endorsed by, or approved by Euroleague Basketball. Data originates from Euroleague Basketball and is retrieved from publicly accessible endpoints. For research and educational use. See DISCLAIMER.md.
Why this exists
The upstream EuroLeague API is undocumented, unversioned, and rate-limited at roughly 10 requests per minute by Cloudflare. That makes it unusable for interactive analysis: three questions in a row from one user would black out everyone else for five minutes.
So this project inverts the problem. A slow, polite, resumable crawler pulls the data into a local DuckDB warehouse once. Everything else — the MCP server, the Parquet exports — reads that snapshot.
The MCP server never contacts upstream. It holds no HTTP client. No amount of traffic to this project can generate load on Euroleague Basketball's infrastructure.
Related MCP server: College Basketball Stats MCP Server
Status
Four seasons loaded: EuroLeague E2024 and E2025, EuroCup U2024 and U2025.
Component | State |
Throttled crawler with permanent cache | working |
DuckDB warehouse, 8 base tables | working |
Validation suite, 8 reconciliation checks | working |
Derived analytics (TS%, eFG%, usage, Four Factors, shot zones) | working |
MCP server, stdio transport, 13 tools + 3 resources | working |
HTTP transport + landing page, Docker image build-tested | working |
Public deployment on Render (free instance, sleeps when idle) | live |
Full backfill (52 seasons, 12 122 games) | not started, ~50h of crawling |
Dataset publishing to GitHub Releases / HuggingFace | not started |
Quick start
Requires uv and Python 3.12+.
git clone https://github.com/McNews11/euroleague-open-data && cd euroleague-open-data
uv sync --extra etl--extra etl pulls in the crawler's dependencies. Plain uv sync installs only what is
needed to serve an existing warehouse, which is what the deployed image does — it keeps
polars, pyarrow and httpx out of the container and halves its size.
Build the warehouse. The crawl is deliberately slow — about two hours for one season — and it is safe to interrupt and rerun, because every response is cached permanently.
uv run euroleague-etl --season E2025Already have the cache and only changed the schema? Skip the network entirely:
uv run euroleague-etl --season E2025 --skip-crawlConnect it to Claude
Claude Code
claude mcp add euroleague --env EUROLEAGUE_DB=$PWD/data/euroleague.duckdb -- $PWD/.venv/bin/python -m euroleague_open_data.mcp_serverRemote, for sharing with other people
A hosted deployment serves the same tools over HTTPS, so anyone can connect by URL with nothing installed — and it is the only way to use this from ChatGPT, which cannot run local MCP servers.
claude mcp add --transport http euroleague https://euroleague-open-data.onrender.com/mcpIt runs on a free instance that sleeps after 15 minutes idle, so the first request after a
quiet spell takes about a minute. Everything after it is fast. To host your own, see
docs/DEPLOY.md — the landing page at / fills in whatever hostname it
is served from, so a fork needs no edit.
Note that ChatGPT custom connectors require a paid plan (Plus, Pro, Business, Enterprise or Edu) with Developer mode enabled. Claude Code and Claude Desktop work on any plan.
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"euroleague": {
"command": "/absolute/path/to/euroleague-open-data/.venv/bin/python",
"args": ["-m", "euroleague_open_data.mcp_server"],
"env": {
"EUROLEAGUE_DB": "/absolute/path/to/euroleague-open-data/data/euroleague.duckdb"
}
}
}
}Things to ask it
Who had the best true shooting percentage in EuroLeague last season, minimum 20 games?
Compare Vezenkov and Nwora on efficiency and usage.
Which team had the best defensive rating, and which Four Factor drove it?
Show me Micic's shot chart by zone.
Which games are unreliable for lineup analysis?That last one matters. The warehouse tracks its own completeness, so the model can say "this game has no shot data" instead of inventing a number.
Fantasy drafting
Built for BasketNews Fantasy draft mode: private leagues of 3–12 managers, 13-player rosters, unique squads, snake or reverse-snake order.
Fantasy points are recomputed exactly from boxscores, not estimated. Every term in the modern scoring system maps onto a stored field, so a player's score here is the score the game would award.
Ranking is by value over replacement, not by average. In a draft each manager gets a unique roster, so what decides a pick is how much better a player is than the next one available at the same position — and that depends on league size. An 8-team league and a 12-team league produce different boards from the same data.
uv run python -m euroleague_open_data.fantasy --teams 8 --scoring classicTwo things about scoring are worth knowing before you trust a late-round pick:
The "classic" formula is not published for draft mode, so it was reverse-checked against the live site. Vezenkov, E2025 round 1: PIR 27 in a win scores 29.7 there, and 27 × 1.1 = 29.7 here. The PIR base and the win multiplier are confirmed. The loss multiplier is still inferred — and measured to be immaterial: rebuilding the board with 1.0 instead of 0.9 gives rank correlation 0.9996, an unchanged top 7, and an average move of 1.4 places.
It matters less than it looks. Rank correlation between classic and modern is 0.99 and seven of the top eight are the same players. The disagreement shows up in the middle: one player moves 94th to 61st, which in an 8×13 draft is a different round.
Tools
Tool | Purpose |
| fuzzy name → canonical |
| fuzzy name → canonical |
| season or career, totals / per-game / per-36, plus TS%, eFG%, usage |
| ratings and Four Factors, team and opponent |
| full game detail with completeness flags |
| zone aggregates, optionally raw x/y coordinates |
| read-only DuckDB SELECT — the escape hatch for unanticipated questions |
| draft ranking by value over replacement, sized to your league |
| your picks in snake order, and who should survive until each |
| head to head for a specific pick decision |
| game-by-game fantasy points, for form and role changes |
| how deep a coach's rotation runs — the ceiling on minutes |
| minutes and production a club vacated, by position |
Resources: euroleague://schema, euroleague://coverage, euroleague://data-quality.
run_sql runs on a read-only connection, permits a single SELECT/WITH, caps rows, and
cancels after 15 seconds.
Data quality
Validation runs as part of every ETL run and writes
docs/data-quality-report.json, which is committed so
regressions show up in git log.
Three findings worth knowing about, all documented in
docs/api-notes.md:
Shot coordinates and play-by-play begin at the 2007 season. Earlier seasons have boxscores only. This is a property of the source, not of this project.
Period buckets and event sequence numbers disagree in roughly 40% of games.
NUMBEROFPLAYis unique and reliable; the per-quarter arrays upstream returns are not. Affected games are flaggedlineup_safe = false.Player identifiers differ across endpoints. Boxscores use
TGB, the live feed usesPTGB. Normalisation is source-aware, and there is a regression test for it.
Coverage
Measured across all 52 seasons on 2026-08-10 (docs/coverage.json):
Segment | Seasons | Games | Boxscore | PBP + shots |
EuroLeague | E2000–E2006 | 1 563 | yes | no |
EuroCup | U2002–U2006 | 896 | yes | no |
Both | 2007–2025 | 9 059 | yes | yes |
Total | 52 | 12 122 |
Development
uv run pytest
uv run ruff check src tests
uv run mypy srcLicence and contact
Code is MIT — see LICENSE. The licence covers the code only. It grants no rights in the underlying match data, which belongs to Euroleague Basketball and its data partners. Commercial use of the data may require a licence from them.
Takedown: if you represent a rights holder and want this changed or removed, open a
GitHub issue titled TAKEDOWN. We will respond within 7 days and will take published
datasets down on request while any disagreement is discussed. No formal legal process is
needed to get our attention.
Prior art
giasemidis/euroleague_api— Python wrapper. The shot-coordinate endpoint used here was reverse-engineered there first.FlavioLeccese92/euroleaguer— R wrapper, useful for cross-checking endpoint coverage.bsamot10/EuroleagueDataETL— existing ETL patterns for this data.vtzimpl/euroleague-api-mcp— an earlier MCP server that proxies the API directly. Given the rate limit measured here, proxying is the thing this project deliberately avoids.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceMCP-Server from your Database optimized for LLMs and AI-Agents. Supports PostgreSQL, MySQL, ClickHouse, Snowflake, MSSQL, BigQuery, Oracle Database, SQLite, ElasticSearch, DuckDB541Apache 2.0
- Flicense-qualityDmaintenanceAn MCP server for accessing college basketball statistics through the SportsData.io CBB v3 Stats API, enabling AI agents to retrieve and analyze college basketball data through natural language interactions.
- Flicense-qualityCmaintenanceAn MCP server that enables natural language querying of over 10 million ball-by-ball cricket deliveries stored in a local DuckDB database. It provides 26 tools for analyzing player matchups, situational stats, and historical records across all major cricket formats and tournaments.2
- Alicense-qualityAmaintenanceAn MCP server that provides access to over 12 years of NFL play-by-play data through a local DuckDB database. It enables users to query player performance, team statistics, and situational efficiency metrics like EPA and WPA using natural language.12MIT
Related MCP Connectors
MCP server for AI dialogue using various LLM models via AceDataCloud
GibsonAI MCP server: manage your databases with natural language
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/McNews11/euroleague-open-data'
If you have feedback or need assistance with the MCP directory API, please join our Discord server