Skip to main content

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.

Metadata

Release files for ctfd-mcp 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ctfd-mcp 0.1.2
File Size Uploaded
ctfd_mcp-0.1.2.tar.gz 56.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ctfd-mcp 0.1.2
File Interpreter ABI Platform
ctfd_mcp-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 78.3 kB

Release files / ctfd_mcp-0.1.2.tar.gz

Download URL ctfd_mcp-0.1.2.tar.gz
Size 56.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b7e693b113625c03cb523755a24a23bfbd5e7996a129cfb4d104db38fc170c5c
BLAKE2b-256 checksum
How to use checksums
19a43b1f6048bed86815d14df468b21573d06f9c7c07b3710e92a02c863823ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 4, 2026.

Transparency log

Release files / ctfd_mcp-0.1.2-py3-none-any.whl

Download URL ctfd_mcp-0.1.2-py3-none-any.whl
Size 22.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0a32dfbe346b18e24af2f4f5a194b3629f510b63972e60b3717c8c190d728afa
BLAKE2b-256 checksum
How to use checksums
e0647a9f2565ff661e3a3718a1da928c0fce6c9c0e54d8e6d54df11df176ca9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page