Skip to main content
Glama

liquipedia-mcp

A small, careful Python client and MCP server for the Liquipedia LPDB v3 API: match results (with every single game), upcoming matches, matches in a time range, and league/group/Swiss standings.

  • Core library (liquipedia_mcp.client, .matches, .standings, .format) usable without MCP. It returns structured dataclasses, so you can format answers yourself (in any language).

  • MCP server (liquipedia-mcp) that exposes the core as five read-only tools, returning English text for the model plus the structured data.

  • Built to respect Liquipedia: a hard 60 requests/hour budget, caching, no automatic retries, a mandatory identifying User-Agent and attribution on every result. See Respecting Liquipedia.

Bring your own key. This project is meant to be self-hosted by each user with their own LPDB API key. There is no public instance, and you must not run one with your key (see below).

Verified wikis: rocketleague and leagueoflegends. Other LPDB wikis (e.g. dota2, counterstrike) are accepted, but the data pitfalls described below were only verified for those two.

Installation

Requires Python 3.11+. The package is not on PyPI; install it from this repository:

pip install "git+https://github.com/LionScherer/liquipedia-mcp"
# or run it without installing:
uvx --from "git+https://github.com/LionScherer/liquipedia-mcp" liquipedia-mcp --help

For development:

git clone https://github.com/LionScherer/liquipedia-mcp && cd liquipedia-mcp
pip install -e ".[dev]"
pytest && ruff check .

The tests use recorded/reconstructed API answers in tests/fixtures and never touch the network, so they need no API key.

Related MCP server: liquipedia-dota2-mcp

Get your own API key

  1. Read Liquipedia's API terms and request access at https://liquipedia.net/api. The free plan is for public, open-source projects that serve the esports community.

  2. Keep the key secret. It belongs in an environment variable or a git-ignored .env file, never in code or in a repository.

Configuration

Variable

Required

Meaning

LIQUIPEDIA_API_KEY

yes

Your LPDB API key. Sent only in the Authorization header; never logged.

LIQUIPEDIA_USER_AGENT

yes

Identifies your project and how to reach you, e.g. "<your-project>/<version> (<contact>)" → "esports-helper/1.2 (https://github.com/you/esports-helper; you@example.org)".

LIQUIPEDIA_MAX_REQUESTS_PER_HOUR

no

Lower the per-process budget (1–60, default 60). Values above 60 are refused.

LIQUIPEDIA_LOCKOUT_SECONDS

no

Pause after an HTTP 429 (default 600, minimum 60).

The server refuses to start when the key is missing or when the User-Agent is empty, still the placeholder, a generic library default (python-httpx/…, curl/…, …) or has no contact (e-mail address or URL). liquipedia-mcp/<version> is appended automatically.

See .env.example.

Use with an MCP client

Claude Desktop (or any client using the mcpServers format)

{
  "mcpServers": {
    "liquipedia": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/LionScherer/liquipedia-mcp", "liquipedia-mcp"],
      "env": {
        "LIQUIPEDIA_API_KEY": "your-key",
        "LIQUIPEDIA_USER_AGENT": "my-assistant/1.0 (https://github.com/you/my-assistant)"
      }
    }
  }
}

Streamable HTTP (local only)

liquipedia-mcp --transport streamable-http --host 127.0.0.1 --port 8000
# MCP endpoint: http://127.0.0.1:8000/mcp

The default bind address is 127.0.0.1. Binding to any other address is refused unless you pass --allow-remote.

⚠️ Never expose this server to the internet. Every tool call is paid for with your API key. A public endpoint lets strangers use your key, which violates Liquipedia's terms and can get the key revoked. If you need remote access, keep it inside your own private network or behind authentication you control.

Tools

Tool

What it does

Requests

get_results(wiki, team?, tournament?, max_tier=1, include_minor_types=false, limit=5)

Finished matches, newest first, with series score, winner by name, every game score (incl. overtime). Champion picks + MVP for ≤ 3 LoL matches.

1

get_upcoming(wiki, team?, tournament?, max_tier=1, include_minor_types=false, limit=10)

Scheduled matches from now on, soonest first. TBD pairings are left out.

1

get_matches_between(wikis, start_utc, end_utc, max_tier=1, include_minor_types=false, team?)

Everything in a time range (≤ 31 days), several wikis in one request. Up to 50 matches with a known time, plus day-only matches (see below).

1

