mcp-prov
README.md
# mcp-prov
Proxy MCP local en Python que envuelve un servidor MCP existente en n8n
(la instancia de aprovisionamiento de Metrotel). Agrega **caché**,
**logging**, **tool compuesta de diagnóstico** y **auth Bearer propio**
sin tocar el backend.
**Imagen en Docker Hub**: [`metrotel/mcp-prov`](https://hub.docker.com/r/metrotel/mcp-prov)
- 🌐 Habla stdio (Claude Code / clients embed) o HTTP (Claude Desktop y otros)
- 🔐 Aísla el token upstream: nunca sale al cliente
- ⚡ Caché in-memory 60s para lecturas idempotentes (config vía env var)
- 📝 Log JSON-lines de cada tool call (`tool`, `args`, `cached`, `duration_ms`, `error`)
- 🛠 Expone las **32 tools upstream** + una tool compuesta `diagnostico_completo`
- ♻️ Re-inicializa sesión si el upstream la cierra (bug conocido de n8n MCP)
- 🚀 Deploy: **Docker** / Docker Swarm / Kubernetes / systemd user unit / standalone Python
- 💾 Volumen `/data` para logs persistentes (y cache futura)
## Por qué existe
El server MCP embebido en el flujo de n8n de Metrotel cierra el long-poll SSE
tras un tiempo de inactividad, y clientes como `mcp-remote` empiezan a hacer
reintentos ruidosos. Además el token upstream vivía en JSONs de config en
claro.
Este proxy:
- **Elimina el long-poll**: cada tool call abre su propia HTTP request al upstream y cierra al terminar.
- **Aísla el token upstream** (`X-Prov-MCP-Key`): vive solo en el env file del proxy, no en Claude Desktop / Claude Code configs.
- **Agrega caché** para las lecturas que se repiten (ej. mismo `contexto_servicio` varias veces en pocos minutos).
- **Agrega una tool compuesta** que encadena varias tools upstream y devuelve un resumen — evita que el modelo tenga que orquestar 3 llamadas cuando puede pedir una sola.
## Requisitos
- Python 3.10+
- [`uv`](https://docs.astral.sh/uv/) (recomendado, o `pip`)
- Acceso de red al server MCP upstream y el header `X-Prov-MCP-Key` válido
## Quickstart
### Docker (recomendado, sin build local)
```bash
docker run -d --name prov-mcp -p 8767:8767 \
-e PROV_MCP_KEY='pmcc_...' \
-e PROV_MCP_AUTH_TOKEN='pmcp_...' \
-v prov-data:/data \
--restart unless-stopped \
metrotel/mcp-prov:0.2.2
```
O con `docker-compose.yml` del repo:
```bash
git clone https://github.com/datacenter-metrotel/mcp-prov.git
cd mcp-prov
cp .env.example .env && chmod 600 .env # editá .env
docker compose up -d
```
Log persistido en el volumen `prov-data` (montado a `/data/logs`):
```bash
docker exec prov-mcp tail -f /data/logs/calls.log
```
### Modo HTTP nativo (sin Docker)
```bash
git clone https://github.com/datacenter-metrotel/mcp-prov.git
cd mcp-prov
cp .env.example .env
chmod 600 .env
# editá .env con los valores reales
# Arrancar en foreground
uvx --from . prov-mcp-proxy
# server escuchando en http://0.0.0.0:8767/mcp
```
Verificar:
```bash
KEY=$(grep '^PROV_MCP_AUTH_TOKEN=' .env | cut -d= -f2)
curl -sS -L -X POST http://127.0.0.1:8767/mcp \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}'
```
### Modo stdio (para Claude Code / Cursor u otros clients que arrancan el proceso)
```bash
export PROV_MCP_KEY='pmcc_...'
export PROV_MCP_TRANSPORT=stdio
uvx --from . prov-mcp-proxy
```
Y en `.mcp.json` (Claude Code):
```json
{
"mcpServers": {
"prov": {
"command": "uvx",
"args": ["--from", "/ruta/al/repo", "prov-mcp-proxy"],
"env": { "PROV_MCP_KEY": "${PROV_MCP_KEY}" }
}
}
}
```
## Deploy en Kubernetes / Docker Swarm
- **Kubernetes** con `envFrom.secretRef` + `PersistentVolumeClaim`:
ver [`k8s/README.md`](k8s/README.md).
- **Docker Swarm** con secrets encriptados en raft + volumen: ver
[`swarm/README.md`](swarm/README.md).
## Deploy como systemd user unit
Template en `systemd/prov-mcp-proxy.service.example`:
```bash
mkdir -p ~/.config/systemd/user ~/.config/prov-mcp-proxy
cp systemd/prov-mcp-proxy.service.example ~/.config/systemd/user/prov-mcp-proxy.service
cp .env.example ~/.config/prov-mcp-proxy/env
chmod 600 ~/.config/prov-mcp-proxy/env
# editá ~/.config/prov-mcp-proxy/env con los valores reales
systemctl --user daemon-reload
systemctl --user enable --now prov-mcp-proxy.service
systemctl --user status prov-mcp-proxy.service
```
Para que sobreviva a reboots sin login:
`sudo loginctl enable-linger $USER`.
## Uso desde Claude Desktop
Editar `claude_desktop_config.json`:
```json
{
"mcpServers": {
"prov": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"http://<HOST_IP>:8767/mcp",
"--allow-http",
"--transport", "http-only",
"--header", "Authorization:Bearer <PROV_MCP_AUTH_TOKEN>"
]
}
}
}
```
Rutas del config:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- Linux (community): `~/.config/Claude/claude_desktop_config.json`
Ver ejemplo completo en `examples/claude_desktop_config.example.json`.
## Variables de entorno
| Variable | Requerida | Default | Descripción |
|---|---|---|---|
| `PROV_MCP_KEY` | ✅ | — | Header `X-Prov-MCP-Key` que se envía al upstream |
| `PROV_MCP_AUTH_TOKEN` | ✅ (si `TRANSPORT=http`) | — | Bearer que los clientes MCP deben mandar en `Authorization` |
| `PROV_MCP_URL` | ❌ | `https://n8n-asegured.metrotel.com.ar/mcp/prov_mcp_cc` | Endpoint upstream |
| `PROV_MCP_TRANSPORT` | ❌ | `stdio` | `stdio` o `http` |
| `PROV_MCP_HTTP_HOST` | ❌ | `127.0.0.1` | Bind del listener HTTP |
| `PROV_MCP_HTTP_PORT` | ❌ | `8767` | Puerto |
| `PROV_MCP_HTTP_PATH` | ❌ | `/mcp` | Path del endpoint |
| `PROV_MCP_CACHE_TTL` | ❌ | `60` | TTL de caché en segundos (0 = off) |
| `PROV_MCP_LOG_DIR` | ❌ | `~/.cache/prov_mcp_proxy` | Directorio del log JSON-lines |
## Tools expuestas
Todas las tools del upstream se re-exponen tal cual (32 al momento de escribir),
más una compuesta:
- `diagnostico_completo(service_number)` — llama `contexto_servicio` →
`Topologia` → (si el subproducto es ISI) `ISI_Check_IP`, y devuelve un
resumen agrupado. Útil como "punto de entrada" para diagnóstico rápido de
un servicio dado su número.
Ver el detalle de las tools upstream en la colección Postman en
[`postman/`](postman/).
## Caché
Tools que **nunca** se cachean (efectos activos o datos volátiles):
- `Ping_tool`
- `ATA_Test_1`, `ATA_Test_2`, `ATA_Test_3`
- `Gestion_ACS`
- `Obtener_backup_equipo`
El resto entra a caché con TTL configurable (default 60s). El key incluye
nombre de tool + hash SHA1 de los argumentos normalizados.
## Log
Cada tool call se registra en `~/.cache/prov_mcp_proxy/calls.log` como una
línea JSON con `ts`, `tool`, `args`, `cached`, `duration_ms`, `error`.
Rotación automática 5 MB × 3.
## Seguridad
Ver [SECURITY.md](SECURITY.md). En resumen:
- Bearer obligatorio en modo HTTP (middleware Starlette).
- Token upstream nunca sale del proxy.
- Env file con creds va con `chmod 600`, fuera de git.
- `.env` en `.gitignore`.
## Licencia
MIT — ver [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues