ctfd-mcp

Servidor MCP para CTFd que permite que usuários comuns naveguem por desafios, gerenciem instâncias dinâmicas e enviem flags.

Documentação

Servidor MCP CTFd (escopo de usuário)

GitHub Release License Python Issues

Servidor MCP que permite a um usuário comum do CTFd listar desafios, ler detalhes, iniciar/parar instâncias dinâmicas do docker e enviar flags.

Requisitos

  • Python 3.13 (gerenciado por uv).
  • Variáveis de ambiente (escolha um método de autenticação):
  • CTFD_URL (ex.: https://ctfd.example.com)
  • CTFD_TOKEN (token de usuário, não admin) ou CTFD_SESSION (cookie de sessão se os tokens estiverem desabilitados).
    • CTFD_CSRF_TOKEN (opcional, somente se o servidor/plugin exigir CSRF para ctfd-owl).

Você pode armazená-los em um arquivo .env na raiz do repositório:

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

Instalação

  • Do PyPI (recomendado): uvx ctfd-mcp --help
  • Do checkout do código-fonte (sem instalação): uvx --from . ctfd-mcp --help

Executar servidor MCP (stdio)

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

Exemplo de configuração MCP para Cursor e Claude

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

Exemplo de configuração 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"

Ferramentas expostas

  • list_challenges(category?, only_unsolved?) — lista desafios visíveis, com filtro opcional por categoria/não resolvidos.
  • challenge_details(challenge_id) — descrição (HTML + description_text), metadados, URLs de anexos, status de resolução.
  • submit_flag(challenge_id, flag) — tenta uma flag; retorna status/mensagem.
  • start_container(challenge_id) — início unificado; detecta automaticamente dynamic_docker, ctfd-owl ou k8s /api/v1/k8s.
  • stop_container(container_id?, challenge_id?) — parada unificada; whale pode ser parado apenas com container_id, owl/k8s precisam de challenge_id.

Anexos são retornados como URLs absolutas em files; o cliente/host pode buscá-los diretamente.

Recursos MCP

  • resource://ctfd/challenges/{challenge_id} — snapshot em markdown de um desafio (metadados, descrição, URLs de anexos, informações de conexão se presentes).

Tratamento de erros

  • Env/config ausente -> erro MCP claro.
  • 401/403 -> falha de autenticação, verifique token ou cookie de sessão.
  • 404 -> não encontrado (ou API de contêiner dinâmico ausente).
  • 429 -> limite de taxa atingido (Retry-After se presente).
  • Outros erros HTTP/API -> exibidos como erros MCP com mensagem/status do CTFd.

Notas e solução de problemas

  • Contêineres dinâmicos exigem o plugin ctfd-whale (dynamic_docker) no CTFd de destino; caso contrário, /api/v1/containers retorna 404.
  • Desafios Owl (dynamic_check_docker) usam um endpoint diferente: /plugins/ctfd-owl/container?challenge_id=<id>. Eles geralmente exigem um cookie de sessão, e algumas configurações exigem um token CSRF; defina CTFD_CSRF_TOKEN se necessário.
  • Alguns eventos expõem instâncias baseadas em Kubernetes em /api/v1/k8s/{get,create,delete} com dados de formulário multipart; o cliente tentará esses quando o tipo de desafio incluir k8s (ou quando um endpoint dynamic_docker estiver ausente).
  • Se o servidor redirecionar você para /login (302) ao usar um token, mude para um cookie de sessão do navegador: defina CTFD_SESSION a partir do cookie session após fazer login.
  • O cliente agora suporta login com CTFD_USERNAME e CTFD_PASSWORD; esses campos têm precedência sobre tokens/sessões desatualizados.
  • Prioridade de autenticação: usuário/senha primeiro, depois token, depois cookie de sessão. Credenciais de prioridade mais baixa são ignoradas quando uma opção de prioridade mais alta está presente.

Suporte / feedback

Se algo quebrar ou você tiver dúvidas, entre em contato:

Testes

  • Execute uv run pytest.
  • Timeouts são configuráveis via env: CTFD_TIMEOUT (total), CTFD_CONNECT_TIMEOUT, CTFD_READ_TIMEOUT (segundos). Os padrões são 20s total / 10s conexão / 15s leitura.

Desenvolvimento

  • Dependências de desenvolvimento: uv sync --group dev
  • Lint/formatação: uv run ruff check . e uv run ruff format .
  • Testes: uv run pytest
  • Pre-commit: uv run pre-commit install (veja CONTRIBUTING.md)

Licença

Apache-2.0. Veja LICENSE.