get_standings(wiki, team? | tournament?)

Current table of a team (finds the phase itself) or all groups of a tournament (exact name).

2–3

get_match_details(wiki, team, opponent?, limit=1)

Every game of the team's latest match(es): scores, OT, length, kills, maps, MVP, champions.

1

Tier filters (1=S, 2=A, 3=B, 4=C, 5=D) only apply to general queries; with a team or tournament, all tiers are included. A tier filter keeps exactly tiers 1..max_tier: unranked events (liquipediatier -1) never pass, and minor tier types (Qualifier, Showmatch, Misc, Monthly, Weekly, Biweekly, Daily, Charity) are left out unless include_minor_types=true. Regular tournaments have an empty tier type and always stay in.

Matches whose time is not announced yet (dateexact=0) only carry a day; the 00:00 in their date is a placeholder (the structured result has date_exact=false and day). get_matches_between treats them as whole UTC days: they are included only if their day lies completely inside the range, or the range lies completely inside that day. A range like 13:35 to 01:35 the next day therefore leaves the second day's day-only matches out and says how many were skipped. Exact and day-only matches are limited separately, so day-only matches cannot push exact ones out; a cut-off list says "… and N more". In the text, more than five unplayed day-only matches of one tournament stage and day become one line ("FIFAe World Cup 2026 – Group A: 16 matches on 2026-10-20, times not announced yet"); the structured data still lists every match. Tool descriptions tell the model to read each match line on its own, never invent totals, never present unplayed matches as 0–0, and to cite Liquipedia.

Use as a library

import asyncio
from liquipedia_mcp import LiquipediaClient
from liquipedia_mcp.matches import get_results
from liquipedia_mcp.standings import get_standings


async def main():
    async with LiquipediaClient.from_env() as client:  # one client per process
        results = await get_results(client, "rocketleague", team="Team Falcons", limit=3)
        for m in results.matches:
            print(
                m.date,
                m.score_line,
                "winner:",
                m.winner_name,
                [(g.score1, g.score2, g.overtime) for g in m.games],
            )
        print(results.source.text)  # keep the attribution!

        table = await get_standings(client, "leagueoflegends", team="T1")
        print(table.to_dict())


asyncio.run(main())

