关于 CTFd
CTFd 是面向 CTFd v3 实例的 MCP 服务端和可选 REST API,供 AI 工具及脚本查询挑战、提交 Flag 和查看积分榜。它支持多种认证方式,并默认将凭据保留在内存中。
主要功能
- 01支持令牌、Cookie 和表单登录
- 02分页筛选并查看挑战详情
- 03确认后提交 Flag
- 04查询积分榜与个人进度
- 05可选 REST API
适用场景
- 01让 AI Agent 浏览 CTF 挑战
- 02提交答案并检查提交结果
- 03查询排行榜和已解题进度
MCP 相关
通过 stdio 或 SSE 向 MCP 客户端提供 CTFd v3 操作工具,包括挑战查询、Flag 提交和积分榜查询。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx ctfd-mcp-serverCTFD_BASE_URLRoot URL of the CTFd v3 instance, e.g. https://ctf.example.com (without /api/v1)CTFD_ADMIN_TOKEN密钥CTFd API access token (preferred authentication method)CTFD_SESSION_COOKIE密钥Full CTFd session cookie, e.g. session=abc...CTFD_USERNAMEUsername for CTFd form loginCTFD_PASSWORD密钥Password for CTFd form loginCTFD_HTTP_TIMEOUTPer-request HTTP timeout in seconds (default 15)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
14收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 |
详细介绍
CTFd MCP 服务
一个用于与任意 CTFd v3 实例交互的模型上下文协议(MCP)服务。 它允许 AI 工具(Claude Desktop、Cursor、自定义 Agent 等)进行身份验证、列出 和查看挑战、提交 Flag,并通过稳定、类型安全的接口查询实例状态。
本项目提供两个基于同一个客户端库构建的接口:
- MCP 工具(主要接口)—
ctfd_mcp_server.py,通过stdio或sse使用。 - REST API(可选)—
server/main.py,一个用于脚本编写、 调试和 Docker 部署的 FastAPI 镜像。
┌──────────────────────────────────────────────┐
AI agent / MCP │ FastMCP (MCP tools) │
client ────────►│ set_token · login · challenges · submit_flag │
└──────────────────┬───────────────────────────┘
│ shared client
┌──────────────────▼───────────────────────────┐
curl / scripts ─►│ FastAPI REST (/api/v1/...) (optional) │
└──────────────────┬───────────────────────────┘
│
┌──────────────────▼───────────────────────────┐
│ server.ctfd_client.CTFdClient │
│ └─ gateway.py (HTTP, auth, timeouts) │
└──────────────────┬───────────────────────────┘
│ HTTPS / HTTP
┌─────▼─────┐
│ CTFd │
└───────────┘
凭据(令牌 / Cookie / 密码)仅存储在内存中,绝不会回显在工具输出中、写入
server_state.json 或记录到日志中。
功能特性
- 多种身份验证模式 — API 令牌、会话 Cookie 或用户名/密码表单登录 (支持 CSRF 处理)。
- 丰富的挑战查询 — 支持分页列出挑战,并按
category、search(名称) 和solved/unsolved筛选,还可获取单个挑战的详细信息。 - 安全提交 Flag — 需要显式设置
confirm=True,返回明确的成功/失败结果,并显示速率限制错误。Flag 绝不会记录到日志中。 - 实例信息查询 — 提供公开的实例信息、健康检查和身份验证状态工具,不会泄露任何机密。
- 一致的结构化错误 —
AuthenticationError、CTFdAPIError、ChallengeNotFoundError、SubmissionError、ValidationError、ConfigurationError。 - 默认分页 — 每次调用仅获取一页挑战;不会意外下载全部数据。
- 强化的 HTTP 处理 — 可配置超时时间,对幂等的
GET请求安全重试一次, 不重试POST请求(避免重复提交),严格解析 JSON 和内容。 - REST + MCP 共用一个代码库 — 两种接口的行为一致。
- 不硬编码实例 —
BASE_URL会在启动时和运行时进行验证和配置。
安装
需要 Python 3.10+。
最快捷的方式是从 PyPI 安装:
pip install ctfd-mcp-server
# MCP stdio server with env config:
CTFD_BASE_URL=https://ctf.example.com CTFD_ADMIN_TOKEN=ctfd_... ctfd-mcp
# optional REST interface:
ctfd-rest
对于 MCP 客户端,将配置指向打包后的入口点:
{
"mcpServers": {
"ctfd-mcp": {
"command": "ctfd-mcp",
"env": {
"CTFD_BASE_URL": "https://demo.ctfd.io",
"CTFD_ADMIN_TOKEN": "ctfd_..."
}
}
}
}
或者从源代码运行:
git clone https://github.com/MrJamescot/ctfd-mcp-server.git
cd ctfd-mcp-server
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # then edit .env
配置
| 变量 | 默认值 | 含义 |
|---|---|---|
CTFD_BASE_URL | (empty) | CTFd 实例根地址,例如 https://ctf.example.com(不含 /api/v1) |
CTFD_ADMIN_TOKEN | (empty) | API 令牌(首选认证方式) |
CTFD_SESSION_COOKIE | (empty) | 会话 Cookie,例如 session=abc... |
CTFD_USERNAME | (empty) | 表单登录用户名 |
CTFD_PASSWORD | (empty) | 表单登录密码 |
CTFD_HTTP_TIMEOUT | 15 | 每次请求的 HTTP 超时时间(秒) |
CTFD_HTTP_MAX_REDIRECTS | 5 | 每次请求最多跟随的重定向次数 |
CTFD_STATE_FILE | ~/.local/state/ctfd-mcp/server_state.json | 用于缓存认证状态的文件 |
CTFD_MCP_TRANSPORT | stdio | MCP 传输方式:stdio 或 sse |
MCP_HOST / MCP_PORT | 127.0.0.1 / 8000 | REST 服务绑定设置(默认仅绑定环回地址) |
CTFD_API_TOKEN | (empty) | 用于保护可选 REST API(/api/v1/*)的可选 Bearer 令牌 |
CTFD_ALLOW_PRIVATE_IPS | false | 允许连接到私有/环回/元数据地址(例如本地 CTFd 测试实例) |
CTFD_DOWNLOAD_DIR | ./downloads | download_file 保存挑战附件的目录 |
CTFD_PERSIST_SECRETS | false | ⚠ 强烈不建议:将密钥写入磁盘 |
CTFD_BASE_URL可以包含路径前缀(例如https://host/ctfd);客户端会 自动追加/api/v1。
运行 MCP 服务
大多数 MCP 客户端会通过 command/args 配置自行启动服务。
因此,客户端配置应引用 ctfd_mcp_server.py:
// e.g. Claude Desktop / mcp.json
{
"mcpServers": {
"ctfd-mcp": {
"command": "python",
"args": ["/path/to/ctfd-mcp-server/ctfd_mcp_server.py"],
"env": {
"CTFD_BASE_URL": "https://demo.ctfd.io",
"CTFD_ADMIN_TOKEN": "ctfd_..."
}
}
}
}
手动启动:
# stdio (default) — used by MCP clients
python ctfd_mcp_server.py
# SSE — expose over HTTP for remote/Docker use
CTFD_MCP_TRANSPORT=sse python ctfd_mcp_server.py # http://127.0.0.1:8000/sse
MCP 工具
| 工具 | 参数 | 描述 |
|---|---|---|
set_base_url | url | 将服务指向某个 CTFd 实例 |
set_token | token | 使用 API 令牌(仅保存在内存中) |
set_cookie | cookie | 使用会话 Cookie(仅保存在内存中) |
login | username、password | 表单登录;保留会话 Cookie |
challenges | category、search、solved、page、per_page | 带筛选条件的分页挑战列表 |
challenge | identifier(id 或 name) | 单个挑战的完整详情 |
submit_flag | flag、challenge_name/challenge_id、confirm | 提交 Flag(需要 confirm=True) |
download_file | file_url、dest_dir | 通过 CTFd /files/… 路由下载挑战附件 |
unlock_hint | hint_id | 解锁并查看提示(付费提示需要消耗积分) |
scoreboard | — | 公开排行榜 |
progress | — | 你的分数和已解出的挑战 |
instance_info | — | 安全的公开实例元数据 |
auth_status | — | 认证模式和有效性(不含机密信息) |
health | — | 可访问性、API 和认证检查 |
使用令牌认证时,请求会以
Content-Type: application/json发送 (CTFd 仅在 JSON 请求中认可Authorization: Token ...)。使用 Cookie/凭据认证时,会更改状态的请求会将会话 CSRF 随机数作为CSRF-Token标头回传;登录后会从站点重新获取该随机数。
工具会返回 JSON 文本。错误采用结构化格式,例如:
{ "error": { "type": "ChallengeNotFoundError", "message": "Challenge '99' not found (or not visible)." } }
运行 REST API(可选)
python scripts/run_local.sh # reads .env, default http://127.0.0.1:8000
# or
uvicorn server.main:app --host 0.0.0.0 --port 8000
端点(均位于 /api/v1 下):
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /set_base_url | 验证并设置 CTFd 基础 URL |
| POST | /set_token | 设置 API 令牌 |
| POST | /set_cookie | 设置会话 Cookie |
| POST | /set_creds | 保存用户名/密码,以供后续登录使用 |
| POST | /login | 表单登录(会话 Cookie) |
| GET | /challenges | 分页并筛选挑战列表 |
| GET | /challenges/{id-or-name} | 挑战详情 |
| POST | /submit | 提交 flag(必须设置 confirm: true) |
| POST | /download | 下载挑战附件(请求体:file_url) |
| POST | /unlock_hint | 解锁并查看提示(请求体:hint_id) |
| GET | /scoreboard | 公开排名 |
| GET | /progress | 你的分数和解题记录 |
| GET | /instance_info | 公开实例元数据 |
| GET | /auth_status | 身份验证模式和有效性 |
| GET | /health | 健康检查 |
可使用额外的 bearer 令牌保护可选 REST API:设置
CTFD_API_TOKEN后,对/api/v1/*的请求将要求提供Authorization: Bearer <token>。服务默认绑定到回环地址 (MCP_HOST=127.0.0.1)。
Docker
现成的镜像已发布在 Docker Hub:
docker run --rm -p 8000:8000 \
-e CTFD_BASE_URL=https://ctf.example.com \
-e CTFD_ADMIN_TOKEN=ctfd_... \
jamescot/ctfd-mcp-server
也可以在本地构建(REST 模式):
docker build -t ctfd-mcp .
docker run --rm -p 8000:8000 \
-e CTFD_BASE_URL=https://ctf.example.com \
-e CTFD_ADMIN_TOKEN=ctfd_... \
ctfd-mcp
docker compose up --build 也可正常使用(REST API 位于 http://localhost:8000)。
如需在容器中运行 MCP SSE 服务:
docker run --rm -it -e CTFD_BASE_URL=https://ctf.example.com ctfd-mcp python ctfd_mcp_server.py
# stdio on the attached terminal
使用示例
MCP(Agent)
1. set_base_url url="https://ctf.example.com"
2. set_token token="ctfd_..."
3. challenges category="web", solved=false, page=1, per_page=25
4. challenge identifier="3"
5. submit_flag flag="flag{...}", challenge_id=3, confirm=true
REST
curl -X POST http://localhost:8000/api/v1/set_base_url \
-H 'Content-Type: application/json' -d '{"url":"https://ctf.example.com"}'
curl -X POST http://localhost:8000/api/v1/set_token \
-H 'Content-Type: application/json' -d '{"token":"ctfd_..."}'
curl 'http://localhost:8000/api/v1/challenges?search=web&solved=false&per_page=10'
curl -X POST http://localhost:8000/api/v1/submit \
-H 'Content-Type: application/json' \
-d '{"challenge_id":3,"flag":"flag{...}","confirm":true}'
curl http://localhost:8000/api/v1/health
完整的操作指南请参阅 DEMO.md,curl 和 Python 代码片段请参阅 examples/。
开发与测试
pip install -r requirements-dev.txt
python -m pytest -q # 76 unit tests, mocked CTFd API (no network)
ruff check server ctfd_mcp_server.py tests
测试套件会模拟 CTFd API(tests/conftest.py::FakeGateway),因此单元测试可离线运行。
针对真实 CTFd 进行集成测试
运行本地 CTFd 进行实时测试(推荐使用本地实例,而非共享演示实例;共享演示实例会在需要身份验证的公开路由上提供 HTML):
git clone https://github.com/CTFd/CTFd.git /tmp/CTFd
docker compose -f /tmp/CTFd/docker-compose.yml up
# create a user/challenge, then:
CTFD_BASE_URL=http://localhost:8000 python ctfd_mcp_server.py
CTFD_BASE_URL=http://localhost:8000 uvicorn server.main:app --port 8001
curl http://localhost:8001/api/v1/health
安全注意事项
- 凭据仅保存在内存中。 默认情况下,不会将任何内容写入
server_state.json。不建议启用CTFD_PERSIST_SECRETS。 - 绝不会回显机密信息。 工具和 API 响应、错误消息及日志会对令牌、Cookie、密码和 flag 进行脱敏(
server/utils.py)。 - 每个工具都会先验证输入,再访问网络(
set_base_url要求绝对http(s)URL,submit_flag要求confirm=True, 等等)。 - 受控重试。 仅幂等的
GET请求会重试一次。 flag 提交绝不会自动重放。 - 信任模型。 该服务是本地/开发工具:任何能够调用其工具的人,都可以将其指向任意 CTFd 实例,并且(凭借有效凭据)读取数据或提交 flag。请勿在不受信任的网络上公开 REST/SSE 端点。
- SSRF 防护。 默认情况下,会拒绝连接到私有、回环、链路本地或
元数据地址(设置
CTFD_ALLOW_PRIVATE_IPS=1可选择退出)。本地 容器或指向私有实例的工具将收到明确的错误信息。
局限
- 需要 CTFd v3+。使用的
/api/v1路由是 CTFd v3 的标准 API 路由。 - 表单登录依赖 CTFd 的 Web 会话流程(尽力提取 CSRF nonce)。建议使用 API 令牌进行身份验证。
difficulty不是 CTFd 的标准字段;返回的是挑战的value(分数)。solved筛选使用 CTFd 的solved_by_me标志,该标志只有在通过身份验证时才有意义。- 只有在呈现的页面中显示实例“版本”时,才会报告该版本;CTFd 没有公开的版本 API 端点。
- 令牌按实例区分。 当凭据无效时,CTFd 会将
/api/v1调用重定向到登录页面。服务会检测到这种情况并报告:"此凭据对 THIS 实例无效"——一个 CTFd 实例的令牌绝不会在另一个实例上生效。 - 配置
CTFD_USERNAME/CTFD_PASSWORD后,每当调用返回未通过身份验证时,服务都会按需自动登录(轮换会话 Cookie),从而自动修复过期会话。每次登录后,都会从站点重新获取 CSRF nonce(通过 Web 会话提交 flag 需要新的 nonce)。 - 在团队模式实例上,未加入团队的账号在加入或创建团队之前看不到
/api/v1/challenges;服务会呈现 CTFd 的权限提示。
贡献
欢迎提交拉取请求。请:
- 创建一个 Issue 描述所做的更改。
- 在
tests/中添加测试(优先使用模拟的 CTFd API)。 - 运行
python -m pytest -q和ruff check server ctfd_mcp_server.py tests。 - 不要在代码或测试中加入凭据,也不要提交
server_state.json/.env。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。