npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sportmonks/football-mcp-server

v1.5.0

Published

[BETA] MCP server for Sportmonks Football API 3.0 — companion tool for AI-assisted football data exploration. Not a production API client.

Readme

Sportmonks Football MCP Server

** BETA** — This server is currently in beta. Functionality may change and edge cases may be unhandled. It is a companion tool for AI-assisted exploration of the Sportmonks Football API, not a production API client. Use it to chat with your data, prototype, and learn the API shape; for production workloads keep using the Sportmonks Football API 3.0 directly.

We actively welcome feedback — see the Feedback section below.

Model Context Protocol (MCP) server for the official Sportmonks Football API 3.0.

This server exposes focused Sportmonks Football API tools for search, player/team/league/coach/referee/venue lookup, squads, fixtures, standings, seasons, topscorers, odds, season statistics, per-fixture player statistics, match pressure index, transfers, match news, match facts, commentary key moments, team of the week, and team rivals.

Features

  • Focused MCP tools instead of a broad raw API surface
  • Typed input schemas plus runtime validation on every tool
  • JSON output for every tool response, including error responses
  • Descriptive errors with a how_to_fix field for the LLM
  • Pagination metadata (returned, cap, possibly_more, date_window) on every list-style tool so the LLM knows when results were truncated
  • Built on official Sportmonks Football API 3.0 endpoints
  • Player current-team resolution iterates candidate clubs and rejects national-team relations, so current_team returns the player's club rather than their country
  • Unknown ids surface as typed not_found errors instead of all-null rows or silent empties — across the entity lookups (get_player, get_team, get_league, get_coach, get_referee, get_venue), the fixture lookups (get_fixture_details, get_match_preview), get_standings, get_historic_seasons, get_rivals, and get_totw; partial-coverage tools still return a clean empty result for real-but-uncovered ids
  • Types and states are loaded on startup and reused for shared mappings (broad and detailed positions are resolved to readable names via this cache)

Configuration

| Variable | Required | Default | Description | | --- | --- | --- | --- | | SPORTMONKS_API_TOKEN | Yes | — | Your Sportmonks API token from MySportmonks | | SPORTMONKS_LOG_FILE | No | <os.tmpdir()>/sportmonks-football-mcp.log | Absolute path for the local tool-call log. Set to off, none, or empty to disable file logging | | SPORTMONKS_DEBUG_URLS | No | off | Set to 1, true, yes, or on to log each outbound Sportmonks URL to stderr (with api_token redacted). Off by default |

Sportmonks authentication follows the official api_token query parameter approach documented at https://docs.sportmonks.com/v3/welcome/authentication.

Installation

The published npm binary works with any MCP client. Each example below fetches the package on first run (via npx -y) and starts the server; no manual install required.

Claude Code CLI

claude mcp add sportmonks-football \
  --env SPORTMONKS_API_TOKEN="your-token" \
  -- npx -y @sportmonks/football-mcp-server

Claude Desktop

{
  "mcpServers": {
    "sportmonks-football": {
      "command": "npx",
      "args": ["-y", "@sportmonks/football-mcp-server"],
      "env": {
        "SPORTMONKS_API_TOKEN": "your-token"
      }
    }
  }
}

Cursor

{
  "mcpServers": {
    "sportmonks-football": {
      "command": "npx",
      "args": ["-y", "@sportmonks/football-mcp-server"],
      "env": {
        "SPORTMONKS_API_TOKEN": "your-token"
      }
    }
  }
}

VS Code

{
  "servers": {
    "sportmonks-football": {
      "command": "npx",
      "args": ["-y", "@sportmonks/football-mcp-server"],
      "env": {
        "SPORTMONKS_API_TOKEN": "your-token"
      }
    }
  }
}

Install from source

For contributing or running against unreleased changes:

npm install
npm run build
SPORTMONKS_API_TOKEN="your-token" node dist/index.js

Point your MCP client at the compiled entrypoint (node /absolute/path/to/dist/index.js) instead of the npx command.

Available Tools

Response shapes