All results are dataclasses with to_dict() (JSON-ready). Highlights:

  • Match.winner_name is computed explicitly (from the scores, or LPDB's winner for forfeits). Pass names, not indices, to language models: index-based winners were reproducibly attributed to the wrong team.

  • Opponent.score is None for unplayed matches (LPDB stores -1 placeholders).

  • StandingsGroup.started is False before the first match; placements are then cleared and leader is None.

  • liquipedia_mcp.format contains the English formatter used by the server.

You can inject your own HTTP function (LiquipediaClient(..., fetch=my_fetch)), which is how the tests run without a network.

Respecting Liquipedia

Liquipedia is run by volunteers and Team Liquid, and the API is a shared resource. This package is deliberately conservative:

  • Request budget. At most 60 requests per hour per process (sliding window), as allowed by the API terms. You can lower it, not raise it. When it is used up, the call fails with a clear error instead of sending a request. Cached answers keep working. If you run several processes with the same key, lower the budget so their sum stays within the limit.

  • No automatic retries. Errors are reported, never retried in a loop. After an HTTP 429, all requests pause for 10 minutes (configurable, or longer if the server sends Retry-After).

  • Caching. Successful answers are cached for 5 minutes (time-range queries 10 minutes); errors are cached for 1 minute so that polling clients cannot hammer the API. The cache is size-bounded and in memory.

  • Few, precise requests. One request per match query (multiple wikis are combined with |), field projection via query=…, standings in 2–3 requests.

  • Identification. A User-Agent naming your project and contact is mandatory, plus liquipedia-mcp/<version>. Responses are requested gzip-compressed.

  • No background traffic. There are no health checks, warm-ups or polling loops; requests only happen when a tool is called.

  • Safe queries. Team and tournament names are validated before they are placed in LPDB conditions: [, ], {, }, |, ::, leading operators (!, <, >, ~) and stand-alone AND/OR are rejected; wiki names must match ^[a-z0-9]+$; limits are clamped.

  • Key hygiene. The key is read from the environment only, is never logged and never appears in repr() or error messages. .env is git-ignored.

  • Attribution. Every result carries Source: Liquipedia (liquipedia.net), CC-BY-SA 3.0 both in the text and as a structured source field.

Your obligations as a downstream user

Data from Liquipedia is licensed under CC-BY-SA 3.0. If you show or publish it (in a chat answer, a bot message, a website…), credit Liquipedia and keep the license notice; derived data must stay under the same license. Do not strip the source field when you re-format results. Follow Liquipedia's API terms for your own key.

Data pitfalls handled

Discovered against real LPDB answers (Rocket League and League of Legends, July–September 2026):

  • order=date DESC without [[finished::1]] returns the matches furthest in the future first, so results, upcoming matches and time ranges are separate queries.

  • winner is a string ("1", "2", ""), finished an integer. Unplayed scores are -1; undetermined opponents have empty names. Neither is ever shown as a result.

  • Round names come from match2bracketdata.header; wiki shorthands like !l4!x are dropped instead of guessed (the section, e.g. "Playoffs", remains).

  • Player names like Diaz_(Brazilian_Player) are cleaned to Diaz.

  • Single games marked notplayed/np or without two valid scores are skipped.

  • Standings store one row per team per round, unsorted; only the latest round counts. Tables exist before the first match with placements 1..n; those are reported as "not started". Only definitestatus is used (currentstatus is "down" for everyone before the start). Bo1 Swiss stages keep game records at 0–0; then only match records are shown.

  • Team names are matched exactly by LPDB, but people say "FURIA Esports" where Liquipedia says "FURIA". When a team lookup finds nothing, it is retried once without affixes like "Esports"/"Gaming"/"Team", and the opponent filter of get_match_details compares names the same tolerant way.

  • For team standings, the current phase is the played one with the latest end date, not the highest page id (which picked a January cup over a September league).

Example output

From the test fixtures (reconstructed API answers), as the MCP server returns it:

Latest results – Rocket League (S-Tier only), newest first:
1. 2026-09-14 18:30 UTC | RLCS 2026 - World Championship | Playoffs, Grand Final | Bo7
   Result: Team Falcons 4–1 Karmine Corp. Winner: Team Falcons.
   Games (Team Falcons–Karmine Corp): G1 1–0 (OT, DFH Stadium, 6:21), G2 2–1 (Mannfield), G3 0–3 (Champions Field), G4 1–0 (OT, Utopia Coliseum), G5 3–2 (Urban Central)
2. 2026-09-14 15:00 UTC | RLCS 2026 - World Championship | Playoffs | Bo7
   Result: Karmine Corp 4–0 Gentle Mates. Winner: Karmine Corp.
   Games (Karmine Corp–Gentle Mates): G1 1–0 (DFH Stadium), G2 1–0 (OT, Mannfield), G3 1–0 (Neo Tokyo), G4 1–0 (Forbidden Temple)
Source: Liquipedia (liquipedia.net), CC-BY-SA 3.0
Upcoming matches – Rocket League (S-Tier only), in chronological order:
1. 2026-10-24 14:00 UTC | RLCS 2027 - Paris Open | Swiss Stage, Round 1 | Bo5
   Team Falcons vs Karmine Corp – not played yet
2. 2026-10-25 (time TBA) | RLCS 2027 - Paris Open | Swiss Stage | Bo5
   NRG vs Gentle Mates – not played yet
(1 match(es) with opponents not determined yet were left out.)
Source: Liquipedia (liquipedia.net), CC-BY-SA 3.0
Standings – T1 (League of Legends)

LCK 2026 – Rounds 3-5 – Legend Group
1. Gen.G – matches 12–1 – games 25–6 – advanced
2. T1 – matches 10–3 – games 20–3 – advanced  (queried team)
3. Hanwha Life Esports – matches 8–5 – games 17–12 – advanced
4. Dplus KIA – matches 4–9 – games 10–19
5. KT Rolster – matches 1–12 – games 4–24 – eliminated
(Records are W–L.)
Leader: Gen.G
This stage is finished.

Next up for T1 (not started): 2026 World Championship – Swiss Stage

Source: Liquipedia (liquipedia.net), CC-BY-SA 3.0

License

  • Code: MIT, see LICENSE. © 2026 Lion Scherer.

  • Data retrieved through this software: © Liquipedia contributors, CC-BY-SA 3.0. The MIT license of the code does not apply to the data.

This project is not affiliated with or endorsed by Liquipedia or Team Liquid.

Available Tools

5 tools
get_match_detailsMatch detailsA
Read-onlyIdempotent

Every game of a team's most recent finished match(es): game scores, overtime, game length, kills and maps where available, MVPs and League of Legends champion picks per player. Optionally only matches against a given opponent. Use this for follow-up questions like 'was it close?' or 'who played which champion?'. Cite Liquipedia as the source.

Inputs: team (required), wiki (required), limit, opponent.

get_matches_betweenMatches in a time rangeA
Read-onlyIdempotent

All matches between two UTC timestamps (max. 31 days), in chronological order, for one or more wikis in a single request – e.g. 'what's on this weekend' or 'what happened yesterday'. Finished matches show score and winner; the others are marked 'not played yet' and have no score. Without a team only top-tier matches (max_tier, no qualifiers/showmatches unless include_minor_types) are returned. Matches whose time is not announced count as whole days: they are included only if their UTC day lies fully inside the range (or the range inside that day), and many of them are summarised per tournament stage. Up to 50 matches with a known time are listed; the text says when the list was cut off. Cite Liquipedia as the source.

Inputs: wikis (required), end_utc (required), start_utc (required), team, +2 more.

get_resultsLatest match resultsA
Read-onlyIdempotent

Finished matches, newest first, with the series score, the winner by name and the score of every single game (e.g. 3–2 OT), so you can tell close series from one-sided ones. Filter by team and/or exact tournament name; without either, only top-tier matches (max_tier, no qualifiers/showmatches unless include_minor_types) are returned. With 3 matches or fewer, League of Legends champion picks and MVPs are included. Read each line on its own and do not invent totals. Cite Liquipedia as the source.

Inputs: wiki (required), team, limit, max_tier, +2 more.

get_standingsStandingsA
Read-onlyIdempotent

League, group or Swiss standings. Preferred: pass the team – this finds the phase the team is currently playing in (works when you only know 'Worlds' or 'LCK') and names its next phase if one is scheduled. Alternatively pass the exact tournament name to get all groups of its newest stage. Each row: placement, team, match record, game record (when meaningful), advanced/eliminated if decided. If a table is 'Not started yet', there is no leader. Cite Liquipedia as the source.

Inputs: wiki (required), team, tournament.

get_upcomingUpcoming matchesA
Read-onlyIdempotent

Scheduled matches from now on, soonest first (times in UTC; 'time TBA' when only the day is known). Filter by team and/or exact tournament; without either, only top-tier matches (max_tier, no qualifiers/showmatches unless include_minor_types). These matches have no result yet: never present them with a score. Pairings with undetermined (TBD) opponents are left out. Cite Liquipedia as the source.

Inputs: wiki (required), team, limit, max_tier, +2 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 5 tools

    Disambiguation4/5

    Most tools target distinct query patterns: get_results for finished matches by team/tournament, get_upcoming for future matches, get_standings for tables, get_matches_between for date ranges, and get_match_details for deep per-game stats. However, get_results and get_matches_between both return finished match scores, and get_results sometimes includes champion picks/MVPs that get_match_details specializes in, creating mild overlap.

    Naming Consistency5/5

    All tools use a consistent get_ prefix with snake_case noun phrases (get_results, get_standings, get_upcoming, get_matches_between, get_match_details). The pattern is predictable with no mixed conventions.

    Tool Count5/5

    Five tools is well-scoped for a match-data server, covering results, standings, upcoming fixtures, date-range queries, and detailed game stats without redundancy or bloat.

    Completeness4/5

    The set covers core match lifecycle needs: finished results, upcoming fixtures, standings, time-range queries, and detailed game breakdowns. Minor gaps remain, such as direct tournament/team/player lookup or roster information, but agents can work around most common esports queries.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Provides MCP tools to query Liquipedia esports data (matches, teams, players, tournaments, placements, standings) via the Liquipedia v3 API and MediaWiki action API.
      8
      55 npm
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Read-only MCP server for sourced Dota 2 tournament, team, player, schedule, and result data from Liquipedia, with revision-level metadata and caching.
      5
      9 npm
      1
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables MCP clients to discover tournaments, inspect events, entrants, sets, standings, and streams for any game on start.gg using natural language.
      15
      34 npm
      MIT
    • F
      license
      Not graded
      quality
      C
      maintenance
      Provides live football data from API-Football over HTTP, enabling queries for upcoming matches, recent results, current standings, injuries, live matches, and team search through MCP tools.
      -