Skip to main content
Glama

Servidor MCP: proveedor modular de comandos

Un servidor FastAPI que expone comandos de terminal arbitrarios —además de calendarios CalDAV, fuentes ICS, repositorios de Gitea y proveedores de notificación— como herramientas reutilizables para un modelo de lenguaje. Los programas CLI se registran colocando un archivo YAML en registry/; las integraciones se activan mediante variables de entorno. El modelo descubre las herramientas disponibles a través del esquema OpenAPI y las invoca mediante endpoints HTTP tipados.

Por qué

  • Independiente del lenguaje – envuelve cualquier script, binario o programa compilado.

  • Autodescriptivo — cada comando lleva un esquema JSON de sus argumentos.

  • DescubribleGET /commands lo lista todo; OpenAPI, en /openapi.json.

  • Ejecución segura — los argumentos se validan contra el esquema antes de ejecutar el comando; un tiempo de espera de 30 s evita bloqueos que nos mantienen.

  • Registro condicional — los endpoints solo existen cuando el servicio que les da soporte está configurado. El LLM nunca ve rutas que devolverían un 404.

  • Clave API opcional — si define MCP_API_KEY, se requiere autenticación en todos los endpoints excepto /api/health y /api/about.

Related MCP server: Graft

Inicio rápido

Los siguientes comandos te guían para empezar:

cd ~/projects/mcp-server
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Optional: set an API key to secure the server
export MCP_API_KEY="your-secret-key"

.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

El servidor queda a la espera en la hora http://127.0.0.1:8000.

Si se define MCP_API_KEY, todos los endpoints excepto /api/health y /api/about requieren una cabecera X-API-Key que coincida con la clave. Si no se define, el servidor arranca en abierto (adecuado para desarrollo local o redes de confianza).

Seguridad de inicio: si no hay nada configurado (ni proveedores de calendario, ni Gitea, ni proveedores de notificación, ni clima, ni comandos registrados), el servidor se niega a arrancar. Al menos una función tiene que estar activada.

Arquitectura

El servidor utiliza un patrón de fábrica (create_app()) que inspecciona las variables de entorno al arrancar y registra los routers de forma condicional para cada integración configurada. Esto significa que el esquema OpenAPI solo contiene los endpoints que van a funcionar de verdad: el LLM nunca descubre rutas que devolverían un 404.

Sistema de proveedores

Las integraciones de calendario (CalDAV e ICS) se implementan como proveedores que implementan un protocolo común. Un provider_registry global mantiene todos los proveedores activos. El router unificado (unified_routes.py) expone /events, /calendars y —cuando ICS está configurado— /calendars/refresh en todos los proveedores. Las operaciones de escritura (crear, actualizar y eliminar eventos) solo se registran cuando existe un proveedor editable (es decir, CalDAV con CALDAV_EDITABLE_CALENDAR definida).

Trabajos en segundo plano

Un pequeño planificador de trabajos (jobs.py) ejecuta tareas periódicas en segundo plano durante toda la vida de la aplicación. Actualmente se usa para renovar la caché de ICS. Su estado se puede consultar en GET /jobs.

API

Los endpoints se registran de forma condicional según la configuración. La tabla siguiente muestra todos los endpoints posibles; solo están presentes los correspondientes a las funciones configuradas.

Núcleo (siempre presente)

Method

Path

Description

GET

/api/health

Puesta en vivo (no autenticado)

GET

/api/about

Nombre y version del servidor (no autente)

GET

/commands

Lista todos los comandos registrados

GET

/commands/{name}

Obtiene el esquema de un comando

GET

/validate

Valida todos los archivos del registro (informe detallado)

GET

/jobs

Muestra el estado de los trabajos periódicos en segundo plano

POST

/{command}

Ruta dedicada a cada comando del registro (auto-generada)

Calendario (si CalDAV o ICS está configurado)

Method

Path

Description

GET

/events

Lista los eventos de todos los proveedores de calendario

GET

/events/{uid}

Obtiene un único evento por UID

GET

/calendars

Lista los calendarios accesibles con metadatos

POST

/calendars/refresh

Refresca la caché de ICS (cuando hay ICS)

POST

/events

Crea un evento (solo con proveedor editable)

PUT

/events/{uid}

