liquipedia-mcp
Click on "Deploy 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., "@liquipedia-mcp show me the latest Rocket League match results"
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.
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 --helpFor 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
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.
Keep the key secret. It belongs in an environment variable or a git-ignored
.envfile, never in code or in a repository.
Configuration
Variable | Required | Meaning |
| yes | Your LPDB API key. Sent only in the |
| yes | Identifies your project and how to reach you, e.g. |
| no | Lower the per-process budget (1–60, default 60). Values above 60 are refused. |
| 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/mcpThe 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 |
| Finished matches, newest first, with series score, winner by name, every game score (incl. overtime). Champion picks + MVP for ≤ 3 LoL matches. | 1 |
| Scheduled matches from now on, soonest first. TBD pairings are left out. | 1 |
| 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 |
| Current table of a team (finds the phase itself) or all groups of a tournament (exact name). | 2–3 |
| 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_nameis computed explicitly (from the scores, or LPDB'swinnerfor forfeits). Pass names, not indices, to language models: index-based winners were reproducibly attributed to the wrong team.Opponent.scoreisNonefor unplayed matches (LPDB stores-1placeholders).StandingsGroup.startedisFalsebefore the first match; placements are then cleared andleaderisNone.liquipedia_mcp.formatcontains 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 viaquery=…, 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-aloneAND/ORare 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..envis git-ignored.Attribution. Every result carries
Source: Liquipedia (liquipedia.net), CC-BY-SA 3.0both in the text and as a structuredsourcefield.
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 DESCwithout[[finished::1]]returns the matches furthest in the future first, so results, upcoming matches and time ranges are separate queries.winneris a string ("1","2",""),finishedan 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!xare dropped instead of guessed (thesection, e.g. "Playoffs", remains).Player names like
Diaz_(Brazilian_Player)are cleaned toDiaz.Single games marked
notplayed/npor 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
definitestatusis used (currentstatusis "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_detailscompares 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.0Upcoming 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.0Standings – 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.0License
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 toolsget_match_detailsMatch detailsARead-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 rangeARead-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 resultsARead-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_standingsStandingsARead-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 matchesARead-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
Scored across 5 tools
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.
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.
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.
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
Related MCP Connectors
Sports MCP — wraps TheSportsDB API (free tier, test key 3, no auth required)
ESPN MCP — keyless multi-sport live scores, teams, and news via ESPN's public site API.
BetsAPI MCP — wraps BetsAPI (betsapi.com) sports events + odds.
TheSportsDB MCP — sports catalog (teams, players, events)
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides MCP tools to query Liquipedia esports data (matches, teams, players, tournaments, placements, standings) via the Liquipedia v3 API and MediaWiki action API.855 npmMIT
- AlicenseAqualityDmaintenanceRead-only MCP server for sourced Dota 2 tournament, team, player, schedule, and result data from Liquipedia, with revision-level metadata and caching.59 npm1MIT
- AlicenseAqualityCmaintenanceEnables MCP clients to discover tournaments, inspect events, entrants, sets, standings, and streams for any game on start.gg using natural language.1534 npmMIT
- FlicenseNot gradedqualityCmaintenanceProvides 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.-