Skip to main content

MCP server for CTFd that lets regular users browse challenges, manage dynamic instances, and submit flags.

Project description

CTFd MCP server (user scope)

GitHub Release License Python Issues

MCP server that lets a regular CTFd user list challenges, read details, start/stop dynamic docker instances, and submit flags.

Requirements

  • Python 3.13 (managed by uv).
  • Environment variables (choose one auth method):
  • CTFD_URL (e.g. https://ctfd.example.com)
  • CTFD_TOKEN (user token, not admin) or CTFD_SESSION (session cookie if tokens are disabled).
    • CTFD_CSRF_TOKEN (optional, only if the server/plugin requires CSRF for ctfd-owl).

You can store them in a .env file in the repo root:

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

Install

  • From PyPI (recommended): uvx ctfd-mcp --help
  • From source checkout (no install): uvx --from . ctfd-mcp --help

Run MCP server (stdio)

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

Cursor and Claude MCP config example

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

Codex MCP config example

[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"

Exposed tools

  • list_challenges(category?, only_unsolved?) — list visible challenges, optional category/unsolved filter.
  • challenge_details(challenge_id) — description (HTML + description_text), metadata, attachment URLs, solved status.
  • submit_flag(challenge_id, flag) — attempt a flag; returns status/message.
  • start_container(challenge_id) — unified start; auto-detects dynamic_docker, ctfd-owl or k8s /api/v1/k8s.
  • stop_container(container_id?, challenge_id?) — unified stop; whale can be stopped with just container_id, owl/k8s need challenge_id.

Attachments are returned as absolute URLs in files; the client/host can fetch them directly.

MCP resources

  • resource://ctfd/challenges/{challenge_id} — markdown snapshot of a challenge (metadata, description, attachment URLs, connection info if present).

Error handling

  • Missing env/config -> clear MCP error.
  • 401/403 -> auth failed, check token or session cookie.
  • 404 -> not found (or dynamic container API missing).
  • 429 -> rate limited (Retry-After if present).
  • Other HTTP/API errors -> surfaced as MCP errors with CTFd message/status.

Notes and troubleshooting

  • Dynamic containers require the ctfd-whale (dynamic_docker) plugin on the target CTFd; otherwise /api/v1/containers returns 404.
  • Owl challenges (dynamic_check_docker) use a different endpoint: /plugins/ctfd-owl/container?challenge_id=<id>. They usually require a session cookie, and some setups require a CSRF token; set CTFD_CSRF_TOKEN if needed.
  • Some events expose Kubernetes-backed instances at /api/v1/k8s/{get,create,delete} with multipart form data; the client will try these when the challenge type includes k8s (or when a dynamic_docker endpoint is missing).
  • If the server redirects you to /login (302) when using a token, switch to a browser session cookie: set CTFD_SESSION from the session cookie after logging in.
  • The client now supports logging in with CTFD_USERNAME and CTFD_PASSWORD; these fields take precedence over stale tokens/sessions.
  • Auth priority: username/password first, then token, then session cookie. Lower-priority credentials are ignored when a higher-priority option is present.

Support / feedback

If something breaks or you have questions, reach out:

Testing

  • Run uv run pytest.
  • Timeouts are configurable via env: CTFD_TIMEOUT (total), CTFD_CONNECT_TIMEOUT, CTFD_READ_TIMEOUT (seconds). Defaults are 20s total / 10s connect / 15s read.

Development

  • Dev dependencies: uv sync --group dev
  • Lint/format: uv run ruff check . and uv run ruff format .
  • Tests: uv run pytest
  • Pre-commit: uv run pre-commit install (see CONTRIBUTING.md)

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ctfd_mcp-0.1.2.tar.gz (56.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ctfd_mcp-0.1.2-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

Details for the file ctfd_mcp-0.1.2.tar.gz.

File metadata

  • Download URL: ctfd_mcp-0.1.2.tar.gz
  • Upload date:
  • Size: 56.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ctfd_mcp-0.1.2.tar.gz
Algorithm Hash digest
SHA256 b7e693b113625c03cb523755a24a23bfbd5e7996a129cfb4d104db38fc170c5c
MD5 b0dd299338c1ef46e98da99df8dd5504
BLAKE2b-256 19a43b1f6048bed86815d14df468b21573d06f9c7c07b3710e92a02c863823ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for ctfd_mcp-0.1.2.tar.gz:

Publisher: publish.yml on umbra2728/ctfd-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ctfd_mcp-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: ctfd_mcp-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 22.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ctfd_mcp-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0a32dfbe346b18e24af2f4f5a194b3629f510b63972e60b3717c8c190d728afa
MD5 9dccdb2b3cd885c8995093c77db574dc
BLAKE2b-256 e0647a9f2565ff661e3a3718a1da928c0fce6c9c0e54d8e6d54df11df176ca9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ctfd_mcp-0.1.2-py3-none-any.whl:

Publisher: publish.yml on umbra2728/ctfd-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page