Actualiza un evento (solo con proveedor editable)

DELETE

/events/{uid}

Elimina un evento (solo con proveedor editable)

Tareas CalDAV (cuando CalDAV está configurado)

Method

Path

Descripción

GET

/tasks

Lista las tareas de calendario (VTODO)

GET

/tasks/{uid}

Obtiene una tarea por su UID

POST

/tasks

Crea una tarea (solo con proveedor editable)

PUT

/tasks/{uid}

Actualiza una tarea (solo con proveedor editable)

DELETE

/tasks/{uid}

Elimina una tarea (solo con proveedor editable)

Gitea (cuando GITEA_URL está configurado)

Method

Path

Descripción

GET

/repos/{owner}/{repo}

Muestra la información de un repositorio

GET

/user/repos

Lista los repositorios accesibles

GET

/repos/{owner}/{repo}/commits

Lista los últimos commits

GET

/repos/{owner}/{repo}/compare

Compara dos referencias (tools extra)

GET

/issues

Lista de issues (repositorio por defecto u owner/repo)

GET

/issues/{index}

Obtiene un issue por su índice

POST

/issues

Crea un issue nuevo

PATCH

/issues/{index}

Modifica un issue (p. ej., cerrarlo)

GET

/issues/{index}/comments

Lista los comentarios de un issue

POST

/issues/{index}/comments

Comenta un issue

GET

*/branches

Lista las ramas (repositor por defecto u owner/repo)

POST

/branches

Crea una nueva rama

PUT

/branches

Actualiza una rama

DELETE

/branches/{name}

Elimina una rama

GET

/prs

Lista las pull requests

POST

/prs

Crea una pull request

GET

/prs/{index}

Obtiene una PR determinada

PATCH

/prs/{index}

Actualiza una PR (p. ej., cerrarla)

POST

/prs/{index}/merge

Fusiona una pull request

GET

/prs/{index}/reviews

Lista las revisiones de una PR (tools extra)

POST

/prs/{index}/comments

Comenta en una PR

GET

/actions

Muestra las ejecuciones de CI workflows

GET

/commits/{sha}/statuses

Obtiene los checks de estado de CI (tools extra)

GET

/releases

Lista las releases

POST

/releases

Crea una release

GET

/releases/{release_id}

Obtiene una release

PATCH

/releases/{release_id}

Actualiza una release

DELETE

/releases/{release_id}

Elimina una release

Extra tools: /repos/.../compare, /prs/{index}/reviews y /commits/{sha}/statuses están ocultos del esquema OpenAPI por defecto para reducir el recuento de tokens. Defina MCP_GITEA_EXTRA_TOOLS=1 para exponerlos.

Notificación (cuando Discord o Ntfy está configurado)

Método

Nome de la ruta

Descripción

POST

/notify

Envía una notificación a los proveedores configurados

Clima (cuando WEATHER_LOCATION está definido)

Método

Ruta

Descripción

GET

/weather

Condiciones actuales y previsión a varios días

Ejemplo

# List available commands
curl http://127.0.0.1:8000/commands

# Execute the `log` command (dedicated route — the only way to run it)
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Server started"}'

Response:

{"stdout": "[2026-01-15T10:30:00-0500] [INFO] Server started\n", "stderr": "", "exit_code": 0, "success": true}
...

Si hay una clave API, inclúyela en la libreta:

curl -H "X-API-Key: your-secret-key" http://127.0.0.1:8000/commands

Validar el registro

Antes de reiniciar el servidor tras editar los archivos del registro, puede validarlos; igual que caddy validate hace con la configuración de Caddy.

CLI

Salida

python -m app.validate

También puedes indicar un directorio de registro distinto:

python -m app.validate /path/to/registry

Output:

MCP Server registry validation: /app/registry

  ✓ log.yaml → log
  ✓ log_read.yaml → log_read
  ✗ broken.yaml: mapping values are not allowed here
  ⚠ noprogram.yaml → noprogram: Executable not found: /usr/bin/nonexistent

  4 file(s) checked · 1 error(s) · 1 warning(s)

  Registry has errors — fix them before restarting.

Códigos de salida:

  • 0 — todos los archivos est; canutos son válidos (las advertencias no importan)

  • 1 — uno o más archivos tienen errores

  • 2 — el directorio del registro no existe

