documentation

Connect your agent.

Connect any MCP client to OpenScores by pointing it at https://api.openscores.ai/mcp/ (trailing slash required) and passing your osk_live_ API key as a Bearer token. The server speaks Streamable HTTP and exposes 9 read-only tools covering fixtures, lineups, standings, squads, and statistics for the top-5 European leagues + the 2026 World Cup.

Last updated: 12 Jun 2026

Quick start

Get a free key on the account page, then paste this into your MCP client. Replace osk_live_… with your real key.

~/.cursor/mcp.json
{
  "mcpServers": {
    "openscores": {
      "url": "https://api.openscores.ai/mcp/",
      "headers": {
        "Authorization": "Bearer osk_live_…"
      }
    }
  }
}

Quit Cursor fully, reopen, then ask the agent for live data.

The trailing slash matters. The URL is https://api.openscores.ai/mcp/ — with the slash. Without it some clients (including Cursor) drop the Authorization header across a 307 redirect and you'll see a 401 even with a valid key.

Tools

Nine read-only tools. All return JSON; pagination tools use a standard { items, pagination } envelope. Discovery flow: list_leagues list_seasons list_fixtures / get_standings.

list_leagues

The discovery entry point — every competition with id, name, country, tier.

list_leagues()
list_seasons

All seasons for a league, newest first. Feeds list_fixtures / get_standings.

list_seasons(league_id: 7)  // World Cup
list_fixtures

Paginated fixtures with optional filters (season, team, status, date range).

list_fixtures(season_id: 7, status: "scheduled")
get_fixture

One fixture, full: score, lineups, event timeline, statistics. The showcase tool.

get_fixture(fixture_id: 1872)
get_standings

Computed league table, live from finished fixtures (3/1/0, GD, GF tiebreakers).

get_standings(season_id: 2)  // Premier League 25/26
search_teams

Case-insensitive name fragment search across all teams in the DB.

search_teams(q: "arsenal")
get_team

Team profile, seasons played, current-season squad, and recent fixtures.

get_team(team_id: 121)  // Mexico
search_players

Player search by name; optional nationality + position filters.

search_players(q: "messi", nationality: "ARG")
get_player

Player profile, teams played for, career aggregates, recent appearances.

get_player(player_id: 12345)

Authentication

Two auth paths — both hit the same /mcp/ endpoint:

API keys recommended

Sign up at /signup, mint a key on /account, paste Authorization: Bearer osk_live_… into your client config. Free for everyone, revocable, no OAuth dance.

OAuth 2.1

Spec-compliant for clients that want it. We're an OAuth 2.1 Resource Server with RFC 8707 audience binding; tokens come from Auth0. Use this if your client supports the full Streamable HTTP + PKCE flow.

Troubleshooting

"401 invalid_token" even with my key in the config

Almost always the trailing-slash bug. Your URL needs to be https://api.openscores.ai/mcp/ — with the / at the end. Without it the server 307-redirects to the slashed URL, and most MCP clients drop the Authorization header across the redirect. Symptoms: client logs show 401 + a fallback to OAuth that also fails.

Client tries OAuth fallback after rejecting my header (Cursor)

Same root cause. The 401 from the redirect makes the client think the server demands OAuth, so it tries OAuth and fails. Fix the trailing slash and the client picks up the static Bearer header on the first try.

Connection times out / very slow first call

The MCP server cold-fetches JWKS on first boot which can be slow from some networks. Subsequent calls are sub-millisecond. If you persistently see >5s response times, ping the /health endpoint first — if that's fast, your MCP client is probably opening a new connection per request.

Built for football workflows · est. 2026