freebox-mcp
freebox-mcp
A spec-driven Model Context Protocol server for the Freebox OS API — exposing the entire local API of your Freebox Server to any MCP client (Claude, etc.) as ready-to-call tools.
Every tool is generated from an OpenAPI 3.1 document that is itself auto-generated from the official Freebox documentation (https://dev.freebox.fr/sdk/os/). When Free ships a new API version, a scheduled job on a France-reachable host regenerates the spec; on a change it ships a release automatically — no hand-written tool code to maintain.
Three bricks, one contract
┌── 1. SCRAPER ──┐ ┌──── 2. GENERATOR ────┐ ┌─── 3. GENERATED CLIENT ───┐
official docs ─► tools/cache ─────────► spec/freebox-openapi.json ─► FastMCP.from_openapi() ─► MCP tools
(dev.freebox.fr) (html + objects.inv) (pure Python — no AI) (raw output — no edits)The whole pipeline is deterministic — no AI anywhere. The scraper and generator are pure
Python; the generated client is the verbatim output of FastMCP.from_openapi(spec) — no tool is
hand-added, edited, pre-processed, or post-processed. A CI test (test_tools_are_raw_generated_output)
enforces the last step: every exposed tool must be an operationId from the generated spec, or the
build fails.
The only hand-written code is the authenticated transport the generated client runs on (discovery · HMAC session · TLS · envelope unwrap) — things no API spec can express. It is generic, never edited per-endpoint, and app registration / login live in the CLI, not as injected tools.
Exhaustive — every documented operation across every section (wifi, lan, connection, calls, contacts, downloads, fs, nat, dhcp, vpn server + client, pvr, parental control, airmedia, system, …) becomes a tool.
login(auth handshake) and/ws/(WebSocket) are excluded. Runfreebox-mcp sectionsfor the live list and counts.Self-maintaining — regeneration runs on a France-reachable host (GitHub-hosted runners can't reach
dev.freebox.fr); on a doc change it auto-releases. See Regenerating the spec below.Secure — app-token never leaves your machine, HMAC-SHA1 sessions, TLS verified against the bundled Freebox root CAs,
0600credential store. See SECURITY.md.
Quick start
# 1. Authorize the app on your Freebox (one time — press the button on the box).
uvx freebox-mcp authorize
# 2. Point your MCP client at it (stdio).
uvx freebox-mcpauthorize is a one-time physical confirmation (Freebox anti-hijack design). After it, the
token is saved and every later session opens automatically — you never touch the box again.
MCP client config (Claude Desktop / Claude Code)
{
"mcpServers": {
"freebox": { "command": "uvx", "args": ["freebox-mcp"] }
}
}Docker
docker run -i --rm -v ~/.config/freebox-mcp:/home/app/.config/freebox-mcp \
ghcr.io/nelson-proia/freebox-mcp(The container needs LAN access to the box; on Linux add --network host.)
Run from source, no install
uvx --from git+https://github.com/Nelson-PROIA/freebox-mcp freebox-mcp discoverWhat you can do
Because the whole API is exposed, an LLM can chain real tasks:
List every device on the LAN, then reboot the box.
Set up a port-forward / NAT redirect for a self-hosted service.
Schedule a TV recording on the PVR and manage existing recordings.
Toggle wifi, change the SSID/passphrase, split 2.4/5 GHz bands.
Read live xDSL / FTTH line stats (rate, SNR, attenuation).
Apply per-device parental controls and time schedules.
Configure the built-in VPN server and provision VPN client tunnels.
Manage downloads + RSS feeds, FTP, network shares, Freeplug & switch ports.
CLI
freebox-mcp run the MCP server over stdio (default)
freebox-mcp --http run over streamable-HTTP (--host/--port)
freebox-mcp authorize register the app (press the button on the box)
freebox-mcp login open a session and print granted permissions
freebox-mcp discover print discovery info and the chosen transport
freebox-mcp tools list the generated MCP tools
freebox-mcp sections list API sections + tool counts (values for FREEBOX_SECTIONS)
freebox-mcp call OP [JSON] invoke one operation, e.g. `freebox-mcp call get_system`Configuration
Env var | Default | Purpose |
|
|
|
| — | Force a base URL, e.g. |
| — | Comma list to expose only some sections, e.g. |
| — | Comma list of sections to hide. |
|
| App identity on the box. |
Scoping the sections keeps the tool surface small when you only care about a few areas.
Permissions. Configuration-changing tools need the
settingspermission. Grant it (andparental, etc.) for this app in the Freebox OS web UI: Paramètres ▸ Gestion des accès ▸ Applications — no walking to the box.
Regenerating the spec
python -m tools.build # scrape live docs → parse → emit spec/freebox-openapi.json
python -m tools.build --offline # rebuild from the committed cache (deterministic; what CI verifies)dev.freebox.fr blocks GitHub-hosted runner IPs, so the scrape runs on a France-reachable host
— e.g. a weekly cron on an always-on Raspberry Pi (scripts/regenerate.sh). On a spec change it
bumps the version, tags, and pushes; the GitHub release pipeline (which needs no access to the
docs host) then publishes PyPI + signed GHCR + GitHub Release automatically.
Development
uv sync --group dev
uv run pytest # unit + integration (mocked); add FREEBOX_TEST=1 for live
uv run ruff check . && uv run ruff format .License
MIT — see LICENSE. Not affiliated with Free / Iliad.