HTTP

curl http://127.0.0.1:8000/validate

Devuelve un informe en JSON con el resultado por archivo, incluida detección de nombres duplicados y comprobación de que los ejecutables existen.

Registrar una orden

Crear un archivo en registry/ (p. ej., my_tool.yaml):

name: my_tool
description: Does something useful.
executable: /usr/local/bin/my_tool
# (relative paths like scripts/my_tool.sh are resolved against
#  the project root, so they work in any clone or Docker image)
args:
  - name: input
    type: string
    required: true
    help: Path to the input file.
  - name: --verbose
    type: flag
    required: false
    help: Enable verbose output.
  - name: --mode
    type: string
    required: false
    choices: [fast, slow]
    help: Execution mode.

Spec de campo de los argumentos

Campo

Tipo

Notas

name

string

Ruta (posicion) place holders o nombre de la opción --flag.

type

string

string, int, float, bool o flag.

required

bool

Por defecto false.

choices

list

Lista optativa de valores permitidos.

default

any

Valor por defecto opcional, que se aplica automáticamente si el llamador omite este argumento.

help

string

Descripción legible para humanos.

field_name

string

Nombre opcional (limpio) para el parámetro del tema entre la herramienta original. Si se establece, se convierte en el nombre de la propiedad OpenAPI (p. ej. title en lugar de -t). El name original se sigue usando como opción de la línea de comando.

hidden

bool

Cuando es true, el argumento es invisible en la superficie de la herramienta, pero se aplicará siempre su valor default (que debe estar establecido). Sirve para flags que siempre se deben pasar pero que nunca deben controlarse por el modelo.

El tipo flag indica solo presencia (sin valor): el nombre del flag se añade a la línea de comandos dependiendo únicamente de que el argumento sea truthy.

Comendos condicionados (requires)

Los comandos pueden pos summary:

requires:
  - "MCP_LOG_ENABLED != false"

Esto se usa en log and log_read para desaparecer cuando el logging está desactivado por MCP_LOG_ENABLED=false.

Default

Cualquier argumento puede llevar un valor por defecto. Cuando el llamador no incluye ese argumento, el executor lo rellena automáticamente; muy útil para obligar el paso de flags que siempre deben estar activos (por ejemplo, discord.sh -q para modo silencioso):

args:
  - name: -q
    type: flag
    default: true
    help: Quiet mode — forced on by default.

Rutas nativas para los registry commands

Cada comando definido en registry/ se expone automáticamente como su propia ruta FastAPI — POST /{command_name} — con una petición generada por pydantic a partir del schema YAML de argumentos. De este La plataforma puede leer el esquema de OpenAPI y presentar cada comando como una herramienta nativa con parámetros bien tipados (strings, enums, flags, default values).

Estas rutas dedicadas son la única forma de ejecutar comandos del registry — no hay un endpoint genérico POST /execute. Los archivos del registry siguen alimentando GET /commands y GET /validate para que puedas descubrir e inspeccionar comandos, pero la execucución commite en las rutas tipadas pro command.

Los campos desconectados son rechazados (extra: forbid) con una respuesta 422, y si falta un argumento requerido, también devuelve 422.

La clave YAML field_name controla cómo se llama el parámetro en la tool que el modelo ve. Si no se especifica, se usa el name del arg (eliminando los guiones iniciales).

Si el nombre de un comando del registro coincide con una ruta existente (p. ej. events, issues), la ruta dedicada se omite con una advertencia y el comando no se puede ejecutar por HTTP (aunque sigue apareciendo en GET /commands). Renombra el comando en el registro para permitir su ejecución.

Biblioteca del cliente

Un pequeño cliente síncrono basado en httpx se encuentra en app/client.py. Refleja la API HTTP para que un modelo o un script pueda tratar cada comando registrado como una función Python nativa.

from app.client import MCPClient

mc = MCPClient("http://127.0.0.1:8000", api_key="your-secret-key")

# Discover available commands
for cmd in mc.list_commands():
    print(cmd["name"], "-", cmd["description"])

# Execute a command
result = mc.execute("log", message="Server started")
print(result["stdout"])

# Bind a command to a reusable callable
log = mc.tool("log")
log(message="Deploy complete")

