lcu-mcp
Provides tools for interacting with the League of Legends client, including querying the LCU REST API, streaming live game events, inspecting the client UI via CDP, and optionally executing JavaScript in the client.
Click on "Install 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., "@lcu-mcpWhat's my current queue and champ select status?"
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.
lcu-mcp
An MCP server that exposes a running League of Legends client to any MCP host — the LCU REST API, its live OnJsonApiEvent stream, and the client UI's own DOM and JavaScript context, as nine tools over stdio.
Ask your assistant what queue you are in, watch champ select unfold event by event, inspect the client's DOM, or drive the client itself — without writing a line of glue code.
Contents
Related MCP server: League of Legends MCP Server
How it works
Two independent subsystems run inside one Node process:
LcuClientreads the client's lockfile to discover the port and password, then talks REST over HTTPS with Riot's root CA pinned, and holds a WebSocket tap onOnJsonApiEventthat feeds an in-process ring buffer.CdpClientattaches to the client's Chrome DevTools Protocol endpoint (exposed by Pengu Loader) for DOM queries and JavaScript evaluation.
Both connect lazily and survive client restarts — the lockfile port changes on every launch, so the directory is watched rather than the file. Events are polled rather than pushed, because MCP has no server-to-client push.
Design rationale and the live-verified protocol details live in docs/design.md.
Requirements
Node.js | >= 24 (ESM, no build step) |
League of Legends | Running. The lockfile at |
Pengu Loader | Optional — required only for |
Windows only in practice: the default lockfile path and the Pengu integration are Windows-specific.
Installation
git clone https://github.com/Triggered0/lcu-mcp.git
cd lcu-mcp
npm installRuntime dependencies are exactly three: @modelcontextprotocol/sdk, zod, and ws.
Registering with an MCP host
Claude Code
claude mcp add lcu --scope user -- node C:\path\to\lcu-mcp\src\index.jsAny host that reads .mcp.json
{
"mcpServers": {
"lcu": {
"command": "node",
"args": ["C:\\path\\to\\lcu-mcp\\src\\index.js"],
"env": { "LCU_MCP_CONFIG": "C:\\path\\to\\lcu-mcp\\config\\allowlist.json" }
}
}
}LCU_MCP_CONFIG is optional; without it the server looks for config/allowlist.json relative to its working directory, and falls back to built-in defaults if that file does not exist.
Tools
Tool | Purpose |
| Per-subsystem health, resolved LCU port, configured CDP port, whether |
| GET any LCU path |
| Any verb, subject to the write allowlist |
| List the curated endpoint table |
| Open the WebSocket tap and begin buffering |
| Drain the ring buffer |
| Close the tap |
| Query the client DOM |
| Evaluate JavaScript in the page |
lol_status first. When anything else fails it tells you which half is down — a closed client looks nothing like a missing Pengu install.
Events are polled. lol_events_poll returns a cursor; pass it back as since next time. A non-zero dropped means the ring buffer wrapped and that many events were lost after your cursor. Entries with truncated: true had their data clipped at 4 KB — re-fetch the full body with lol_get on the entry's uri.
The client only emits when state changes. Sitting idle on the home screen it can stay silent indefinitely; navigating the UI or entering a lobby produces bursts. An empty poll usually means nothing happened, not that the tap is broken — check running and lol_status to tell the two apart.
Filters are URI prefixes applied at ingest. The unfiltered firehose fills the buffer quickly, so pass something like ["/lol-champ-select/", "/lol-gameflow/"] unless you genuinely want everything.
Configuration
config/allowlist.json:
{
"allowEval": true,
"cdpPort": 8888,
"eventBufferSize": 1000,
"writeAllowlist": [
"POST /lol-matchmaking/v1/ready-check/accept",
"PATCH /lol-champ-select/v1/session/actions/*"
]
}Key | Default | Meaning |
|
| Whether |
|
| Pengu Loader's remote debugging port |
|
| Ring buffer capacity; oldest entries are evicted first |
|
| Which mutating requests |
Allowlist matching rules:
An entry is
METHOD path. The method is compared case-insensitively, the path case-sensitively.GETandHEADare always allowed and need no entry.*is only meaningful as a trailing path segment:/a/b/*matches/a/b/cbut not/a/b/c/dand not/a/b. Anywhere else it is a literal character.A refused call returns the exact config line that would permit it, and the request is never sent.
Enabling DOM access
lol_dom_query and lol_eval need the client's CEF remote debugging port, which Riot's build only opens through Pengu Loader — an externally added --remote-debugging-port flag is ignored.
Pengu's config is plain key=value text, one pair per line — not JSON, not INI. In C:\Program Files\Pengu Loader\config, set:
RemoteDebuggingPort=8888Then restart the client UX so CEF picks the port up:
POST /riotclient/kill-and-restart-uxThis leaves a live game untouched. Until it happens, both tools fail with these exact instructions rather than a bare ECONNREFUSED.
Security
TLS verification stays on. The LCU's self-signed certificate is validated against Riot's root CA, vendored at
certs/riotgames.pem. The server never setsrejectUnauthorized: false.The password never leaves the process. It is held only to build the
Authorizationheader — no tool returns it, nothing logs it, and error text is scrubbed of it before it reaches the host. CDP target URLs embed it too, so they are redacted before any tool returns them.lol_evalbypasses the write allowlist by construction. The client page canfetchany LCU endpoint from its own origin, so evaluated JavaScript can do anything the client can. This is accepted, not fixed: it is gated by theallowEvalflag, whose statelol_statusreports.
Treat the write allowlist as a guardrail against mistakes, not as a security boundary — while
allowEvalistrueit can be bypassed. SetallowEvaltofalsefor a real boundary.lol_dom_querykeeps working, because it injects the selector as data rather than as code.
Development
npm test # unit tests via node:test — no League client needed
npm run smoke # live end-to-end check against a running client
npm start # run the server on stdionpm run smoke prints one line per stage and exits 1 if any stage fails. It is never run in CI. The event stage waits for real delivery and reports three outcomes: PASS when events arrived, SKIP when the tap connected but an idle client sent nothing, and FAIL when the tap could not connect.
src/
index.js # stdio transport and tool registration
config.js # config loading and validation
allowlist.js # pure write-allowlist matching
redact.js # strip passwords from URLs and strings
lcu/
lockfile.js # parse, read, and watch the lockfile
client.js # REST with the pinned CA
buffer.js # ring buffer with cursor and drop accounting
ingest.js # pure ingest policy: prefix filters, truncation
events.js # WebSocket tap with backoff reconnect
cdp/
discover.js # probe the debugging port, pick and redact the target
client.js # attach, evaluate, DOM query
tools/ # one module per tool group
tests/ # one test file per source moduleTroubleshooting
Symptom | Cause |
| The client is closed, or installed somewhere other than the default path. |
Every CDP tool fails with a Pengu hint | Pengu Loader is not active, or |
| CDP is reachable but the UX is still starting. Retry once the client is visible. |
| Usually an idle client, not a fault. Navigate the UI and poll again; check |
A write is refused | The verb and path are not on the allowlist. The error message contains the exact line to add. |
TLS errors on every REST call | The vendored CA is wrong or stale. Fix the PEM — never disable verification. |
Disclaimer
lcu-mcp is not endorsed by Riot Games and does not reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. Riot Games and all associated properties are trademarks or registered trademarks of Riot Games, Inc.
This project uses the client's own local API. You are responsible for how you use it; automating gameplay may violate Riot's Terms of Service.
License
MIT © Triggered
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseCqualityDmaintenanceAn MCP (Model-Controller-Processor) server for accessing League of Legends client data. This server provides a collection of tools that communicate with the League of Legends Live Client Data API to retrieve in-game data.1212Apache 2.0
- AlicenseBqualityAmaintenanceMCP server exposing 30 tools for League of Legends player analysis, match review, and training-plan generation.3515MIT
- AlicenseAqualityAmaintenanceBridges MCP clients to Affinity by Canva's local MCP server, exposing tools for script execution, rendering, and SDK documentation.1564MIT
- AlicenseAqualityCmaintenanceProvides MCP tools to query Liquipedia esports data (matches, teams, players, tournaments, placements, standings) via the Liquipedia v3 API and MediaWiki action API.8MIT
Related MCP Connectors
Riot Games API MCP.
Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).
Speedrun.com MCP — wraps the Speedrun.com API v1 (speedrun.com/api/v1)
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Triggered0/lcu-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server