tft-meta-coach
by JoonHyun814
README.md
# TFT Meta Coach MCP Server
A stateless, Streamable-HTTP MCP server providing Teamfight Tactics (TFT, 전략적 팀 전투)
meta statistics and personal match analysis, built for submission to PlayMCP.
See [`abstrack.txt`](abstrack.txt) for the project pitch, [`mcp_guide.md`](mcp_guide.md) for
the PlayMCP requirements this server follows, and [`skills.md`](skills.md) for the full tool spec.
## Architecture
```
app/
api/ # (reserved for future non-MCP HTTP endpoints)
tools/ # MCP tool implementations + FastMCP registry
riot/ # Riot API wrapper (account/summoner/league/match/ddragon/patch notes)
cache/ # Redis client + key schema
analysis/ # Deck classifier, meta stat aggregation, history/weakness analysis
models/ # Pydantic domain models
scheduler/ # Batch jobs (Cloud Run Job entrypoint)
utils/ # Config, logging, errors
main.py # FastAPI app; mounts the MCP Streamable HTTP transport
```
Realtime MCP tool calls only ever read Redis or make lightweight, per-player Riot API
calls (profile lookup, match history). Meta statistics (deck tier list, augment stats,
item builds, Challenger baseline) are **never computed on request** — they're produced
by the scheduled batch job below and served from Redis.
## Batch pipeline
```
Cloud Scheduler -> Cloud Run Job (python -m app.scheduler.run_batch)
-> tft-league-v1 (Challenger players)
-> tft-match-v1 (recent matches, deduped across shared lobbies)
-> deck classification + pandas aggregation
-> Redis (meta:decks, meta:augments, meta:items, meta:baseline, meta:lastUpdated)
```
Each key is stored both as the "latest" value and patch-scoped (e.g. `meta:decks:14.24`),
so tools can serve either the current snapshot or a specific past patch.
## Deck classification
Riot's match API never returns a deck name — `app/analysis/deck_rules.py` is a small,
declarative rule table (trait-threshold rules + carry-item rules) that `deck_classifier.py`
matches against. To update for a new TFT set, edit `deck_rules.py` only; the classifier
itself has no set-specific logic.
## Running locally
```bash
cp .env.example .env # fill in RIOT_API_KEY at minimum
pip install -r requirements.txt
redis-server & # or point REDIS_URL at an existing instance
# one-off: populate the meta caches
python -m app.scheduler.run_batch
# start the MCP server
uvicorn main:app --reload --port 8080
```
The Streamable HTTP endpoint is served at `http://localhost:8080/mcp` (stateless mode —
no session negotiation required). `GET /healthz` is a plain liveness check.
## Tests
```bash
pytest
```
Unit tests cover deck classification, meta stat aggregation, history/weakness analysis,
and hidden-OP deck recommendation. Integration tests mock the Riot API with `respx` and
Redis with `fakeredis`, and drive the MCP tool functions end-to-end.
## Docker / Cloud Run
```bash
docker build -t tft-mcp-server .
docker run -p 8080:8080 --env-file .env tft-mcp-server
```
The same image serves both roles on Cloud Run:
- **Service** (the MCP server): default `CMD` from the Dockerfile.
- **Job** (the batch scheduler): override the container command to
`python -m app.scheduler.run_batch`, triggered on a schedule by Cloud Scheduler.
## Known limitations
- `tft_summarize_patch` scrapes Riot's public patch notes page with a heuristic
buff/nerf classifier (keyword-based `<li>` parsing) — if Riot changes that page's
markup, only this tool's parsing degrades (it returns an empty buff/nerf list with an
explanatory `meta_impact`, rather than failing the whole server).
- `rankFilter` currently only supports `"challenger"`, matching what the batch job
actually collects (`tft-league-v1` Challenger league).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing