CTFd

io.github.MrJamescot由 GitHub 帳號 MrJamescot 發布v1.0.4更新於 Oct 24, 2026

MCP server for CTFd v3: list challenges, submit flags, and query scoreboards via AI agents.

已驗證STDIO僅桌面效率與工作流安全與監控

概覽

AI 產生的概覽

面向 CTFd v3 實例的 MCP 伺服器,讓 AI 助理瀏覽題目、提交 flag、解鎖提示並查看排行榜。

可以做什麼
將伺服器指向 CTFd 實例並設定憑證(基礎 URL、API 權杖、工作階段 Cookie 或表單登入)。依分類、名稱與是否已解出篩選題目清單,並查看單一題目的完整詳情。在明確確認後提交 flag,並解鎖提示。將題目附件下載到本機目錄。讀取公開排行榜、自己的進度與實例中繼資料。檢查驗證狀態與實例健康狀態。
適用情境
適合在以 CTFd 為基礎的搶旗賽中,讓助理協助整理題目、查詢詳情、追蹤進度或提交你已找到的 flag。也適合透過可選的 REST 鏡像對 CTFd 實例撰寫腳本。
執行需求
本機 Python 3.10+ 程序,可從 PyPI 安裝(uvx 或 pip)或從原始碼執行。需要 CTFD_BASE_URL 指向 CTFd v3 實例,並提供一種憑證:CTFD_ADMIN_TOKEN(建議)、CTFD_SESSION_COOKIE,或 CTFD_USERNAME 加 CTFD_PASSWORD。需要能連線該實例的網路;除非啟用 CTFD_ALLOW_PRIVATE_IPS,否則私有與回送位址會被拒絕。
安裝前請注意
需要處理 CTFd 憑證:CTFD_ADMIN_TOKEN、CTFD_SESSION_COOKIE、CTFD_PASSWORD。預設僅保存在記憶體中;CTFD_PERSIST_SECRETS 會把密鑰寫入磁碟,不建議開啟。submit_flag 會改變比賽狀態,unlock_hint 可能消耗點數解鎖付費提示。能呼叫這些工具的人即可用你的憑證操作,因此不要把 REST 或 SSE 端點暴露在不受信任的網路上。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 CTFd,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

CTFd MCP Server

[PyPI - Version] [PyPI - Python Versions] [Docker Pulls] [License: MIT] [GitHub Stars]

A Model Context Protocol (MCP) server for interacting with any CTFd v3 instance. It lets AI tools (Claude Desktop, Cursor, custom agents, ...) authenticate, list and inspect challenges, submit flags, and query instance state through a stable, type-safe interface.

The project ships two interfaces built on the same client library:

  • MCP tools (primary) — ctfd_mcp_server.py, used over stdio or sse.
  • REST API (optional) — server/main.py, a FastAPI mirror for scripting, debugging, and Docker deployments.
                 ┌──────────────────────────────────────────────┐ 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    │                              └───────────┘

Credentials (token / cookie / password) live in memory only and are never echoed in tool output, written to server_state.json, or logged.


Features

  • Multiple authentication modes — API token, session cookie, or username/password form login (with CSRF handling).
  • Rich challenge queries — paginated listing with category, search (name), and solved/unsolved filters, plus per-challenge detail retrieval.
  • Safe flag submission — requires an explicit confirm=True, returns clear success/failure, and surfaces rate-limit errors. Flags are never logged.
  • Instance introspection — public instance info, health check, and an authentication-status tool that reveal no secrets.
  • Consistent structured errors — AuthenticationError, CTFdAPIError, ChallengeNotFoundError, SubmissionError, ValidationError, ConfigurationError.
  • Pagination by default — one page of challenges per call; no accidental full-dump downloads.
  • Hardened HTTP — configurable timeouts, one safe retry for idempotent GETs, no retries for POSTs (no duplicate submissions), strict JSON/content parsing.
  • REST + MCP from one codebase — identical behaviour on both interfaces.
  • No hardcoded instance — BASE_URL is validated and configurable at startup and at runtime.

Installation

Requires Python 3.10+.

The fastest way is to install from PyPI:

bash
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

For MCP clients, point your config at the packaged entry point:

jsonc
{  "mcpServers": {    "ctfd-mcp": {      "command": "ctfd-mcp",      "env": {        "CTFD_BASE_URL": "https://demo.ctfd.io",        "CTFD_ADMIN_TOKEN": "ctfd_..."      }    }  }}

