Klipper MCP Server
# 🔌 Klipper MCP Server
**Servidor Model Context Protocol de nivel industrial para el ecosistema Klipper / Moonraker.**
[](#)
[](LICENSE)
[](#requisitos-técnicos)
[](https://modelcontextprotocol.io)
`klipper-mcp-server` expone, mediante una API uniforme (tools, resources
y prompts), las capacidades necesarias para que clientes LLM (Claude,
GPT, Cursor, VS Code) operen sobre el stack Klipper + Moonraker con
garantías industriales de resiliencia, observabilidad, seguridad y
**rendimiento extremo**.
---
## 📑 Tabla de contenidos
1. [Estado del proyecto](#-estado-del-proyecto)
2. [Descripción y propósito](#-descripción-y-propósito)
3. [Casos de uso](#-casos-de-uso)
4. [Optimizaciones de rendimiento](#-optimizaciones-de-rendimiento)
5. [Requisitos técnicos](#-requisitos-técnicos)
6. [Instalación y puesta en marcha](#-instalación-y-puesta-en-marcha)
7. [Configuración](#-configuración)
8. [Manual de uso](#-manual-de-uso)
9. [Benchmarks y perfilado](#-benchmarks-y-perfilado)
10. [Contribuir](#-contribuir)
11. [Créditos y financiación](#-créditos-y-financiación)
12. [Contacto](#-contacto)
13. [Licencia](#-licencia)
---
## 📌 Estado del proyecto
> **Importante:** el repositorio contiene actualmente la
> **especificación técnica v0.1**
> ([`docs/mcp-klipper.md`](docs/mcp-klipper.md)) como fuente única de
> verdad. Dicha especificación incluye la implementación de referencia
> del núcleo y los contratos de tools, resources, prompts, agentes y
> skills. El código ejecutable se genera a partir de ella.
>
> Las optimizaciones de rendimiento descritas en la
> [sección 4](#-optimizaciones-de-rendimiento) están **especificadas y
> diseñadas**; sus objetivos son metas de ingeniería verificables
> mediante el arnés de benchmark incluido en el plan de medida. Los
> valores de línea base deben capturarse en CI antes de certificar la
> mejora (ver [Benchmarks](#-benchmarks-y-perfilado)).
| Campo | Valor |
|---|---|
| Artefacto | `klipper-mcp-server` |
| Versión | 0.1.0 (baseline) · optimización objetivo v0.2 |
| Protocolo | MCP 2026-07-28 (stateless core) |
| Runtime | Python ≥ 3.10 · asyncio · aiohttp |
| Licencia | GPLv3 |
---
## 🎯 Descripción y propósito
### El problema
El desarrollo de extensiones para Klipper y plugins para Moonraker
presenta tres barreras recurrentes:
1. **Reglas de oro no verificables automáticamente**: muchas
contribuciones fallan en revisión por usar `time.sleep()`,
variables globales o I/O síncrono en callbacks del reactor.
2. **Errores silenciosos de configuración**: `SAVE_CONFIG` solo escribe
en `printer.cfg`; los parámetros auto-calibrados en includes
provocan fallos de arranque difíciles de diagnosticar.
3. **Ausencia de tooling LLM-aware**: los asistentes genéricos no
disponen de contexto estructural del ecosistema Klipper/Moonraker.
### La solución
Un servidor MCP que actúa como **capa de abstracción tipada** entre el
cliente LLM y:
- La API REST/JSON-RPC de Moonraker.
- El sistema de archivos de configuración Klipper.
- El log de eventos de Klipper (`klippy.log`).
- Validadores AST y plantillas canónicas de código conforme.
### Objetivos principales
- **Contratos verificables**: cada tool valida su entrada contra schema
y devuelve resultados deterministas.
- **Resiliencia activa**: circuit breaker por fábrica, cache con purga
periódica y detector de anomalías EWMA con histéresis.
- **Seguridad por defecto**: comandos G-code peligrosos requieren
`confirm=True`; las API keys nunca se registran en logs.
- **Rendimiento extremo**: cache multinivel, coalescencia de peticiones
y economía de tokens (ver [sección 4](#-optimizaciones-de-rendimiento)).
- **Asincronía estricta**: el event loop nunca se bloquea.
### Capacidades entregadas (v0.1)
| Categoría | Cantidad | Descripción |
|---|---:|---|
| Tools | 17 | Herramientas invocables por el modelo |
| Resources | 8 | Recursos direccionables (URIs) |
| Prompts | 10 | Plantillas de interacción predefinidas |
| Agentes | 3 | System prompts especializados |
| Skills | 3 | Guías ejecutables con checklist |
| Core | 6 | Cache multinivel, single-flight, circuit breaker, EWMA, cliente Moonraker, token budget |
---
## 🧩 Casos de uso
1. **Validación offline de configuración**: comprobar `printer.cfg` y
todo su sistema de `[include]` antes de reiniciar la impresora,
detectando parámetros auto-calibrados mal ubicados.
2. **Desarrollo de extras y componentes**: generar plantillas canónicas
y validar con el linter AST que se respetan las reglas del reactor.
3. **Diagnóstico asistido**: analizar `klippy.log` y telemetría con
prompts especializados y detección de anomalías.
4. **Operación controlada**: ejecutar G-code con salvaguardas para
comandos peligrosos (movimientos, calibración, cambios de estado).
5. **Telemetría y SLO**: exponer latencias, hit-rate de cache y estado
del circuit breaker para integrarlos en observabilidad.
---
## ⚡ Optimizaciones de rendimiento
Las siguientes técnicas están especificadas en
[`docs/mcp-klipper.md`](docs/mcp-klipper.md) (§6.2 y §6.6) y son las que
habilitan los objetivos medibles del proyecto.
| Área | Técnica | Archivo | Beneficio |
|---|---|---|---|
| Cache | **Multinivel L1 (RAM) + L2 (disco)** con doble cota (entradas y bytes) | `cache.py` | Reduce latencia de acceso y persistencia entre reinicios |
| Concurrencia | **Single-flight** (coalescencia de peticiones idénticas) | `coalescer.py` | Elimina el *cache stampede*; N llamadas → 1 a Moonraker |
| Red | **Pool de conexiones** persistente (keep-alive, DNS cacheado) | `moonraker_client.py` | Menos handshakes TCP/TLS, menor latencia p95 |
| Serialización | **orjson** con fallback a stdlib `json` | `moonraker_client.py` | Serialización/deserialización más rápida |
| Compresión | **zstd/gzip** en tránsito y en reposo | `compression.py` | Menos bytes en red y disco |
| Paralelización | `asyncio.gather(return_exceptions=True)` + semáforo | `moonraker_client.py` | Solapa latencias con aislamiento de fallos |
| Memoria | Cotas duras, purga activa, streaming, referencias débiles | `cache.py` | RSS estable, sin fugas en ejecución prolongada |
| Tokens | Compactación, delta `unchanged`, rotación O(1) | `token_budget.py` | Menos tokens por respuesta, sin sobrecarga |
| Arranque | **Lazy loading** memoizado | `resources/`, `prompts/` | Menor tiempo de arranque y RSS en reposo |
### Objetivos declarados (metas, no resultados medidos)
| Objetivo | Meta | Métrica |
|---|---|---|
| Reducción de latencia (p50/p95) | ≥ 60 % vs línea base v0.1 | PERF-1…3 |
| Consumo de recursos (CPU/RAM) | ≤ 30 % de los máximos v0.1 | PERF-6…7 |
| Hit-rate combinado L1+L2 | ≥ 95 % | PERF-4 |
| Throughput | ≥ 250 req/s | PERF-5 |
| Bloqueo del event loop | 0 | PERF-8 |
> La metodología completa de perfilado y medición está en
> [§6.6.6 de la especificación](docs/mcp-klipper.md) y en
> [Benchmarks y perfilado](#-benchmarks-y-perfilado).
---
## 🛠 Requisitos técnicos
| Componente | Versión mínima | Versión recomendada | Notas |
|---|---|---|---|
| Python | 3.10 | 3.11 | 3.10 · 3.11 · 3.12 soportadas |
| Klipper | Últimas 2 stable | stable | También `dev` |
| Moonraker | Últimas 2 stable | stable | API REST/JSON-RPC accesible |
| aiohttp | ≥ 3.9 | última 3.x | Cliente HTTP asíncrono |
| mcp | ≥ 2.3 | última 2.x | SDK MCP (`mcp.server.mcpserver.MCPServer`) |
| orjson | ≥ 3.9 (opcional) | última | Fallback automático a `json` |
| zstandard | ≥ 0.22 (opcional) | última | Fallback automático a `gzip` |
| uv | ≥ 0.4 | última | Gestor de entorno recomendado |
Herramientas de desarrollo:
| Herramienta | Uso |
|---|---|
| `pytest` + `pytest-asyncio` | Tests unitarios e integración |
| `pytest-benchmark` | Micro-benchmarks reproducibles |
| `ruff` | Lint y formato |
| `mypy` | Tipado estático |
| `py-spy` / `memray` | Perfilado de CPU y memoria |
| `locust` / `vegeta` | Pruebas de carga y throughput |
Sistemas operativos soportados: **Debian 12**, **Ubuntu 22/24** y
**Raspberry Pi OS**.
---
## 🚀 Instalación y puesta en marcha
### 1. Clonar el repositorio
```bash
git clone https://github.com/<org>/klipper-mcp-server.git
cd klipper-mcp-server
```
### 2. Crear el entorno e instalar dependencias
Se recomienda `uv` por velocidad y reproducibilidad:
```bash
uv venv
# Linux / macOS
source .venv/bin/activate
# Windows (PowerShell)
.\.venv\Scripts\Activate.ps1
# Instalación editable con dependencias de desarrollo y rendimiento
uv pip install -e ".[dev,perf]"
```
Alternativa con `pip` estándar:
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,perf]"
```
### 3. Configurar las impresoras
Cada impresora se declara con dos variables de entorno: la URL de
Moonraker y, opcionalmente, su API key.
```bash
# Linux / macOS
export PRINTER_DEFAULT="http://localhost:7125"
export PRINTER_VORON="http://192.168.1.100:7125"
export PRINTER_VORON_API_KEY="tu-api-key"
# Windows (PowerShell)
$env:PRINTER_DEFAULT = "http://localhost:7125"
$env:PRINTER_VORON = "http://192.168.1.100:7125"
$env:PRINTER_VORON_API_KEY = "tu-api-key"
```
### 4. Arrancar el servidor
```bash
python -m klipper_mcp.server
```
El servidor se comunica por `stdio` con el cliente MCP. Si no se
declara ninguna impresora, se usa `http://localhost:7125` por defecto.
### 5. Verificar la instalación
```bash
pytest tests/ -q
```
---
## ⚙️ Configuración
Todas las variables se leen del entorno y se validan de forma tipada en
`src/klipper_mcp/config.py`.
### Impresoras
| Variable | Descripción | Ejemplo |
|---|---|---|
| `PRINTER_<NAME>` | URL base de Moonraker para la impresora `<NAME>` | `http://192.168.1.100:7125` |
| `PRINTER_<NAME>_API_KEY` | API key opcional (`X-Api-Key`) | `abc123…` |
`<NAME>` se normaliza a minúsculas. Si solo hay una impresora, no es
necesario indicar su nombre en las llamadas.
### Núcleo runtime
| Variable | Default | Descripción |
|---|---|---|
| `MCP_CACHE_SIZE` | `512` | Nº de entradas del cache L1 en memoria |
| `MCP_CACHE_TTL` | `30` | TTL del cache L1 en segundos |
| `MCP_CACHE_DISK` | *(vacío)* | Ruta del cache L2 en disco. Vacío = sin L2 |
| `MCP_CACHE_L2_TTL` | `300` | TTL del cache L2 en segundos |
| `MCP_CB_THRESHOLD` | `5` | Fallos consecutivos antes de abrir el circuit breaker |
| `MCP_CB_RECOVERY` | `30` | Segundos antes de pasar a `HALF_OPEN` |
| `MCP_MAX_CONCURRENCY` | `32` | Concurrencia máxima por host (semáforo) |
| `MCP_TOKEN_BUDGET` | `4000` | Tokens máximos por respuesta |
| `MCP_POLL_INTERVAL` | `2` | Intervalo de polling en segundos |
| `MCP_LOG_LEVEL` | `INFO` | Nivel de logging (`DEBUG`…`CRITICAL`) |
### Ejemplo completo
```bash
export PRINTER_DEFAULT="http://localhost:7125"
export MCP_CACHE_DISK="/var/cache/klipper-mcp"
export MCP_CACHE_TTL="30"
export MCP_CACHE_L2_TTL="300"
export MCP_MAX_CONCURRENCY="32"
export MCP_TOKEN_BUDGET="4000"
export MCP_LOG_LEVEL="INFO"
```
---
## 📖 Manual de uso
### Integración con Claude Desktop
Edita `claude_desktop_config.json`:
```json
{
"mcpServers": {
"klipper": {
"command": "python",
"args": ["-m", "klipper_mcp.server"],
"env": {
"PRINTER_DEFAULT": "http://192.168.1.100:7125",
"PRINTER_DEFAULT_API_KEY": "tu-api-key",
"MCP_CACHE_SIZE": "512",
"MCP_CACHE_TTL": "30"
}
}
}
}
```
### Instalación en TRAE IDE (install link)
TRAE permite instalar un servidor MCP desde un enlace con esquema propio
([documentación oficial](https://docs.trae.ai/ide/mcp-server-install-links)).
El proyecto incluye un generador reproducible en
[`install_link.py`](src/klipper_mcp/install_link.py).
**Formato del enlace:**
```
trae://trae.ai-ide/mcp-import?type=<TYPE>&name=<NAME>&config=<B64_URLENCODED>
```
| Componente | Obligatorio | Descripción |
|---|---|---|
| `trae://trae.ai-ide/mcp-import` | Sí | Esquema y ruta fijos del handler de TRAE |
| `type` | Sí | `stdio` o `http` |
| `name` | No | Nombre del servidor en TRAE |
| `config` | Sí | JSON de configuración en Base64 y URL-encoded |
**Generar el enlace:**
```bash
# Con el script de consola instalado (pip install -e .)
klipper-mcp-install-link --name klipper \
--printer-url http://192.168.1.100:7125
# Equivalente sin instalar el entry point
python -m klipper_mcp.install_link --name klipper \
--printer-url http://192.168.1.100:7125
# Con API key y variables extras (repetible)
klipper-mcp-install-link --name voron \
--printer-url http://192.168.1.100:7125 \
--env PRINTER_VORON_API_KEY=TU_API_KEY \
--env MCP_CACHE_DISK=/var/cache/klipper-mcp
# Emitir un badge Markdown para el README
klipper-mcp-install-link --markdown
```
**Ejemplo de enlace generado:**
```
trae://trae.ai-ide/mcp-import?type=stdio&name=klipper&config=eyJjb21tYW5kIjoicHl0aG9uIiwiYXJncyI6WyItbSIsImtsaXBwZXJfbWNwLnNlcnZlciJdLCJlbnYiOnsiUFJJTlRFUl9ERUZBVUxUIjoiaHR0cDovLzE5Mi4xNjguMS4xMDA6NzEyNSJ9fQ%3D%3D
```
**Importar en TRAE:**
1. Pega el enlace en la barra de direcciones del navegador y pulsa Enter.
2. Confirma en el diálogo del navegador que quieres abrir TRAE.
3. En la ventana **Configure Manually** de TRAE, revisa la configuración
y pulsa **Confirm**.
> **Seguridad:** `config` va codificado en Base64, **no cifrado**. No
> compartas enlaces que incluyan API keys; genera el enlace en local y
> pasa los secretos vía `--env` solo cuando lo vayas a usar.
### Tools
| Tool | Propósito | Ejemplo de invocación |
|---|---|---|
| `validate_config` | Valida `printer.cfg` y sus includes | `{"config_content": "...", "filename": "printer.cfg"}` |
| `lint_extra` | Linter AST de reglas de oro | `{"source_code": "..."}` |
| `generate_extra` | Genera plantilla de extra | `{"name": "mi_extra", "description": "..."}` |
| `get_printer_status` | Estado de la impresora | `{"printer": "voron"}` |
| `query_objects` | Consulta objetos Moonraker | `{"objects": {"print_stats": null}}` |
| `run_gcode` | Ejecuta G-code (con salvaguardas) | `{"script": "G28", "confirm": true}` |
> Consulta la especificación (§7) para el contrato completo de las 17
> tools, sus parámetros y sus valores de retorno.
### Resources
Los recursos se direccionan por URI, por ejemplo:
```
klipper://config/printer.cfg
klipper://logs/klippy.log
klipper://docs/index
```
### Prompts
Plantillas predefinidas para diagnóstico, optimización y generación:
- **Troubleshooting**: análisis guiado de `klippy.log`.
- **Optimización**: tuning de `pressure_advance`, `input_shaper`, etc.
- **Generación**: scaffolding de extras y componentes conforme a las
reglas de Klipper/Moonraker.
### Docker Compose
```bash
# Definir la API key en el entorno del host
export VORON_API_KEY="tu-api-key"
docker compose up --build
```
---
## 📊 Benchmarks y perfilado
El proyecto incluye un arnés offline (`benchmarks/profile_harness.py`)
que ejecuta las operaciones contra un Moonraker simulado
(`tests/harness/sim_moonraker.py`) para eliminar ruido de red.
```bash
# CPU: flamegraph sin instrumentar el proceso
py-spy record -o profile.svg -- python -m klipper_mcp.server
# Línea base de CPU
python -m cProfile -o baseline.prof -m klipper_mcp.server
# Memoria (detección de fugas en ejecución prolongada)
memray run -o mem.bin benchmarks/profile_harness.py
memray flamegraph mem.bin
# Benchmarks reproducibles y comparables en CI
pytest benchmarks/ --benchmark-only --benchmark-json=out.json
```
### Protocolo de medición
1. **Congelar la línea base** en la revisión v0.1 y versionar
`benchmarks/baseline.json`.
2. **Medir la candidata** en el mismo hardware, con el mismo corpus e
idénticas iteraciones.
3. **Comparar** p50/p95/p99, throughput y RSS. Se acepta la candidata
solo si cumple los objetivos y no introduce regresiones > 10 %.
4. **Verificar estabilidad**: soak de 24 h sin crecimiento de RSS
(pendiente ≤ 0.1 %/h) con hit-rate estable.
---
## 🤝 Contribuir
### Estándares de código
- **Estilo**: `ruff` (lint + format) sin errores y `mypy` sin errores.
- **Longitud de línea**: ≤ 80 caracteres.
- **Cabeceras**: todo archivo `.py` incluye cabecera GPLv3.
- **Asincronía**: prohibido `time.sleep()` en código del reactor; usar
mecanismos del reactor o `asyncio`. Sin variables globales mutables.
- **I/O**: nunca bloqueante dentro del event loop.
- **Tipado**: anotaciones en todas las funciones públicas.
### Flujo de trabajo con Git
1. Crea una rama descriptiva desde `main`:
`git checkout -b feat/single-flight-cache`.
2. Realiza commits atómicos siguiendo
[Conventional Commits](https://www.conventionalcommits.org/):
`feat:`, `fix:`, `perf:`, `docs:`, `refactor:`, `test:`.
3. Asegura que los tests y linters pasan antes de subir la rama.
4. Abre un Pull Request hacia `main`.
### Proceso de revisión de Pull Requests
- Al menos **una aprobación** de un maintainer.
- La **CI debe estar en verde** (lint, mypy, tests y benchmarks).
- Todo cambio de rendimiento debe incluir **evidencia de medición**
(JSON de benchmark) y no introducir regresiones > 10 %.
- Los PR deben ser pequeños y con un único propósito.
### Requisitos de pruebas
- Cobertura mínima: **80 %**.
- Tests nuevos obligatorios para toda funcionalidad: casos válidos,
inválidos y de borde.
- Tests de integración con el Moonraker simulado para todo acceso de
red.
- Los tests de rendimiento usan `pytest-benchmark` y no dependen de red
real.
```bash
ruff check src/ tests/
mypy --ignore-missing-imports src/
pytest tests/ -v --cov=src/klipper_mcp --cov-fail-under=80
```
---
## 🙌 Créditos y financiación
### Autores
- **Equipo Klipper MCP Server** — diseño de arquitectura, núcleo runtime
y especificación técnica.
### Agradecimientos
- A los proyectos **Klipper** y **Moonraker** por su documentación
abierta y su ecosistema.
- A la comunidad de **Model Context Protocol** por el estándar y los
SDKs de referencia.
- A los mantenedores de **aiohttp**, **orjson** y **zstandard**.
### Fuentes de financiación
Este proyecto es de desarrollo independiente y no cuenta actualmente con
financiación institucional. Si deseas apoyar su mantenimiento,
contacta con el equipo (ver [Contacto](#-contacto)).
---
## 📬 Contacto
- **Issues y bugs**:
[GitHub Issues](https://github.com/<org>/klipper-mcp-server/issues)
- **Solicitudes de funcionalidad**: usa la plantilla de *feature
request* en el mismo repositorio.
- **Consultas generales y seguridad**: escribe a
`maintainers@klipper-mcp.dev`.
Por favor, reporta vulnerabilidades de forma **privada** y no abras un
issue público hasta que se haya evaluado el impacto.
---
## 📄 Licencia
Este proyecto se distribuye bajo la **GNU General Public License v3.0**.
Consulta el archivo [LICENSE](LICENSE) para el texto completo.
La elección de GPLv3 garantiza que las mejoras derivadas —incluidas las
optimizaciones de rendimiento— permanezcan disponibles para la comunidad
del ecosistema Klipper/Moonraker.
---
<p align="center">
<sub>Hecho con ❤️ para la comunidad de impresión 3D y agentes LLM.</sub>
</p>
TDQS
Scored across 17 tools
Most tools target distinct resources and actions (config files, validation, server info, runtime status, logs, G-code execution). However, verify_component_loaded vs verify_extra_loaded and get_printer_status vs list_objects/get_print_progress have somewhat overlapping scopes that could cause occasional misselection.
Tool names consistently use snake_case with a predictable verb_noun pattern (get_*, list_*, verify_*, validate_*, run_*). There is no mixed casing or vague naming, making the set easy to scan.
17 tools is slightly above the ideal range but reasonable for a server covering Klipper config validation, Moonraker diagnostics, telemetry, and printer control. Each tool appears to have a distinct purpose, though the surface is on the heavier side.
The server covers reading, listing, searching, validating configs, plus diagnostics, logs, and basic control. However, it lacks config write/update/delete operations and print lifecycle controls like pause/resume/cancel, leaving some common Klipper management workflows incomplete.