ctfd-mcp

Servidor MCP para CTFd que permite a usuarios regulares explorar desafíos, gestionar instancias dinámicas y enviar banderas.

Documentación

Servidor MCP de CTFd (ámbito de usuario)

GitHub Release License Python Issues

Servidor MCP que permite a un usuario regular de CTFd listar desafíos, leer detalles, iniciar/detener instancias dinámicas de docker y enviar banderas.

Requisitos

  • Python 3.13 (gestionado por uv).
  • Variables de entorno (elige un método de autenticación):
  • CTFD_URL (p. ej. https://ctfd.example.com)
  • CTFD_TOKEN (token de usuario, no administrador) o CTFD_SESSION (cookie de sesión si los tokens están deshabilitados).
    • CTFD_CSRF_TOKEN (opcional, solo si el servidor/plugin requiere CSRF para ctfd-owl).

Puedes guardarlas en un archivo .env en la raíz del repositorio:

CTFD_URL=https://ctfd.example.com/
CTFD_USERNAME=your_username
CTFD_PASSWORD=your_password
# or, if you prefer to use a token:
# CTFD_TOKEN=your_ctfd_api_token_here
# or, if tokens are disabled:
# CTFD_SESSION=your_session_token_here
# and, if the owl plugin enforces CSRF:
# CTFD_CSRF_TOKEN=your_csrf_token_here

Instalación

  • Desde PyPI (recomendado): uvx ctfd-mcp --help
  • Desde el código fuente (sin instalación): uvx --from . ctfd-mcp --help

Ejecutar el servidor MCP (stdio)

# installed from PyPI
uvx ctfd-mcp
# from local checkout
uvx --from . ctfd-mcp

Ejemplo de configuración MCP para Cursor y Claude

{
  "mcpServers": {
    "ctfd-mcp": {
      "command": "uvx",
      "args": ["ctfd-mcp"],
      "env": {
        "CTFD_URL": "https://ctfd.example.com",
        "CTFD_TOKEN": "your_user_token"
      }
    }
  }
}

Ejemplo de configuración MCP para Codex

[mcp_servers.ctfd-mcp]
command = "uvx"
args = ["ctfd-mcp"]

[mcp_servers.ctfd-mcp.env]
CTFD_URL = "https://ctfd.example.com"
CTFD_TOKEN = "your_user_token"

Herramientas expuestas

  • list_challenges(category?, only_unsolved?) — lista los desafíos visibles, con filtro opcional por categoría/no resueltos.
  • challenge_details(challenge_id) — descripción (HTML + description_text), metadatos, URLs de adjuntos, estado de resolución.
  • submit_flag(challenge_id, flag) — intenta una bandera; devuelve estado/mensaje.
  • start_container(challenge_id) — inicio unificado; detecta automáticamente dynamic_docker, ctfd-owl o k8s /api/v1/k8s.
  • stop_container(container_id?, challenge_id?) — detención unificada; whale se puede detener solo con container_id, owl/k8s necesitan challenge_id.

Los adjuntos se devuelven como URLs absolutas en files; el cliente/host puede obtenerlos directamente.

Recursos MCP

  • resource://ctfd/challenges/{challenge_id} — instantánea en markdown de un desafío (metadatos, descripción, URLs de adjuntos, información de conexión si está presente).

Manejo de errores

  • Falta de env/config -> error MCP claro.
  • 401/403 -> autenticación fallida, verifica el token o la cookie de sesión.
  • 404 -> no encontrado (o API de contenedor dinámico ausente).
  • 429 -> límite de velocidad alcanzado (Retry-After si está presente).
  • Otros errores HTTP/API -> se muestran como errores MCP con mensaje/estado de CTFd.

Notas y solución de problemas

  • Los contenedores dinámicos requieren el plugin ctfd-whale (dynamic_docker) en el CTFd de destino; de lo contrario, /api/v1/containers devuelve 404.
  • Los desafíos Owl (dynamic_check_docker) usan un endpoint diferente: /plugins/ctfd-owl/container?challenge_id=<id>. Generalmente requieren una cookie de sesión, y algunas configuraciones requieren un token CSRF; establece CTFD_CSRF_TOKEN si es necesario.
  • Algunos eventos exponen instancias respaldadas por Kubernetes en /api/v1/k8s/{get,create,delete} con datos de formulario multipart; el cliente intentará estos cuando el tipo de desafío incluya k8s (o cuando falte un endpoint dynamic_docker).
  • Si el servidor te redirige a /login (302) al usar un token, cambia a una cookie de sesión del navegador: establece CTFD_SESSION desde la cookie session después de iniciar sesión.
  • El cliente ahora admite iniciar sesión con CTFD_USERNAME y CTFD_PASSWORD; estos campos tienen prioridad sobre tokens/sesiones obsoletos.
  • Prioridad de autenticación: nombre de usuario/contraseña primero, luego token, luego cookie de sesión. Las credenciales de menor prioridad se ignoran cuando hay una opción de mayor prioridad presente.

Soporte / comentarios

Si algo falla o tienes preguntas, contacta:

Pruebas

  • Ejecuta uv run pytest.
  • Los tiempos de espera son configurables mediante env: CTFD_TIMEOUT (total), CTFD_CONNECT_TIMEOUT, CTFD_READ_TIMEOUT (segundos). Los valores predeterminados son 20s total / 10s conexión / 15s lectura.

Desarrollo

  • Dependencias de desarrollo: uv sync --group dev
  • Lint/formato: uv run ruff check . y uv run ruff format .
  • Pruebas: uv run pytest
  • Pre-commit: uv run pre-commit install (ver CONTRIBUTING.md)

Licencia

Apache-2.0. Ver LICENSE.