Los nombres de las opciones que empiezan con - no son identificadores válidos de Python, así que puedes pasarlos mediante desempaquetado de diccionario: **{"-c": "green"}.

Si el servidor tiene MCP_API_KEY definida, pásale api_key= al cliente: se enviará como X-API-Key en cada petición.

El cliente también funciona como gestor de contexto:

with MCPClient() as mc:
    mc.execute("log_read", lines="10")

El cliente también ofrece métodos de conveniencia tipados para las API de calendario, tareas y Gitea (list_events, create_task, list_issues, etc.).

Estructura del proyecto

mcp-server/
├─ app/
│   ├─ __init__.py            # package marker, resolves version via importlib.metadata
│   ├─ main.py                # FastAPI app factory + conditional router registration
│   ├─ auth.py                # API key authentication dependency
│   ├─ models.py              # Pydantic schemas (commands, args, validation)
│   ├─ executor.py            # validation + subprocess wrapper with timeout
│   ├─ registry.py            # YAML/JSON command loader + validate_registry()
│   ├─ validate.py            # `python -m app.validate` CLI
│   ├─ client.py              # httpx client library (commands + calendar + Gitea API)
│   ├─ registry_routes.py     # Auto-generated native routes for registry commands
│   ├─ caldav_models.py       # Pydantic models for CalDAV events/tasks
│   ├─ caldav_service.py      # CalDAV service (1 editable + N read-only calendars)
│   ├─ caldav_routes.py       # FastAPI router for /tasks (CalDAV-specific)
│   ├─ ics_models.py          # Pydantic models for ICS feed config
│   ├─ ics_service.py         # ICS feed fetcher, parser, cache
│   ├─ ics_routes.py          # ICS service singleton management
│   ├─ unified_routes.py      # Unified /events, /calendars router across providers
│   ├─ provider_adapters.py   # CalDAVProvider, ICSProvider adapters
│   ├─ providers.py           # Global provider registry
│   ├─ gitea_models.py        # Pydantic models for Gitea resources
│   ├─ gitea_service.py       # Gitea API service (issues, PRs, branches, releases)
│   ├─ gitea_routes.py        # FastAPI router for /issues, /prs, /branches, etc.
│   ├─ notify_models.py       # Pydantic models for notifications
│   ├─ notify_service.py      # Discord + Ntfy notify providers
│   ├─ notify_routes.py       # FastAPI router for /notify
│   ├─ weather_models.py      # Pydantic models for weather config
│   ├─ weather_service.py     # Open-Meteo API client
│   ├─ weather_routes.py      # FastAPI router for /weather
│   └─ jobs.py                # Lightweight background job scheduler
├─ registry/                  # command definitions (one file per command)
│   ├─ log.yaml               # logging command
│   └─ log_read.yaml          # read log tail
├─ scripts/                   # helper scripts referenced by registry YAMLs
│   ├─ log.sh                 # append to log file
│   ├─ log_read.sh            # read log tail
│   └─ config.sh.example      # template (unused in Docker; for reference)
├─ tests/                     # pytest test suite
│   ├─ conftest.py
│   ├─ test_models.py
│   ├─ test_executor.py
│   ├─ test_registry.py
│   ├─ test_api.py
│   ├─ test_client.py
│   ├─ test_auth.py
│   ├─ test_caldav.py
│   ├─ test_ics.py
│   ├─ test_ics_recurrence.py
│   ├─ test_gitea.py
│   ├─ test_notify.py
│   ├─ test_weather.py
│   ├─ test_logging.py
│   ├─ test_jobs.py
│   └─ test_conditional_endpoints.py
├─ Dockerfile                 # multi-arch base image definition
├─ LICENSE                    # MIT license
├─ variants/                  # variant Dockerfiles (PHP, Node, etc.)
│   ├─ Dockerfile.php
│   └─ Dockerfile.node
├─ docker-compose.yml         # easy local run with volumes
├─ .env.example               # environment variable template
├─ .dockerignore              # excludes venv, secrets, tests, etc.
├─ pyproject.toml             # package metadata + pytest/ruff config
└─ requirements.txt           # pip dependencies (used by Dockerfile)

Configuración

Toda la configuración se realiza mediante variables de entorno. Consulta .env.example para ver una referencia completa con comentarios. El servidor las lee al arranque y registra los endpoints de forma condicional.