List-style tools (search, get_matches, get_squad, get_standings, get_topscorers, get_odds, get_season_stats, get_fixture_lineup_stats, get_transfers, get_match_facts) return a { data, meta } envelope where meta contains returned, cap, and possibly_more. Use meta.possibly_more to detect upstream or local truncation. get_matches also exposes meta.date_window for non-live timeframes, the two stats tools (get_season_stats, get_fixture_lineup_stats) expose meta.stat_types with the applied stat filter, get_match_facts exposes meta.basis, meta.category, and meta.scope with the applied filters, and get_odds sets meta.empty_reason on empty results to say why they are empty.

get_pressure_index also returns a { data, meta } envelope, but meta carries returned, cap, possibly_more, and the applied mode; its data is mode-dependent (summary aggregates or a per-minute timeline) rather than a flat list. get_fixture_news returns a { data, meta } envelope too, with data carrying prematch/postmatch article arrays and meta = { timing, returned: { per type } }. get_rivals returns a { data, meta } envelope where meta = { team_id, returned }. get_commentaries returns a { data, meta } envelope where data is a flat list of key-moment lines ({ minute, comment, is_goal }) and meta = { fixture_id, returned }. get_totw returns a flat object { league_id, round, formation, players, meta } (the 11-player selection in players) where meta = { returned, scope, league_id, round_id }.

Single-entity tools (get_player, get_team, get_league, get_coach, get_referee, get_venue, get_match_preview, get_fixture_details) and get_historic_seasons return a JSON object or array directly without an envelope.

search

Search for entities in the Sportmonks database.

Inputs:

  • query (required)
  • type (optional): player, team, league, coach, referee, venue, all (default)

