CTFd MCP Server
The CTFd MCP Server enables AI assistants to interact with CTFd (Capture The Flag) platforms as a regular user for browsing, solving, and managing challenges.
Core Capabilities:
List challenges - Retrieve visible challenges with optional filters for category and unsolved status
View challenge details - Fetch comprehensive information including descriptions (HTML and plain text), metadata, attachment URLs, and solved status
Submit flags - Attempt flag submissions and receive immediate feedback on correctness
Manage dynamic containers - Start and stop Docker/Kubernetes-based instances with unified API that auto-detects backend plugins (ctfd-whale, ctfd-owl, or k8s)
Access challenge resources - Read markdown snapshots via MCP resources with metadata, descriptions, attachment URLs, and connection information
Authentication Support:
Username/password login
API token authentication
Session cookie authentication
Optional CSRF token support for ctfd-owl plugin
Additional Features:
Direct attachment download via absolute URLs
Comprehensive error handling for authentication failures, rate limiting, and API errors
Configurable timeouts for API requests
Allows users to manage the lifecycle of dynamic Docker-based challenge containers, including starting and stopping instances via plugins such as ctfd-whale and ctfd-owl.
Provides tools to manage Kubernetes-backed challenge instances, enabling the starting and stopping of containerized environments for specific CTF challenges.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@CTFd MCP Serverlist the unsolved web challenges"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
CTFd MCP server (user scope)
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) orCTFD_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_hereRelated MCP server: mcp-ctftime
Install
From PyPI (recommended):
uvx ctfd-mcp --helpFrom 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-mcpCursor 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 justcontainer_id, owl/k8s needchallenge_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/containersreturns 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; setCTFD_CSRF_TOKENif 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 includesk8s(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: setCTFD_SESSIONfrom thesessioncookie after logging in.The client now supports logging in with
CTFD_USERNAMEandCTFD_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:
Telegram: @ismailgaleev
Jabber: ismailgaleev@chat.merlok.ru
Email: umbra2728@gmail.com
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 devLint/format:
uv run ruff check .anduv run ruff format .Tests:
uv run pytestPre-commit:
uv run pre-commit install(seeCONTRIBUTING.md)
License
Apache-2.0. See LICENSE.
Available Tools
5 toolschallenge_detailsA
Get challenge details (description, files, meta) by ID.
| Name | Required | Description | Default |
|---|---|---|---|
| challenge_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description must disclose behavioral traits. It implies a read-only get operation, but does not explicitly state side effects, authentication, or error handling. Minimal but adequate for a simple fetch.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence with parenthetical is extremely concise and front-loaded. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (1 param, no output schema), the description is adequate but could specify the return format (e.g., JSON structure) or that it returns all details. Slightly lacking for complete understanding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so description should compensate. It does not explain challenge_id beyond its name and type; omits where to obtain the ID (e.g., from list_challenges). Fails to add value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves challenge details by ID, specifying the fields (description, files, meta). It distinguishes from sibling tools like list_challenges, which likely lists all challenges.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use this versus alternatives like list_challenges. The purpose is implied, but no when-not or prerequisite mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_challengesB
List visible challenges. Optional filter by category and unsolved only.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | ||
| only_unsolved | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided. Description implies read-only but lacks details on authentication, rate limits, or other behavioral traits beyond listing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence front-loaded with purpose, followed by optional filters. No redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Lacks output schema or description of return structure (e.g., array of challenge objects, pagination). Adequate for a simple list but leaves ambiguity for an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% (no param descriptions). The description mentions optional filtering by category and unsolved status but does not clarify valid category values or the precise meaning of 'unsolved only' (e.g., user-specific unsolved).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists visible challenges with optional filters, distinguishing it from siblings like challenge_details or submit_flag.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use this tool versus alternatives such as challenge_details for individual challenge details or submit_flag for flag submission.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_containerB
Unified start: detects plugin (whale/ctfd-owl/k8s) and starts container.
| Name | Required | Description | Default |
|---|---|---|---|
| challenge_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It mentions plugin detection behavior but does not disclose what happens on failure, permissions, or consequences beyond starting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence, front-loaded with key action and plugin detection, and contains no extraneous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema is provided, and the description omits crucial details such as return values, side effects, prerequisites (e.g., challenge existence), and error conditions, making it incomplete for a start action.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single required parameter 'challenge_id' has 0% schema description coverage, and the description does not explain its meaning, format, or how to obtain it, leaving the agent without guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the verb 'start' and resource 'container', and explicitly mentions unified detection of plugins (whale, ctfd-owl, k8s), distinguishing it from sibling tools like stop_container.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by stating it is a unified start, but does not provide explicit guidance on when to use this tool versus alternatives, nor does it mention prerequisites or context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stop_containerC
Unified stop: whale requires container_id; ctfd-owl/k8s require challenge_id.
| Name | Required | Description | Default |
|---|---|---|---|
| container_id | No | ||
| challenge_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so the description must carry behavioral disclosure. It fails to state whether stopping is destructive, requires authentication, or what the effect is. The mention of different systems hints at behavior but lacks detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence with no extraneous words. Front-loaded with the action 'Unified stop'. Every word serves a purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Lacks details on return values, errors, prerequisites, or side effects. No output schema and minimal description make it insufficient for a complete understanding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description adds partial meaning by linking parameters to systems (whale vs. ctfd-owl/k8s). However, it doesn't explain the parameters fully (e.g., format, requiredness beyond default null).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Unified stop', clearly indicating the tool stops containers. It differentiates from sibling 'start_container' by being the inverse operation. However, it does not specify a single verb+resource but rather describes two possible use cases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool versus alternatives like 'start_container' or when not to use it. The only usage hint is about choosing parameters based on system, which is implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_flagC
Submit a flag for a challenge ID.
| Name | Required | Description | Default |
|---|---|---|---|
| challenge_id | Yes | ||
| flag | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, and the description provides no behavioral details. It does not disclose whether flag submission is idempotent, what the side effects are (e.g., scoring), or any error conditions. The agent has no insight into tool behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely short but fails to convey necessary information. While brevity is valued, this description is under-specified and does not earn its place as an informative guide for an AI agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of annotations, output schema, and parameter descriptions, the description is completely inadequate. It does not provide enough context for the agent to know when to use the tool, what the return value looks like, or how it fits into the challenge lifecycle.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description adds no meaning beyond the property names. It does not explain what 'flag' format is expected, how to obtain challenge_id, or any constraints like case sensitivity. The description fails to compensate for the missing schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (submit) and resource (flag for a challenge ID). It is specific enough to distinguish from sibling tools like list_challenges and start_container, which have different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No usage guidelines are provided. The description does not mention when to use this tool, any prerequisites (e.g., must have a started container), or when to avoid it. No alternatives are listed compared to siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v1.0.0- First observed
challenge_details - First observed
list_challenges - First observed
start_container - First observed
stop_container - First observed
submit_flag
TDQS
Scored across 5 tools
Each tool targets a distinct action: starting/stopping containers, listing challenges, viewing details, and submitting flags. There is no overlap between the five tools.
Tool names follow a consistent verb_noun pattern (start_container, list_challenges, challenge_details, submit_flag, stop_container). 'challenge_details' is a noun phrase rather than a verb_noun like 'get_challenge', but the pattern is still clear and predictable.
Five tools is well-scoped for a CTFd server: it covers the core user-facing actions of browsing challenges, getting details, submitting flags, and managing challenge containers. Each tool earns its place.
The surface covers the main CTF participant workflow: list challenges, view details, start/stop containers, and submit flags. Minor gaps exist such as no tool for viewing container status or listing active containers, but agents can work around these with the provided tools.
Maintenance
Related MCP Connectors
Inspect and control your Northflank projects, services, jobs, and builds from your AI assistant.
Agentic CI operations for build inspection, failure diagnosis, and runner troubleshooting.
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Manage portable AI agent playbooks, Agent Skills, MCP configurations, personas, and memory.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with the Dreamhack wargame platform to fetch problem lists, download challenge files, and deploy them locally using Docker or Python for cybersecurity practice.-
- AlicenseAqualityCmaintenanceEnables AI assistants to query CTF (Capture The Flag) cybersecurity competition data from CTFtime.org, including events, team rankings, results, and votes through the public CTFtime API.744 npmMIT
- AlicenseNot gradedqualityNot gradedmaintenanceExposes common CTF and cybersecurity tools (crypto, forensics, malware analysis, steganography, reverse engineering, pwn, OSINT) so LLMs can help solve capture-the-flag challenges in a controlled lab environment.-
- AlicenseNot gradedqualityCmaintenanceEnables users to list CTFd challenges, read details, start/stop dynamic Docker instances, and submit flags through natural language.5Apache 2.0