Variable

Funcionalidad

Descripción

MCP_API_KEY

Autenticación

Clave de API para los endpoints (sin definir = acceso abierto)

MCP_REGISTRY_DIR

Registro

Directorio de registro personalizado

MCP_LOG_FILE

Registro

Ruta del archivo de registro

MCP_LOG_DIR

Registro

Directorio de registro (dentro, el archivo es mcp.log)

MCP_LOG_LEVEL

Registro

Nivel de registro (por defecto: INFO)

MCP_LOG_ENABLED

Registro

Establécelo en false para desactivar los comandos de registro

CALDAV_URL

CalDAV

URL del servidor CalDAV

CALDAV_USERNAME

CalDAV

Nombre de usuario de CalDAV

CALDAV_PASSWORD

CalDAV

Contraseña de CalDAV

CALDAV_EDITABLE_CALENDAR

CalDAV

Nombre del calendario editable (sin definir = todo es de solo lectura)

CALDAV_READONLY_CALENDARS

CalDAV

Nombres de calendarios de solo lectura separados por comas

ICS_CALENDAR_URL

ICS

URL de la fuente ICS de solo lectura

ICS_CALENDAR_NAME

ICS

Nombre visible para la fuente ICS

ICS_REFRESH_INTERVAL

ICS

Intervalo de refresco de la caché en segundos (por defecto 300)

GITEA_URL

Gitea

URL del servidor de Gitea

GITEA_TOKEN

Gitea

Token de API

GITEA_DEFAULT_OWNER

Gitea

Propietario del repositorio por defecto

GITEA_DEFAULT_REPO

Gitea

Nombre del repositorio por defecto

MCP_GITEA_EXTRA_TOOLS

Gitea

Exponer endpoints de nicho en el esquema OpenAPI

DISCORD_*_HOOK

Notificaciones

URLs de webhooks de Discord (por nivel de gravedad)

DISCORD_SERVER_NAME

Notificaciones

Anulación del nombre visible del bot

DISCORD_TITLE_SUFFIX

Notificaciones

Sufijo de título para los mensajes de Discord

NTFY_URL

Notificaciones

URL del servidor Ntfy

NTFY_*_TOPIC

Notificaciones

Temas de Ntfy (por nivel de gravedad)

NTFY_TOKEN

Notificaciones

Token de acceso de Ntfy

NTFY_USERNAME / NTFY_PASSWORD

Notificaciones

Autenticación básica de Ntfy

NTFY_TITLE_SUFFIX

Notificaciones

Sufijo de título para los mensajes de ntfy

WEATHER_LOCATION

Meteorología

"lat,long" para los datos meteorológicos

TZ

Servidor

Zona horaria (por defecto UTC)

Calendario CalDAV

El servidor puede conectarse a un servidor CalDAV (p. ej. Radicale, Baikal, Nextcloud) para gestionar eventos y tareas de calendario. El diseño utiliza un calendario editable (donde se pueden crear, actualizar y eliminar eventos y tareas) y varios calendarios de solo lectura (visibles pero no modificables).

Cuando CALDAV_EDITABLE_CALENDAR no está definido, todos los calendarios son de solo lectura y no se registran endpoints de creación/actualización/eliminación.

Todos los eventos y tareas incluyen un indicador editable y un calendar_name, de modo que el modelo puede ver la vista unificada del calendario, pero no correr el riesgo de modificar calendarios que no debería tocar.

Configuración

CALDAV_URL=https://caldav.example.com/dav
CALDAV_USERNAME=user
CALDAV_PASSWORD=secret
# Optional: set to make a calendar writable.  When unset, all calendars
# are read-only and write endpoints are not registered.
#CALDAV_EDITABLE_CALENDAR=MyCalendar
# Optional: comma-separated list of read-only calendar names to include.
# If empty, all calendars except the editable one are included as read-only.
#CALDAV_READONLY_CALENDARS=Personal,Work

Cuando CALDAV_URL no está definida, los endpoints de calendario no se registran.