Output:

  • { data, meta } envelope; data contains up to 25 items sorted alphabetically by name
  • Each item contains id, entity_type (player, team, league, coach, referee, or venue), name, and country (country may be null when Sportmonks doesn't provide one; useful for disambiguating generic names like the dozen leagues called "Super League")
  • meta is { returned, cap, possibly_more } (cap is 25); possibly_more is true when more matched upstream (across the queried entity endpoints) than the 25 returned

get_player

Get player details by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, position, nationality, date_of_birth, and current_team

get_team

Get team details by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, country, venue, and coach ({ id, name } for the current manager; null when no active coach is recorded)

get_league

Get league details by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, country, current_season_id, and current_season_name

get_coach

Get coach details by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, nationality, date_of_birth, and current_team ({ id, name } for the coach's active appointment; null when none is recorded). Mirrors get_player's shape

get_referee

Get referee (match official) details by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, nationality, and date_of_birth. Mirrors get_coach's shape minus current_team (referees have no team). nationality falls back to the referee's country when the dedicated nationality field is empty (it usually is)

get_venue

Get the full venue (stadium) record by id.

Inputs:

  • id (required)

Output:

  • JSON object with id, name, city, country, capacity, surface, address, and coordinates ({ latitude, longitude }, or null when not recorded)
  • This is the full record; a team's venue (in get_team) stays lean (name only). Address and coordinates are included here because a direct venue lookup wants the complete picture

get_rivals

Get a team's traditional rivals.

Inputs:

  • team_id (required)

Output:

  • { data, meta } envelope; each rival contains rival_team_id, rival_team_name, and rival_short_code. meta is { team_id, returned }
  • Coverage is partial — a real team with no rival data returns an empty list, not an error (an unknown team id returns not_found)

get_squad

Get the current or historic squad for a team.

Inputs:

  • team_id (required)
  • season_id (optional)

Output:

  • { data, meta } envelope; each row contains player_id, name, position, position_id, detailed_position, detailed_position_id, and jersey_number

get_matches

Get matches for a team or league.

Inputs:

  • id (required)
  • type (required): team, league
  • timeframe (optional): live, historic, upcoming (default)

Output:

  • { data, meta } envelope; each match contains id, home_team, away_team, starting_at, state, and league
  • For upcoming and historic timeframes, meta.date_window reports the { start, end } range queried

Built-in limits:

  • upcoming: next 14 days, max 20 fixtures
  • historic: last 30 days, max 20 fixtures
  • live: max 20 fixtures

get_match_preview

Get a compact match preview for a fixture id.

Inputs:

  • id (required): fixture id

Output:

  • JSON object with id, home_team, away_team, starting_at, and last_5_h2h_matches
  • last_5_h2h_matches contains up to 5 previous H2H fixtures with date, home_team, away_team, home_score, away_score, and result_info

Constraint:

  • only works for fixtures that have not started yet

get_fixture_details

Get detailed fixture data with optional expansions.

Inputs:

  • fixture_id (required)
  • includes (optional): subset of lineups, events, statistics, predictions, xg, referees, tv_stations

Output:

  • Base fixture object always includes id, home_team, away_team, starting_at, state, league, and scores
  • lineups (when requested): each row contains player_id, player_name, team_id, jersey_number, position, detailed_position, and type (lineup or bench). team_id lets you split home vs away without inferring from order
  • events (when requested): each event contains minute, type, player_name, related_player_name, result, and info
  • statistics (when requested): grouped per team with team_id, team_name, and a stats object keyed by stat name
  • predictions (when requested): a curated object with home_win, draw, away_win, btts, over_2_5, and value_bets. Probabilities are percentages on a 0–100 scale as Sportmonks returns them; btts and over_2_5 carry only the positive direction (the inverse is derivable). value_bets lists only bets Sportmonks flags as genuine value opportunities (is_value true upstream) — it is an empty array for most fixtures (~99% in practice), including fixtures where the model evaluated a candidate but found no value. Each value bet contains bet (1X2 notation: "1" home, "X" draw, "2" away), bookmaker, fair_odd, odd, and stake. Sportmonks exposes ~35 prediction types; this include curates the four most useful (fulltime result, BTTS, over/under 2.5, value bets) — fields are null (or []) when a type is missing
  • xg (when requested): a list of one object per team with team_id, team_name, xg (Expected Goals), and xg_on_target (Expected Goals on Target / xGoT). Populated for finished and live fixtures with coverage; an empty array for upcoming fixtures or fixtures without xG data. Sportmonks exposes 10+ xG-family metrics; this include curates only xG and xGoT
  • referees (when requested): the match officials — a list of { referee_id, name, type } where type is the resolved role (e.g. Referee, 1st Assistant, 2nd Assistant, 4th Official, VAR). Empty when officials aren't published
  • tv_stations (when requested): the broadcasters showing the fixture grouped by country — an object mapping country name to a sorted list of station names, with the station's url in parentheses when it has one (e.g. "Argentina": ["DGO (https://www.directvgo.com/)", "DIRECTV Sports"]). Sportmonks lists one pivot row per station per broadcast country (a World Cup final carries ~400 rows / ~250 stations across ~120 countries) and duplicate channel records; this include groups, dedupes within each country, and answers "where can I watch in X" by key lookup. An empty object when no broadcasters are listed (coverage varies by competition/region)

Constraint:

  • predictions requires a Sportmonks subscription with the predictions add-on; without it the whole call returns an authentication_error explaining how to retry without predictions

get_standings

Get the standings table for a league. Tries the live endpoint first; if no live standings are returned (including 404 responses for competitions between phases), falls back to season-based standings using the league's current season.

Inputs:

  • id (required)

Output:

  • { data, meta } envelope; each standing row contains position, team, group, round, played, won, drawn, lost, gd, and points
  • group is { id, name } for group-stage competitions (World Cup, Champions League league phase, MLS conferences) and null for single-table leagues; rows are ordered by group then position so each group reads 1→N. round is { id, name } for the matchday the table reflects (null if absent)

get_historic_seasons

Get all seasons for a league, sorted from most recent to oldest.

Inputs:

  • league_id (required)

Output:

  • JSON array with id, name, is_current, finished, starting_at, and ending_at

get_topscorers

Get season topscorers, assisters, or card leaders.

Inputs:

  • season_id (required)
  • type (required): goals, assists, cards
  • limit (optional): default 10, max 25

Output:

  • { data, meta } envelope; each row contains position, player, team, and total

get_odds

Get pre-match or premium betting odds for a fixture. Inplay odds are not supported.

Inputs:

  • fixture_id (required)
  • type (optional): prematch (default), premium
  • market_id (optional): filter to a single market (e.g. 1 for Fulltime Result)
  • bookmaker_id (optional): filter to a single bookmaker
  • limit (optional): default 50, max 200

Output:

  • { data, meta } envelope; each entry contains bookmaker_id, bookmaker_name, market_id, market_name, label, name, value, total, handicap, stopped, and last_updated
  • name disambiguates multi-outcome markets — the scoreline for Correct Score ("7-0"), the player for Goalscorers/player props — when label alone (1/2/Draw, Anytime, 3.5) is ambiguous; null when the market needs no disambiguation
  • value, total, and handicap are decimal strings as Sportmonks sends them; total/handicap carry the line for markets like Goal Line or Asian Handicap
  • When data is empty, meta.empty_reason says why: fixture_has_no_odds, fixture_has_no_premium_odds, filters_matched_no_odds (unknown or unoffered market_id/bookmaker_id), premium_odds_not_available (premium coverage is time-limited, so past fixtures lose it; with filters set, the filters may also be the cause), or no_odds_returned

Built-in limits:

  • up to limit entries (default 50, max 200), sorted by market then bookmaker, rounded down to whole market+bookmaker blocks so a 1X2 block is not cut mid-way (returned can be slightly under the limit; if a single block alone exceeds the limit it is plainly sliced instead of returning nothing). An unfiltered fixture can carry thousands of odds upstream, so narrow with market_id and/or bookmaker_id — or raise limit — when meta.possibly_more is true

Constraint:

  • type='premium' requires a Sportmonks subscription that includes the premium odds feed; without it the tool returns an authentication_error explaining the tier requirement

get_season_stats

Get seasonal statistics for a player or team.

Inputs:

  • entity_id (required): player id or team id
  • entity_type (required): player, team
  • season_id (required): use get_historic_seasons to find one
  • stat_types (optional): stat names to return instead of the per-entity-type defaults, e.g. ["goals", "big_chances_created"]; unknown names are rejected with a validation_error naming the offenders

Output:

  • { data, meta } envelope; each row contains entity_id, entity_name, entity_type, season_id, season_name, and a stats object keyed by snake_case stat name
  • Player rows also contain team ({ id, name }) — a player's season stats are per club, so a mid-season transfer yields one row per club
  • Stat values mirror the upstream data: simple counters are unwrapped to plain numbers; richer stats (e.g. goals with penalty split, team stats with home/away splits, rating with average/highest/lowest) stay objects — so the same stat key can be a number for one entity and an object for another, depending on what Sportmonks tracks. Null subfields upstream never computes (e.g. shots.on_target_pct, shot_frequency) are stripped; a value left with a single subfield unwraps to a plain number
  • meta is { returned, cap, possibly_more, stat_types }; meta.stat_types always reports the applied stat filter, whether default or user-supplied
  • An empty data array means the entity exists but recorded none of the requested statistics for that season (e.g. the season has not started, or a player made no appearances)

Default stat filters:

  • player: goals, assists, minutes_played, appearances, shots_on_target, passes, key_passes, tackles, rating
  • team: goals, goals_conceded, team_wins, team_draws, team_lost, cleansheets, shots, pass_stats, ball_possession

Notes:

  • stat names are the snake_case of the Sportmonks type name ("Shots On Target"shots_on_target); spellings like "Shots On Target" or "shots-on-target" are normalized automatically
  • stat availability varies by league, entity type, and data tier — and Sportmonks omits zero-value stats entirely — so a stat missing from stats means "not tracked or zero"; the two cases cannot be distinguished upstream. A player with no minutes in the season (or an unstarted season) yields no row — "no stats" is always an empty data array
  • teams have no shots_on_target or passes stat types upstream; shots-on-target lives inside shots and pass numbers inside pass_stats

get_fixture_lineup_stats

Get player-level statistics for a fixture — both squads, including bench.

Inputs:

  • fixture_id (required)
  • player_ids (optional): filter to specific players
  • stat_types (optional): stat names to return instead of the defaults, e.g. ["rating", "passes", "shots_total"]

Output:

  • { data, meta } envelope; each row contains player_id, player_name, team_id, team_name, type (lineup or bench), and a stats object keyed by snake_case stat name
  • meta.stat_types always reports the applied stat filter, whether default or user-supplied
  • An empty data array means the fixture exists but has no lineup data (not announced yet, or not covered for the league) — or, when player_ids is set, that none of the requested players are in the lineups

Default stat filter:

  • goals, assists, minutes_played

Built-in limits:

  • max 60 player rows (an international friendly with extended benches produced 49, so real fixtures are never truncated)

Notes:

  • the stat filter is pushed upstream (an unfiltered fixture carries ~900 stat entries across ~60 types), so narrow stat_types rather than post-filtering large responses
  • stat names are the snake_case of the Sportmonks type name, normalized like get_season_stats
  • Sportmonks omits zero-value stats, so a missing stat means "not tracked or zero"; under the default filter (which includes minutes_played) a bench player with an empty stats object did not come on — with a narrower override, empty may just mean none of the requested stats were recorded

get_pressure_index

Get the Sportmonks Pressure Index for a fixture — a proprietary real-time metric scoring which team is dominating, minute by minute. Use it to describe momentum swings and periods of dominance.

Inputs:

  • fixture_id (required)
  • mode (optional): summary (default) or timeline

Output (both modes return a { data, meta } envelope; meta is { returned, cap, possibly_more, mode }):

  • summary: data is { teams, swings }. teams is [home, away], each with team_id, team_name, peak_pressure, average_pressure, and dominance_share (% of recorded minutes that team led). swings is the top momentum-swing minutes (lead changes, most decisive first by pressure, then chronological), each with minute, team_id, team_name, and pressure
  • timeline: data is { teams, timeline }. teams is [home, away] (team_id, team_name); teams[0] is the home key and teams[1] the away key. timeline is the cleaned per-minute series sorted by minute, each entry { minute, home, away } with the redundant id/fixture_id stripped

Built-in limits:

  • timeline capped at 150 minute-entries (a full 90' match is ~94; covers extra time), with meta.possibly_more flagging truncation. Summary aggregates the whole recorded series

Notes:

  • works for live (partial series) and finished (full series) fixtures; returns an empty series for upcoming fixtures or fixtures without pressure data
  • pressure is a relativity metric — only one team has positive pressure at a time, so dominance_share values reflect who led each minute and a tied (both-zero) minute counts toward neither
  • team names are resolved from the fixture participants returned by the same call (no extra lookup)

get_transfers

Get football transfers: latest market activity, transfers for a team or player, or transfers within a date range. Confirmed transfers and rumours share one shape, selected via type.

Inputs:

  • id (optional): team or player id to scope to
  • entity_type (team | player): required when id is provided
  • type (confirmed | rumour): default confirmed; rumours require a subscription add-on
  • timeframe (latest | date_range): defaults to latest when an id is provided; for an unscoped query (no id) it must be set explicitly. Unscoped confirmed latest means transfers dated within the last two weeks plus already-announced moves dated up to a week ahead; a scoped query returns the team's/player's most recent transfers with no date window
  • start_date / end_date (YYYY-MM-DD): required when timeframe=date_range; the window must not exceed 31 days (the Sportmonks API limit for transfer date ranges)

Output:

  • { data, meta } envelope, max 25 results; each entry contains id, player ({ id, name }), from_team ({ id, name }), to_team ({ id, name }), type (confirmed/rumour), transfer_kind (resolved transfer type, e.g. Transfer, Loan, End of loan), fee, and date
  • fee is null for undisclosed deals (never 0)
  • results are sorted newest-dated first (duplicated upstream rows are removed) before the 25-cap

Constraints / validation:

  • requires either an id (with entity_type) or an explicit timeframe — a bare call with neither is rejected
  • id without entity_type is rejected
  • a date_range window longer than 31 days is rejected (Sportmonks caps transfer date ranges at 31 days)
  • date_range cannot be combined with an id — there is no date-scoped team/player endpoint, so the combination is rejected rather than silently ignoring the window
  • date_range cannot be combined with type='rumour' — the Sportmonks rumour between endpoint matches records by update time, not rumour date, so results would be wrong or empty
  • type='rumour' without the rumours add-on returns a clear authentication_error telling you to retry with type='confirmed' or upgrade

Notes:

  • rumours have no dedicated "latest" feed, so an unscoped timeframe=latest rumour query reads the full rumour feed (still capped at 25)
  • rumour-only fields (probability, source, currency) are dropped to keep one uniform shape across both types

get_fixture_news

Get match news for a fixture: expert-written pre-match previews and AI-generated post-match reports.

Inputs:

  • fixture_id (required)
  • timing (optional): prematch (default, richest narrative), postmatch, or both

Output:

  • { data, meta } envelope. data carries the requested prematch and/or postmatch arrays; each article has id, title, type, league_id, and body
  • body is the article's lines sorted by id (their publish order — the API returns them shuffled) and joined into one readable prose string; per-line id/newsitem_id/type are dropped
  • meta is { timing, returned: { prematch?, postmatch? } }, echoing the timing and per-type article counts
  • A fixture with no news returns empty arrays and zero counts (not an error); an unknown fixture id returns not_found

Notes:

  • pre-match coverage is limited to top European competitions (UCL, Premier League, La Liga, Bundesliga, Serie A, Ligue 1); post-match coverage is broader
  • pre-match previews are published ahead of kickoff; post-match reports become available after full time (exact lead/latency windows are not guaranteed)
  • standalone (not a get_fixture_details include) because each article is several paragraphs of prose — bundling it into every fixture call would inflate token usage

get_match_facts

Get pre-calculated Match Facts (structured match insights) for a fixture.

Inputs:

  • fixture_id (required)
  • basis (required): h2h (the head-to-head matchup between the two teams) or team (each team's recent form) — request them separately, not together
  • category (optional): one or more of statistics, streaks, players, coaches, statistic_comparisons

Output:

  • { data, meta } envelope; each fact has type_id, category, participant, natural_language (the sentence), and data (the raw object). Both the sentence and the raw data are always returned
  • meta is { returned, cap, possibly_more, basis, category, scope }, echoing the applied filters (category is null when no category filter is applied; scope reports which scope was served)

Fixed filters (always applied):

  • only facts with a non-null natural_language value (filtered MCP-side across all pages)
  • league_matches-scoped facts when available; on cup/international fixtures (e.g. the World Cup) where league-scoped sentences are absent, falls back to all_matches-scoped facts — meta.scope reports which scope was served, and all_matches sentences aggregate across competitions

Built-in limits / notes:

  • the raw dataset is 400-800 facts per fixture across many pages; after filtering a rich fixture yields ~85-90 facts per basis. Capped at 100 (possibly_more flags truncation)
  • statistic_comparisons exists only for basis='team'; requesting it with basis='h2h' returns a clear validation error
  • requires the Match Facts add-on; coverage varies by league, so a fixture with no facts returns an empty list (an unknown fixture id returns not_found)

get_commentaries

Get the key moments of a fixture's text commentary — goals and cards.

Inputs:

  • fixture_id (required)

Output:

  • { data, meta } envelope; each line is { minute, comment, is_goal }, sorted chronologically. is_goal is true for a goal and false for a card
  • minute is the numeric match minute; stoppage time folds in as a string like "45+9"
  • meta is { fixture_id, returned }

Built-in limits / notes:

  • returns only the is_important lines (goals + cards) — typically ~10-25 per match. A full play-by-play is ~110 lines; returning all of it is deferred until the server has general pagination
  • coverage varies by competition, so a fixture with no commentary returns an empty list (an unknown fixture id returns not_found)

get_totw

Get the latest Team of the Week for a league — the 11 highest-rated players of the most recently completed round, per Sportmonks' player-rating model (best per positional role, max 3 per team, in the formation with the highest combined rating).

Inputs:

  • league_id (required)

Output:

  • { league_id, round, formation, players, meta }
  • players is the 11-player selection sorted by formation_position (goalkeeper first); each is { formation_position, position, player_id, player_name, team_id, team_name, team_short_code, rating }. player_name is the trimmed display name; position is the readable role (Goalkeeper, Defender, Midfielder, Attacker); rating is numeric
  • formation (e.g. "4-3-3") and the round summary ({ id, name, starting_at, ending_at, finished }) are surfaced once at the top level
  • meta is { returned, scope, league_id, round_id } (scope is always "latest")

Built-in limits / notes:

  • always the latest TOTW (by-round and all-leagues variants are not exposed; the round summary tells you which round the selection is from)
  • requires the Team of the Week add-on; coverage is round-based competitions only (no knockouts/playoffs), so a real league with no TOTW returns an empty players list with returned 0 — a clear empty result, not an error (an unknown league id returns not_found)

Resources

The server exposes two MCP Resources. Fetch them via resources/read (or @-mention in clients that support it, e.g. Claude Desktop, Cursor).

| URI | MIME type | Content | | --- | --- | --- | | sportmonks://documentation | text/plain | Server overview: tool list, behavior notes, links to official Sportmonks docs | | sportmonks://openapi | application/json | Official Sportmonks Football OpenAPI spec (fetched fresh on every read) |

Claude Code does not auto-load resources — users attach them explicitly via @-mention when needed.

Observability

The server writes one JSON line per tool call to stderr and to a local log file, including tool name, arguments, duration, and outcome. See OBSERVABILITY.md for the log format, default paths per OS, and debugging flows.

Error Format

All tool errors are returned as JSON with this shape:

{
  "ok": false,
  "error": {
    "type": "validation_error",
    "message": "The 'id' field must be a positive integer.",
    "how_to_fix": "Call the tool again with 'id' set to a positive integer such as 501 or 19735.",
    "details": null
  }
}

Example Prompts

You don't need to know any Sportmonks ids — the server will look them up. Try any of these:

Finding things

  • Search for "Barcelona" — is it a team, a league, or both?
  • Find the player ID for Erling Haaland
  • Search for leagues named "Premier League"

Teams & players

  • Get the profile for Manchester City
  • Show me the current squad for Liverpool
  • Who was in Arsenal's squad during the 2021/22 season?
  • Get the profile for Vinicius Jr — which team is he at?
  • Who is the current coach of Manchester City?
  • Find the coach Pep Guardiola and tell me which club he manages
  • Look up the referee Anthony Taylor
  • Who are the match officials for fixture 123456?
  • Find the venue Old Trafford — capacity, surface, and location
  • Who are Liverpool's traditional rivals?

Fixtures

  • Show me Real Madrid's upcoming fixtures for the next two weeks
  • What were Chelsea's results over the last 30 days?
  • Are there any live matches right now?
  • Get the full details for fixture 123456 including lineups and events
  • What were the xG and xGoT for both teams in fixture 123456?
  • Where can I watch fixture 123456 — which TV channels are broadcasting it?
  • Who controlled fixture 123456 and when did the momentum swing? Use the pressure index
  • Give me the pre-match preview for fixture 123456
  • Summarise the post-match report for fixture 123456
  • Give me the head-to-head match facts for fixture 123456
  • What are the team-form streaks and statistic comparisons for fixture 123456?
  • What were the key moments — goals and cards — in fixture 123456?
  • Who made the Premier League team of the week?

Standings & seasons

  • Show me the current Premier League standings
  • What seasons has the Champions League had? Give me the most recent ones first
  • Who are the top 10 goal scorers in Serie A this season?
  • Show me the top 5 assist providers and top 5 yellow card recipients in the Bundesliga

Odds

  • What are the match-winner odds for England's next fixture?
  • Which bookmaker offers the best odds on a home win in tomorrow's Madrid derby?

Season statistics

  • How many goals and assists did Haaland record in the 2025/26 Premier League season?
  • Compare Manchester City's goals scored and conceded at home vs away last season

Player match stats

  • How many minutes did each Iceland player get in the Argentina friendly?
  • Get the player ratings and passes for both teams in yesterday's final

Transfers

  • Show me the latest confirmed transfers
  • What transfer rumours are linked to Real Madrid right now?
  • List all transfers in January 2026

Briefings (using prompts)

  • Give me a pre-match briefing for the upcoming El Clásico — use the match_preview prompt
  • Run the team_overview prompt for Manchester United
  • Generate a league_overview for the Premier League

Building with the API

  • Fetch a sample fixture with lineups and events using get_fixture_details, then write me a TypeScript interface for the response shape
  • Use get_standings to get the current La Liga table and render it as a formatted markdown table
  • Build a function that takes a team name, searches for it, then fetches its next 5 fixtures

Feedback

This server is in beta and the team actively welcomes feedback. If you encounter issues, unexpected behavior, or have ideas for improvements, please email [email protected] and include:

  • The specific tool that was called and its arguments
  • What you expected versus what actually happened
  • Your AI client (Claude Desktop, Claude Code, Cursor, etc.) and the version of this package

That detail helps us reproduce and fix issues quickly.

Development

npm install
npm run build
npm test