Or run from source:

bash
git clone https://github.com/MrJamescot/ctfd-mcp-server.gitcd ctfd-mcp-serverpython3 -m venv .venv && source .venv/bin/activatepip install -r requirements.txt
cp .env.example .env     # then edit .env

Configure

VariableDefaultMeaning
CTFD_BASE_URL(empty)CTFd instance root, e.g. https://ctf.example.com (without /api/v1)
CTFD_ADMIN_TOKEN(empty)API token (preferred auth)
CTFD_SESSION_COOKIE(empty)Session cookie, e.g. session=abc...
CTFD_USERNAME(empty)Username for form login
CTFD_PASSWORD(empty)Password for form login
CTFD_HTTP_TIMEOUT15Per-request HTTP timeout (seconds)
CTFD_HTTP_MAX_REDIRECTS5Max redirects followed per request
CTFD_STATE_FILE~/.local/state/ctfd-mcp/server_state.jsonFile used to cache auth state
CTFD_MCP_TRANSPORTstdioMCP transport: stdio or sse
MCP_HOST / MCP_PORT127.0.0.1 / 8000REST server bind settings (loopback by default)
CTFD_API_TOKEN(empty)Optional bearer token protecting the optional REST API (/api/v1/*)
CTFD_ALLOW_PRIVATE_IPSfalseAllow connections to private/loopback/metadata addresses (e.g. local CTFd test instances)
CTFD_DOWNLOAD_DIR./downloadsDirectory where challenge attachments are saved by download_file
CTFD_PERSIST_SECRETSfalse⚠ Strongly discouraged: write secrets to disk

CTFD_BASE_URL may include a path prefix (e.g. https://host/ctfd); the client appends /api/v1 automatically.


Running the MCP Server

Most MCP clients launch the server themselves via a command/args config. For that, your client config should reference ctfd_mcp_server.py:

jsonc
// 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_..."      }    }  }}

Manual launch:

bash
# stdio (default) — used by MCP clientspython ctfd_mcp_server.py
# SSE — expose over HTTP for remote/Docker useCTFD_MCP_TRANSPORT=sse python ctfd_mcp_server.py   # http://127.0.0.1:8000/sse

MCP tools

ToolParametersDescription
set_base_urlurlPoint the server at a CTFd instance
set_tokentokenAdopt an API token (memory only)
set_cookiecookieAdopt a session cookie (memory only)
loginusername, passwordForm login; keeps the session cookie
challengescategory, search, solved, page, per_pagePaginated challenge list with filters
challengeidentifier (id or name)Full detail of one challenge
submit_flagflag, challenge_name/challenge_id, confirmSubmit a flag (requires confirm=True)
download_filefile_url, dest_dirDownload a challenge attachment over the CTFd /files/… route
unlock_hinthint_idUnlock and read a hint (paid hints cost points)
scoreboard—Public scoreboard standings
progress—Your score + solved challenges
instance_info—Safe public instance metadata
auth_status—Auth mode + validity (no secrets)
health—Reachability, API and auth checks

With token auth, requests are sent with Content-Type: application/json (CTFd only honours Authorization: Token ... on JSON requests). With cookie/credentials auth, state-changing requests echo the session CSRF nonce as the CSRF-Token header, which is re-fetched from the site after login.

Tools return JSON text. Errors are structured, e.g.:

json
{ "error": { "type": "ChallengeNotFoundError", "message": "Challenge '99' not found (or not visible)." } }

Running the REST API (optional)

bash
python scripts/run_local.sh           # reads .env, default http://127.0.0.1:8000# oruvicorn server.main:app --host 0.0.0.0 --port 8000

Endpoints (all under /api/v1):

MethodPathDescription
POST/set_base_urlValidate & set the CTFd base URL
POST/set_tokenSet API token
POST/set_cookieSet session cookie
POST/set_credsStore username/password for later login
POST/loginForm login (session cookie)
GET/challengesPaginated + filtered challenge list
GET/challenges/{id-or-name}Challenge detail
POST/submitSubmit a flag (confirm: true required)
POST/downloadDownload a challenge attachment (body: file_url)
POST/unlock_hintUnlock and read a hint (body: hint_id)
GET/scoreboardPublic standings
GET/progressYour score and solves
GET/instance_infoPublic instance metadata
GET/auth_statusAuth mode + validity
GET/healthHealth check

The optional REST API can be protected with an extra bearer token: set CTFD_API_TOKEN, and requests to /api/v1/* will require Authorization: Bearer <token>. The server binds to loopback by default (MCP_HOST=127.0.0.1).


Docker

A ready-made image is published on Docker Hub:

bash
docker run --rm -p 8000:8000 \  -e CTFD_BASE_URL=https://ctf.example.com \  -e CTFD_ADMIN_TOKEN=ctfd_... \  jamescot/ctfd-mcp-server

Or build locally (REST mode):

bash
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 also works (REST API on http://localhost:8000).

To run the MCP SSE server in a container instead:

bash
docker run --rm -it -e CTFD_BASE_URL=https://ctf.example.com ctfd-mcp python ctfd_mcp_server.py# stdio on the attached terminal

Usage examples

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=254. challenge         identifier="3"5. submit_flag       flag="flag{...}", challenge_id=3, confirm=true

REST

bash
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

See DEMO.md for a complete walkthrough and examples/ for curl and Python snippets.


Development & testing

bash
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

The test suite mocks the CTFd API (tests/conftest.py::FakeGateway), so unit tests run offline.

Integration testing against a real CTFd

Run a local CTFd for live tests (recommended over the shared demo instance, which serves HTML on public auth-gated routes):

bash
git clone https://github.com/CTFd/CTFd.git /tmp/CTFddocker compose -f /tmp/CTFd/docker-compose.yml up# create a user/challenge, then:CTFD_BASE_URL=http://localhost:8000 python ctfd_mcp_server.pyCTFD_BASE_URL=http://localhost:8000 uvicorn server.main:app --port 8001curl http://localhost:8001/api/v1/health

Security considerations

  • Credentials are memory-only. By default nothing is written to server_state.json. Enabling CTFD_PERSIST_SECRETS is discouraged.
  • Secrets are never echoed. Tool and API responses, error messages and logs redact tokens, cookies, passwords and flags (server/utils.py).
  • Every tool validates its input before touching the network (set_base_url requires an absolute http(s) URL, submit_flag requires confirm=True, etc.).
  • Controlled retries. Only idempotent GET requests are retried (once). Flag submissions are never automatically replayed.
  • Trust model. The server is a local/dev tool: whoever can call its tools can point it at any CTFd instance and (with a valid credential) read data or submit flags. Do not expose the REST/SSE endpoints on an untrusted network.
  • SSRF guard. By default connections to private / loopback / link-local / metadata addresses are refused (CTFD_ALLOW_PRIVATE_IPS=1 opts out). A local container or a tool pointed at a private instance will get a clear error.

Limitations

  • Requires CTFd v3+. The /api/v1 routes used are standard CTFd v3 API routes.
  • Form login depends on CTFd's web session flow (CSRF nonce extraction is best-effort). API tokens are the recommended authentication method.
  • difficulty is not a standard CTFd field; challenge value (points) is returned instead.
  • solved filtering uses CTFd's solved_by_me flag, which is only meaningful when authenticated.
  • Instance "version" is reported only when it appears in the rendered page; CTFd has no public version API endpoint.
  • Tokens are per-instance. CTFd redirects /api/v1 calls to its login page when a credential is invalid. The server detects this and reports: "the credential is not valid for THIS instance" — a token from one CTFd instance never works on another.
  • When CTFD_USERNAME/CTFD_PASSWORD are configured, the server auto-logs-in on demand (rotating the session cookie) whenever a call returns unauthenticated, so expired sessions self-heal. After each login the CSRF nonce is re-fetched from the site (a fresh nonce is required for flag submissions over a web session).
  • A teamless account sees no /api/v1/challenges on team-mode instances until it joins or creates a team; the server surfaces CTFd's permission message.

Contributing

Pull requests are welcome. Please:

  1. Open an issue describing the change.
  2. Add tests in tests/ (mocked CTFd API preferred).
  3. Run python -m pytest -q and ruff check server ctfd_mcp_server.py tests.
  4. Do not ship credentials in code, tests, or commit server_state.json / .env.

License

MIT — repository: https://github.com/MrJamescot/ctfd-mcp-server

來源:README.md,提交 c75b77a

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

3
  1. v1.0.4最新Sep 21, 2026
  2. v1.0.3Sep 20, 2026
  3. v1.0.2Sep 20, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分