Features

  • Eventos (VEVENT): listar (con filtrado por rango de fechas), obtener por UID, crear, actualizar y eliminar; se admiten eventos de todo el día y con hora.

  • Tareas (VTODO): listar, obtener por UID, crear, actualizar y eliminar; con gestión de prioridad, fecha de vencimiento y estado.

  • Recuperación de conexión: si el servidor del CalDAV se vuelve inalcanzable a la mitad de una operación, el servicio restablece su conexión automáticamente y reintza una vez. Captura DAVError, ConnectionError, TimeoutError y OSError.

  • Caché de calendarios: la lista de calendarios se obtiene una vez por conexión y se la guarda en caché, evitando así idas y vueltas redundantes al servidor.

  • UUID explícitos: los eventos y tareas creados siempre reciben un uuid4 como UID, lo que garantiza que se puedan actualizar o eliminar de inmediata after creation.

Calendario ICS (solo lectura)

El servidor puede fusionar una fuente de calendario ICS de solo lectura (p. ej. un calendario publicado de Outlook, iCal de Google Calendar) en el endpoint /events, junto con los eventos de CalDAV.

ICS_CALENDAR_URL=https://outlook.office365.com/owa/calendar/.../calendar.ics
ICS_CALENDAR_NAME=Work
ICS_REFRESH_INTERVAL=300  # seconds (default 300, minimum 30)

La fuente de ICS se obtiene y guarda en caché al iniciarse, y luego una tarea en segundo plano la actualiza periódicamente. Usa POST /calendars/refresh para forzar manualmente una actualización de la caché.

Integración con Gitea

El servidor puede conectarse a una instancia de Gitea para gestionar repositorios, issues, pull requests, ramas, releases y acciones de CI. Cuando GITEA_URL no está definida, los endpoints de Gitea no se registran.

Configuración

GITEA_URL=https://git.example.com
GITEA_TOKEN=your-api-token
GITEA_DEFAULT_OWNER=your-username
GITEA_DEFAULT_REPO=your-repo

Los endpoints de incidencias, ramas, PRs y releases aceptan parámetros opcionales de consulta owner y repo, que toman por defecto los valores configurados. Los endpoints de información de repositorio, commits y comparación utilizan rutas parametrizadas (/repos/{owner}/{repo}/...).

Notify

El servidor puede enviar notificaciones a través de webhooks de Discord y/o Ntfy. Puede haber varios proveedores activos a la vez: una llamada a /notify se reenvía a todos los proveedores configurados.

Los webhooks de Discord se configuran por nivel de gravedad (info, notice, critical, emergency). Si un nivel no está configurado, el sistema uscesa al siguiente inferior configurado.

Ntfy funciona de forma similar con temas por nivel de gravedad. La autenticación admite por tokens o auth básica.

Registro

Los comandos log y log_read proporcionan una utilidad de registro simple: añadir mensajes con marca de tiempo a un archivo y leerlos.

# Log a message
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Deploy complete"}'

# Log with a level
curl -X POST http://127.0.0.1:8000/log \
     -H 'Content-Type: application/json' \
     -d '{"message": "Disk full", "level": "error"}'

# Read the last 20 lines
curl -X POST http://127.0.0.1:8000/log_read \
     -H 'Content-Type: application/json' \
     -d '{"lines": "20"}'

La ruta del archivo de registro se determina en este orden de prioridad:

  1. La variable de entorno MCP_LOG_FILE — ruta completa del archivo de registro.

  2. La variable de entorno MCP_LOG_DIR — un directorio; el archivo es mcp.log dentro de él.

  3. Predeterminado: /tmp/mcp/mcp.log.

Los directorios padre se crean automáticamente si no existen.

Establece MCP_LOG_ENABLED=false para desactivar el registro por completo; los comandos log y log_read no se registrarán y sus rutas no existirán.

Docker

El servidor incluye un Dockerfile multarquitectura listo para amd64 y arm64.

Construcción

docker build -t digitaladapt/mcp-server:latest .

Para compilactions multarquitectura (requiere buildx):

docker buildx build --platform linux/amd64,linux/arm64 -t digitaladapt/mcp-server:latest .

Ejecución

docker run -d --name mcp-server -p 8000:8000 \
  --env-file .env \
  -e MCP_API_KEY="your-secret-key" \
  -v ./registry:/app/registry \
  digitaladapt/mcp-server:latest

O con docker compose:

docker compose up -d

Volumenes

Mount

Finalidad

/app/registry

