MCP server exposing the FACEIT Data API v4 as typed tools.
Project description
faceit-mcp
Give your AI assistant typed, first-class access to the FACEIT platform.
An MCP server that maps the FACEIT Data API v4 to a curated set of tools—so agents can query players, matches, hubs, tournaments, and more with clear, disambiguated intent.
Features
- Full API coverage — All 64
GETendpoints from the official Swagger spec, generated into per-tag Python modules and registered with FastMCP. - Agent-friendly tool design — Every tool carries an enriched description with “use this when / prefer that when” hints so models pick the right call among similar names (for example
searchPlayersvsgetPlayerFromLookupvsgetPlayer, or lifetime vs per-match player stats). - Typed request surfaces — Tool parameters are generated from the spec with accurate Python annotations (paths, query strings, enums, and pagination limits).
- Production-ready HTTP — Async httpx client with bearer auth, timeouts, and structured errors tuned for LLM-facing messages (401 / 403 / 404 / 429 / 503).
- Reproducible codegen — Tools are generated from
swagger.jsonviascripts/generate_tools.py; committed output means the server runs without the spec at runtime.
Requirements
- Python 3.10+ (tested on 3.11)
- A server-side FACEIT API key from developers.faceit.com (My Apps → API Keys → Server-side)
Installation
From PyPI
Ideal for dev containers, CI, and machines where you do not need a git clone:
pip install faceit-mcp
With uv:
uv tool install faceit-mcp
Run once without a global install (also suitable for Cursor):
uvx faceit-mcp
From source (contributors)
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
With uv (this repo ships an uv.lock):
uv venv && source .venv/bin/activate
uv pip install -e .
Configuration
Copy the example env file and set your key:
cp .env.example .env
# Edit .env and set FACEIT_API_KEY=...
| Variable | Required | Default | Description |
|---|---|---|---|
FACEIT_API_KEY |
yes | — | Server-side key (sent as Authorization: Bearer …). |
FACEIT_API_BASE_URL |
no | https://open.faceit.com/data/v4 |
Override for testing or staging. |
FACEIT_API_TIMEOUT |
no | 30 |
HTTP timeout in seconds. |
Run (stdio)
This server uses stdio transport (JSON-RPC over stdin/stdout). Cursor, Claude Desktop, or the MCP Inspector spawn the process and attach to that pipe. If you run faceit-mcp in a normal shell with no client, it will appear idle because it is waiting for MCP messages, not printing a REPL.
faceit-mcp
# equivalent:
python -m faceit_mcp
Quick smoke test (no HTTP; verifies all tools register):
FACEIT_API_KEY=placeholder python -c "
import asyncio
from faceit_mcp.server import mcp
tools = asyncio.run(mcp.list_tools())
assert len(tools) == 64, len(tools)
print('OK', len(tools))
"
Try it with the MCP Inspector
The MCP Inspector is a browser UI for exploring and calling a live MCP server. The mcp[cli] dependency provides mcp dev, which launches the Inspector and connects to this server over stdio.
Prerequisites
- Node.js on
PATH(Inspector is loaded vianpx; see the Inspector repo for supported versions) uvonPATH(used bymcp devfor an isolated env)FACEIT_API_KEYavailable to the server (e.g. via.envat the repo root, loaded byconfig.py)
Launch (venv active so mcp resolves):
source .venv/bin/activate
mcp dev src/faceit_mcp/server.py:mcp --with-editable .
Or call the binary directly:
./.venv/bin/mcp dev src/faceit_mcp/server.py:mcp --with-editable .
What happens
uvcreates a temporary environment and installs this project in editable mode.- The
mcpinstance insrc/faceit_mcp/server.pyloads. - The Inspector UI is served (typically
http://localhost:6274/; proxy on:6277). Open the printed URL (includesMCP_PROXY_AUTH_TOKEN) or paste the token into the UI.
Smoke sequence in the UI
- Connect (often automatic).
- Open Tools — you should see all 64
faceit_*tools with full descriptions. - Try:
faceit_getAllGames→faceit_searchPlayers(nickname: "s1mple") →faceit_getPlayer→faceit_getPlayerLifetimeStats/faceit_getPlayerRecentMatchStatsto compare aggregates vs per-match stats.
Stop with Ctrl+C in the terminal.
Troubleshooting
- 401: Missing or invalid
FACEIT_API_KEY— check.envor export the variable beforemcp dev. ImportError: attempted relative import with no known parent package: Use currentserver.pywith absolute imports, or reinstall withpip install -e ..EADDRINUSEon 6274/6277: Another Inspector is running — stop it orpkill -f '@modelcontextprotocol/inspector'.
Alternative: Inspector via npx
You can run the Inspector package directly; it spawns your server as a child process. Replace the Python path with your venv or use faceit-mcp if it is already on PATH:
npx @modelcontextprotocol/inspector -e FACEIT_API_KEY=YOUR_KEY_HERE -- /absolute/path/to/faceit-mcp/.venv/bin/python -m faceit_mcp
npx @modelcontextprotocol/inspector -e FACEIT_API_KEY=YOUR_KEY_HERE -- faceit-mcp
Open the URL printed in the terminal (it includes the proxy session token), then use Tools to list and call faceit_* tools.
Use in Cursor, Claude Desktop, or Claude Code
All of these clients use the same shape of stdio config: a command, optional args, and environment variables. The server does not open its own network port for MCP.
Cursor
Put this server in user MCP config only, not in the project’s .cursor/mcp.json. The FACEIT API key belongs in env next to the server entry; workspace files are easy to commit, share, or check into git by mistake. User config stays on your machine and keeps the secret out of the repo.
- Open Cursor Settings → MCP (or edit the JSON manually).
- Edit user config:
- macOS / Linux:
~/.cursor/mcp.json - Windows:
%USERPROFILE%\.cursor\mcp.json
- macOS / Linux:
Merge the faceit block into the existing mcpServers object if you already have other servers.
Recommended (PyPI) — uvx creates an isolated environment when Cursor starts the server:
{
"mcpServers": {
"faceit": {
"command": "uvx",
"args": ["faceit-mcp"],
"env": {
"FACEIT_API_KEY": "YOUR_KEY_HERE"
}
}
}
}
If faceit-mcp is already on PATH:
{
"mcpServers": {
"faceit": {
"command": "faceit-mcp",
"env": {
"FACEIT_API_KEY": "YOUR_KEY_HERE"
}
}
}
}
Local clone — point command at the venv script:
{
"mcpServers": {
"faceit": {
"command": "/absolute/path/to/faceit-mcp/.venv/bin/faceit-mcp",
"env": {
"FACEIT_API_KEY": "YOUR_KEY_HERE"
}
}
}
}
Local uvx without PyPI:
{
"mcpServers": {
"faceit": {
"command": "uvx",
"args": ["--from", "/absolute/path/to/faceit-mcp", "faceit-mcp"],
"env": { "FACEIT_API_KEY": "YOUR_KEY_HERE" }
}
}
}
After saving, enable the faceit server in the MCP panel if it is not already on. New chats in Agent mode can then use the FACEIT tools.
If you use a dev container or remote SSH, Cursor may resolve command on the remote side; still keep the entry in user mcp.json so the key is not stored in the project. See Cursor’s docs for how MCP runs in your setup.
Claude Desktop
- Quit Claude Desktop completely.
- Edit the MCP config file for your OS (create it if missing):
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
- Merge a
mcpServersentry with the same JSON shape as in the Cursor examples above (for exampleuvx+faceit-mcpandFACEIT_API_KEYinenv). - Start Claude Desktop again; the FACEIT tools should appear under MCP for supported conversations.
Claude Code
Prefer user scope (or the equivalent global config) so FACEIT_API_KEY is not stored in a committed project file. Example:
claude mcp add --transport stdio --scope user --env FACEIT_API_KEY=YOUR_KEY_HERE faceit -- uvx faceit-mcp
--scope user keeps the definition (and env) in user config rather than a project .mcp.json you might commit. See Connect Claude Code to tools via MCP.
Development
- Hand-written code:
src/faceit_mcp/{server,client,config,errors}.pyandsrc/faceit_mcp/__main__.py— safe to edit. - Generated code: everything under
src/faceit_mcp/tools/comes fromscripts/generate_tools.py— do not edit by hand. See AGENTS.md for the full workflow (hints, overrides, regeneration, and the tool-count smoke test). - Setup: clone the repo, create a venv,
pip install -e .oruv pip install -e ., copy.env.exampleto.env, setFACEIT_API_KEY. - Manual QA: run
mcp dev src/faceit_mcp/server.py:mcp --with-editable .or thenpx @modelcontextprotocol/inspectorcommands above and exercise a few tools against the real API. - Publishing / versioning: see Publishing to PyPI below.
There is no bundled pytest/ruff config yet; the smoke snippet in the Run (stdio) section above is the lightweight regression check documented in AGENTS.md.
Dev container (e.g. TypeScript repo)
Add Python to the container and install the MCP package once. Configure Cursor user ~/.cursor/mcp.json (not a tracked workspace file) with "command": "/opt/faceit-mcp/bin/faceit-mcp" or "faceit-mcp" once that binary is on PATH in the environment where Cursor launches MCP—same rule as above: do not put FACEIT_API_KEY in a project-level .cursor/mcp.json that could be committed.
Example .devcontainer/devcontainer.json fragment — a venv under /opt avoids Debian PEP 668 “externally managed environment” issues:
{
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
"features": {
"ghcr.io/devcontainers/features/python:1": {
"version": "3.11"
}
},
"postCreateCommand": "python3 -m venv /opt/faceit-mcp && /opt/faceit-mcp/bin/pip install -U pip faceit-mcp"
}
Supply FACEIT_API_KEY only in user Cursor MCP env, containerEnv, or a gitignored devcontainer.env — never commit real keys.
For MCP running inside the container, installing faceit-mcp in postCreateCommand is more reliable than assuming uvx on the host. Alternatively, keep a Node-only image and use uvx faceit-mcp if your setup launches MCP where Python is available.
Publishing to PyPI (maintainers)
-
PyPI account and an API token (or trusted publishing from GitHub).
-
Bump
versioninpyproject.tomlfor each release. -
Build and upload:
uv build UV_PUBLISH_TOKEN=pypi-xxxxxxxx uv publish
Or:
python -m buildandtwine upload dist/*. -
After the first upload, the PyPI-based Cursor snippets work for everyone.
Project on PyPI: faceit-mcp — if the name is taken, rename [project] name in pyproject.toml and update docs.
Tool catalogue (64 tools, 13 tags)
| Tag | Count | Highlights |
|---|---|---|
| Championships | 5 | getChampionships, getChampionshipMatches, getChampionshipResults |
| Games | 8 | getAllGames, getGame, getQueuesByEntityFilters |
| Hubs | 6 | getHub, getHubMatches, getHubMembers |
| Leaderboards | 7 | getHubRanking, getHubSeasonRanking, getChampionshipGroupRanking |
| Leagues | 3 | getLeagueById, getLeagueSeason, getPlayerForLeagueSeason |
| Matches | 2 | getMatch, getMatchStats |
| Matchmakings | 1 | getMatchmaking |
| Organizers | 6 | getOrganizer, getOrganizerChampionships, getOrganizerTournaments |
| Players | 9 | getPlayer, getPlayerFromLookup, getPlayerLifetimeStats, getPlayerRecentMatchStats, getPlayerHistory |
| Rankings | 2 | getGlobalRanking, getPlayerRanking |
| Search | 7 | searchPlayers, searchTeams, searchChampionships, … |
| Teams | 3 | getTeam, getTeamStats, getTeamTournaments |
| Tournaments | 5 | getTournament, getTournamentBrackets, getTournamentMatches |
Tools are registered with a faceit_ prefix, e.g. faceit_getPlayer. The two operations that shared getPlayerStats in Swagger are:
faceit_getPlayerLifetimeStats— career aggregates (GET /players/{player_id}/stats/{game_id})faceit_getPlayerRecentMatchStats— paginated per-match stats (GET /players/{player_id}/games/{game_id}/stats)
Regenerating tools
Generated files under src/faceit_mcp/tools/ are committed and must not be edited by hand.
-
Place an updated
swagger.jsonat the repo root (gitignored). -
Adjust
TAG_HINTSorOPERATION_OVERRIDESinscripts/generate_tools.pyif needed. -
Run:
python scripts/generate_tools.py -
Commit the regenerated modules.
In Cursor you can use the /regenerate-tools command (see .cursor/commands/regenerate-tools.md).
Project layout
faceit-mcp/
├── pyproject.toml
├── uv.lock
├── swagger.json # gitignored; build-time input only
├── scripts/generate_tools.py # swagger.json → tool modules
├── src/faceit_mcp/
│ ├── server.py # FastMCP app + stdio entrypoint
│ ├── client.py # httpx async client + auth + errors
│ ├── config.py # env-based settings
│ ├── errors.py # FaceitAPIError
│ └── tools/ # GENERATED; committed
│ └── <one module per swagger tag>.py
├── AGENTS.md
└── .cursor/commands/regenerate-tools.md
License
The code in this repository is licensed under the terms in LICENSE. The FACEIT Data API, its Swagger specification, and API responses are the property of FACEIT LTD.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file faceit_mcp-0.1.0.tar.gz.
File metadata
- Download URL: faceit_mcp-0.1.0.tar.gz
- Upload date:
- Size: 24.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9904a64570458f08842701168266169ef22709205341f1e5ed600860153ce099
|
|
| MD5 |
bce7d053d4e16ce66ec09d29e83787bc
|
|
| BLAKE2b-256 |
b65ac02319deb79fa4db92cb465595fbae2ca5fa688d5952d707c97468dae2c7
|
File details
Details for the file faceit_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: faceit_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55a5b30e5533bb9f04c89f12aeab4d3ec01950aef3414ba2265a0617e92fb445
|
|
| MD5 |
f7896a8cc296d59dbf27d6f456423fab
|
|
| BLAKE2b-256 |
19c43441181cbddfe7e735755027461a7d7cc2cc0f76548bc3312344477deca3
|