Skip to main content
Glama
kupsas
by kupsas
README.md
# football-data-mcp

A football analytics toolkit for Claude (and similar LLM tools) — player scouting, comparisons, market-value filters, expected-goals tables, match-by-match form, team attacking profiles, match search, shot maps, and more.

Built on top of [ScraperFC](https://github.com/oseymour/ScraperFC) by Owen Seymour.

---

## What it does

Combines player and match statistics into one dataset you can explore in conversation with Claude.

**Coverage:** 10 leagues · 3 seasons (2023-24, 2024-25, 2025-26) · 18,800+ player records

**Season stats** (one row per player per season):

| Kind of data | Where it’s available |
|--------------|-------------------|
| Goals, assists, minutes, shots, cards | All 10 leagues |
| Expected goals (xG), expected assists (xAG) | All 10 leagues — **Understat** model in top five; **SofaScore** model elsewhere (`xg_source` / `xag_source` columns) |
| Non-penalty xG, build-up xG, xG chain | Top five leagues only (Understat; not comparable to SofaScore xG) |
| Advanced passing & chance creation | Top five + Netherlands + Portugal — not Championship or European cups |
| Player ratings, duels, dribbles, big chances, and 80+ other performance metrics | All 10 leagues |
| Market value, contract end date, height, nationality | Domestic leagues — weakest for Champions League and Europa League |

**Match-by-match stats** (optional extra step when collecting data):

| Kind of data | Where it’s available |
|--------------|-------------------|
| Last N games, form, ratings, shot locations, team xG for/against | All 10 leagues (after match data is collected) |
| League tables ranked by xG (home / away / overall) | Top five leagues only |

---

## Leagues covered

All leagues include three seasons: **2023-24**, **2024-25**, and **2025-26**.

| League | Season-level data | Match-by-match |
|--------|-------------------|----------------|
| England Premier League | **Full** — xG, build-up, advanced passing, ratings, market value | Yes |
| Spain La Liga | **Full** | Yes |
| Germany Bundesliga | **Full** | Yes |
| Italy Serie A | **Full** | Yes |
| France Ligue 1 | **Full** | Yes |
| Netherlands Eredivisie | **Strong** — xG, advanced passing, ratings, market value (no build-up xG) | Yes |
| Portugal Primeira Liga | **Strong** | Yes |
| England EFL Championship | **Basic** — ratings and core stats; lighter xG; market value often available | Yes |
| UEFA Champions League | **Basic** — ratings and core stats; no market value | Yes |
| UEFA Europa League | **Basic** — ratings and core stats; no market value | Yes |

**Full** = goals and minutes, full xG suite including build-up, advanced passing metrics, player ratings, and market value.

**Strong** = same as Full except build-up xG.

**Basic** = goals, minutes, player ratings, and xG-style metrics; limited advanced passing; European cups lack market value.

Market value and contract data are most complete for the eight main domestic leagues (all except Championship and the two European cups).

---

## The 10 tools

Once connected, Claude can answer questions using **10 built-in tools** (leaner responses; pass `team` with player names when names collide).

### Season-level player data

| Tool | What you can ask |
|------|-----------------|
| `get_player` | "Show me Salah's season stats" (defaults to All Competitions row) |
| `get_eafc_player_attributes` | "What are Saka's EA FC pace and shooting ratings?" |
| `scout_position` | "Top 10 forwards in the Bundesliga by goals" (use position codes F/M/D/GK) |
| `compare_players` | "Compare Salah 2024-25 vs Haaland 2025-26" (per-player season in `subjects`) |
| `get_team_stats` | "Arsenal's league table and average xG this season" (defaults to All Competitions) |
| `compare_teams` | "Compare Liverpool and Man City on standings and xG" (each team can use a different season) |

### Match-by-match analytics

Requires match data to be collected first. Works across all 10 leagues. Resolve fixtures with **home team + away team + season** (optional league).

| Tool | What you can ask |
|------|-----------------|
| `get_match` | Lean overview: score, possession, xG, shots, big chances for one fixture |
| `get_match_player_stats` | **All players** in one match — ratings, goals, xG per player |
| `get_player_match_stats` | **One player** over a date range or matchdays — pass `start_date`/`end_date` or `match_days`; optional `include_summary` for form aggregates |
| `get_match_shots` | Shot map for a match; add `player` to filter to one player's shots |

---

## Setup

Everything runs on your computer: download the stats, then connect Claude Desktop or Cursor so it can answer questions using the **10 tools**.

### 1. Install

```bash
pip install football-data-mcp
```

That installs two commands you can run from any folder:

- **`collect-data`** — downloads and builds the dataset
- **`soccer-mcp`** — starts the connection Claude and Cursor use

**Working on the code?** Clone this repo and run `pip install -e .` in the project folder instead.

### 2. Collect the data

First-time full download takes a while (some sites open a headless browser in the background).

Stats are collected from **Understat**, **SofaScore**, **ClubElo**, **Transfermarkt**, and **Capology** (see `CHANGELOG.md` for recent pipeline changes).

The unified player file also uses the **[REEP](https://github.com/robbyhecht/reep)** (Robust Entity Exchange Protocol) crosswalk (`data/reference/reep_people.csv`) to link player IDs across sources when names differ — for example matching Understat season rows to SofaScore dribble/passing stats, and SofaScore IDs to EA FC / SoFIFA attributes.

```bash
collect-data
```

Useful shortcuts:

```bash
# Only refresh one part of the data
collect-data --sofascore-only
collect-data --understat-only
collect-data --transfermarkt-only

# Extra: league xG tables, match shots, line-ups
collect-data --understat-tables-only
collect-data --understat-matches-only

# Rebuild the merged player file from files you already downloaded
collect-data --rebuild-only
collect-data --rebuild-only --export-csv   # also write a spreadsheet copy
```

### 3. Connect Claude Desktop or Cursor

Add the data connection to your app’s config. After `pip install`, **`soccer-mcp`** should be on your PATH (same program as `python3 -m soccer_server`).

**Claude Desktop** (macOS config file):

`~/Library/Application Support/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "soccer-data": {
      "command": "soccer-mcp"
    }
  }
}
```

**Cursor** — `~/.cursor/mcp.json` or `.cursor/mcp.json` in a project:

```json
{
  "mcpServers": {
    "soccer-data": {
      "command": "soccer-mcp"
    }
  }
}
```

If the app cannot find `soccer-mcp`, use the full path from `which soccer-mcp` as `"command"`, or:

```json
"command": "python3",
"args": ["-m", "soccer_server"]
```

**Quit and reopen** Claude or Cursor after saving. You should see all **10 tools** after step 2 has finished downloading data.

<!--
### Hosted service (coming later) — `mcp.kupsas.com`

Use the managed MCP endpoint (no local scraping). You need an **API key** and a short client config.

**Endpoint:** `https://mcp.kupsas.com/football-data/mcp`  
**Health check:** `https://mcp.kupsas.com/football-data/health`

#### Get an API key

Until a web dashboard ships (`platform.kupsas.com`), mint a key from the terminal:

1. Sign in to the hosted Supabase project (Google SSO or email) and obtain a short-lived **access JWT** (Supabase Auth token endpoint or your app).
2. Exchange it for a long-lived MCP API key:

```bash
export SUPABASE_JWT="paste-your-supabase-access-token-here"

curl -sS -X POST "https://mcp.kupsas.com/football-data/api/keys" \
  -H "Authorization: Bearer $SUPABASE_JWT" \
  -H "Content-Type: application/json" \
  -d '{"name":"my-laptop"}'
```

Copy the `"key"` from the JSON response **once** — it cannot be retrieved again. Store it in a password manager or an env var (do not commit it to git).

```bash
export FOOTBALL_MCP_API_KEY="paste-key-here"
```

#### Cursor (recommended — native HTTPS)

Edit `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a repo):

```json
{
  "mcpServers": {
    "football-hosted": {
      "url": "https://mcp.kupsas.com/football-data/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_MCP_API_KEY"
      }
    }
  }
}
```

Restart Cursor → **Settings → MCP** should show **connected** and list tools. In **Agent** chat, name tools explicitly when needed, e.g. *“Use the scout_position MCP tool for forwards in England Premier League 2024-2025.”*

#### Claude Desktop (requires `mcp-remote` bridge)

Claude Desktop does **not** support `"url"` / remote HTTP in config — only local subprocesses. Use **[mcp-remote](https://www.npmjs.com/package/mcp-remote)** so Claude talks stdio to a local bridge that calls HTTPS:

```json
{
  "mcpServers": {
    "football-hosted": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://mcp.kupsas.com/football-data/mcp",
        "--header",
        "Authorization: Bearer YOUR_MCP_API_KEY"
      ]
    }
  }
}
```

Requires **Node.js** / `npx`. **Quit Claude completely** (Cmd+Q), reopen, wait for first-time `npx` download. Logs: `~/Library/Logs/Claude/mcp*.log`.

#### Verify from the terminal (optional)

```bash
curl -sS "https://mcp.kupsas.com/football-data/health" | python3 -m json.tool