Definiciones de comandos: anular o ampliar en tiempo de ejecución.

/tmp/mcp

Localización por defecto del archivo de registro (o establece MCP_LOG_FILE).

El directorio scripts/ (incluido log.sh) se incluye dentro de la imagen. Los secretos nunca se incluyen en la imagen; se proporcionan mediante variables de entorno (--env-file .env).

Detalles de la imagen

  • Base: python:3.12-slim (multarquitectura)

  • Dependencias del sistema: curl, jq (para scripts), tini

  • Se ejecuta como: usuario no root mcp (uid 1000)

  • Entrypoint: tini (manejo correcto de señales PID-1)

Compilar variantes (PHP, Node, etc.)

El Dockerfile base está diseñado como base. En la directorio variants/ se encuentran los Dockerfile de las variantes y añaden runtimes extra por encima:

Variante

Dockerfile

Runtime

Comandos de ejemplo

PHP

variants/Dockerfile.php

PHP CLI + curl, mbstring, xml

php_eval

Node.js

variants/Dockerfile.node

Node.js 22 LTS + npm

node_run

Compile a varante (desde la raíz del repositorio):

# PHP
docker build -f variants/Dockerfile.php -t digitaladapt/mcp-server:php .

# Node.js
docker build -f variants/Dockerfile.node -t digitaladapt/mcp-server:node .

Run a variant:

docker run -p 8000:8000 \
  --env-file .env \
  -v ./registry:/app/registry \
  digitaladapt/mcp-server:php

Crea tu propia variante:

# variants/Dockerfile.ruby
FROM digitaladapt/mcp-server:latest
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
    ruby && rm -rf /var/lib/apt/lists/*
USER mcp

Luego añade un registry/ruby_eval.yaml que apunte a /usr/bin/ruby.

Pruebas

El proyecto incluye una suite de pytest completa que cubre modelos, ejecutor, registro, endpoints de API, librería de modelo, autenticación, operaciones CalDAV, análisis ICS, integración con Gitea, notificaciones, meteorología, logs, trabajos en segundo plano y registro de endpoints condicional.

# Install dev dependencies
pip install -e ".[dev]"

# Run the full suite
pytest

# Run with verbose output
pytest -v

# Run a single test module
pytest tests/test_executor.py

La regresión de los valores por defecto de las opciones (por ejemplo, una opción con default: true) está cubierta por test_executor.py::TestValidateAndBuild::test_flag_default_true_*.

La lógica de timeout y terminación del grupo de procesos del ejecutor se prueba en test_executor.py.

Notas de seguridad

  • Solo se pueden ejecutar los comandos presentes en registry/: no existe un endpoint de comandos arbitrarios.

  • Los argumentos se validan (tipo, obligatorios, opciones) antes de lanzar el subproceso, y se rechazan los argumentos desconocidos.

  • Cada comando tiene un timeout fijo de 30 s acompañado de terminación del grupo de procesos.

  • Autenticación por API key — define MCP_API_KEY para exigir la cabecera X-API-Key en todos los endpoints excepto /api/health y /api/about. Sin definir, el servidor queda abierto.

  • Los mensajes de error se saneigen — los detalles internos se registran en el servidor, pero no se exponen en las respuestas HTTP (es importante, porque los errores son devueltas hacia la ventana de contexto del LLM).

  • Ejecuta el servidor con una cuenta de usuario limitada; no le des sudo.

  • Comandos que permiten la introspección del sistema de archivos del servidor o la ejecución de código arbitrario han sido eliminados a propósito — solo deben registrarse comandos específicos y permitidos.


Creado por Lyra — tu asistente de pelo plateado en la esquina. ✨

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

0Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.

  • AI-callable tools for API mocking, testing, monitoring, security, and automation.

  • Verified, pay-per-use API tools for AI agents through one authenticated connection.

  • Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.

View all MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI models to access external services including weather data, file system operations, and SQLite database interactions through a standardized JSON-RPC interface. Features production-ready architecture with security, rate limiting, and comprehensive error handling.
    225
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables building agent-ready APIs that expose tools as both HTTP and MCP endpoints from a single server definition, with automatic OpenAPI, discovery docs, and interactive API reference.
    5
    Apache 2.0

View all related MCP servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/digitaladapt/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server