curl -sS -X POST "https://mcp.kupsas.com/football-data/mcp" \
  -H "Authorization: Bearer $FOOTBALL_MCP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
```

Expect HTTP **200** (401 = bad key; 406 = server needs `json_response=True` — contact the operator).

#### Hosted troubleshooting (short)

| Issue | Fix |
| --- | --- |
| Claude: server missing | Use `mcp-remote` config above, not `"type": "http"` |
| 401 | Mint a new key; check Bearer prefix |
| Cursor: connected but no tool use | Agent mode; mention tool name in the prompt |

More detail for operators: private deploy docs (Phase 6 + client §9).

-->
---

## Contributing

This project builds on [ScraperFC](https://github.com/oseymour/ScraperFC). Bug fixes to the underlying scrapers are contributed back upstream — if you find something broken in a scraper, consider opening an issue or PR there too.

For issues specific to the pipeline (`collect_data` package / `collect-data` / `collect_data.py`) or the MCP server (`soccer_server` package / `soccer-mcp` / ``python -m soccer_server``), open an issue here.

---

## Credits

- [ScraperFC](https://github.com/oseymour/ScraperFC) by Owen Seymour — the foundation this project builds on
- Data sources: [Understat](https://understat.com), [SofaScore](https://sofascore.com), [ClubElo](http://clubelo.com), [Transfermarkt](https://transfermarkt.us), [Capology](https://capology.com)

Maintenance

ActivityInactive
ResponsivenessNo issues