Skip to main content
Glama

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.


Related MCP server: CyberEdu MCP Server

Installation

Requires Python 3.10+.

The fastest way is to install from 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

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

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

Or run from source:

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

Configure

Variable

Default

Meaning

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_TIMEOUT

15

Per-request HTTP timeout (seconds)

CTFD_HTTP_MAX_REDIRECTS

5

Max redirects followed per request

CTFD_STATE_FILE

~/.local/state/ctfd-mcp/server_state.json

File used to cache auth state

CTFD_MCP_TRANSPORT

stdio

MCP transport: stdio or sse

MCP_HOST / MCP_PORT

127.0.0.1 / 8000

REST server bind settings (loopback by default)

CTFD_API_TOKEN

(empty)

Optional bearer token protecting the optional REST API (/api/v1/*)

CTFD_ALLOW_PRIVATE_IPS

false

Allow connections to private/loopback/metadata addresses (e.g. local CTFd test instances)

CTFD_DOWNLOAD_DIR

./downloads

Directory where challenge attachments are saved by download_file

CTFD_PERSIST_SECRETS

false

⚠ 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:

// 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:

# 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 tools

Tool

Parameters

Description

set_base_url

url

Point the server at a CTFd instance

set_token

token

Adopt an API token (memory only)

set_cookie

cookie

Adopt a session cookie (memory only)

login

username, password

Form login; keeps the session cookie

challenges

category, search, solved, page, per_page

Paginated challenge list with filters

challenge

identifier (id or name)

Full detail of one challenge

submit_flag

flag, challenge_name/challenge_id, confirm

Submit a flag (requires confirm=True)

download_file

file_url, dest_dir

Download a challenge attachment over the CTFd /files/… route

unlock_hint

hint_id

Unlock 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.:

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

Running the REST API (optional)

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

Endpoints (all under /api/v1):

Method

Path

Description

POST

/set_base_url

Validate & set the CTFd base URL

POST

/set_token

Set API token

POST

/set_cookie

Set session cookie

POST

/set_creds

Store username/password for later login

POST

/login

Form login (session cookie)

GET

/challenges

Paginated + filtered challenge list

GET

/challenges/{id-or-name}

Challenge detail

POST

/submit

Submit a flag (confirm: true required)

POST

/download

Download a challenge attachment (body: file_url)

POST

/unlock_hint

Unlock and read a hint (body: hint_id)

GET

/scoreboard

Public standings

GET

/progress

Your score and solves

GET

/instance_info

Public instance metadata

GET

/auth_status

Auth mode + validity

GET

/health

Health 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:

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):

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:

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=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

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


Development & testing

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):

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

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

Available Tools

14 tools
auth_statusA

Report whether the current session is authenticated and which auth mode is active.

Reveals no tokens/cookies/passwords.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden and does well: it explicitly discloses that the tool reveals no tokens, cookies, or passwords, which is exactly the safety-relevant behavior an agent needs to know before calling. It could go further on whether the call has side effects (it implies a pure read) but the disclosure is a genuine value-add beyond structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core purpose, followed by the safety-relevant caveat. Zero filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-param status tool with an output schema (which presumably documents the return shape), the description is complete enough: purpose and safety posture are covered. Minor gap: it doesn't state that the call is side-effect-free/read-only, which would help an agent reason about retries.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so per the rubric the baseline is 4. The description correctly implies no input is needed; there is nothing further to specify.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource ('Report whether ... authenticated and which auth mode is active'). An agent can immediately distinguish this read-only status check from mutation siblings like set_token, set_cookie, and login.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the name and purpose — use it to discover current auth state — but there is no explicit when-to-use guidance or named alternative. No exclusions or preconditions are stated, though the tool is simple enough that heavy guidance is less critical.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

challengeB

Get the full detail of a single challenge by numeric id or name.

Includes description, category, value, files, hints and connection info.

Args: identifier: challenge id (e.g. "3") or challenge name.

ParametersJSON Schema
NameRequiredDescriptionDefault
identifierYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden, and it does disclose the returned payload ('description, category, value, files, hints and connection info'), implying a read-only lookup. It does not state whether calling it starts or affects an instance, nor whether it requires authentication, which matters given siblings like `login` and `set_token`.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then a single line enumerating the returned fields and an Args block. The 'Args:' formatting is slightly mechanical but every line carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, yet the description still summarizes the payload usefully. For a one-parameter lookup tool this covers what an agent needs, with the only gap being the absence of any auth or state-side-effect note.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate — and it does, clarifying that `identifier` accepts either a numeric-looking id (with example '3') or a challenge name. That is genuine meaning beyond the schema's bare 'Identifier' string title.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Get the full detail of a single challenge by numeric id or name.' The word 'single' implicitly separates it from the plural sibling `challenges`, but the description never names that sibling or explicitly contrasts listing vs. detail retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance and no mention of alternatives such as `challenges` for listing or `instance_info` for connection details. The agent must infer that this tool is the detail-lookup counterpart to `challenges` purely from the name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

challengesA

List challenges with optional filters and pagination.

Args: category: filter by challenge category (exact match). search: case-insensitive substring match on challenge name. solved: only show solved (True) or unsolved (False) challenges. page: page number (1-based) when no filters are applied. per_page: number of challenges per page (1-100).

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
searchNo
solvedNo
categoryNo
per_pageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It does disclose a non-obvious behavioral rule (pagination only applies without filters) and the per_page bounds, but says nothing about authentication requirements, ordering of results, or total-count behavior despite siblings like set_token/login implying an auth prerequisite.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded one-line summary followed by a tight Args list, with no filler sentences. The bullet-per-parameter format is scannable and every line carries parameter meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described. Combined with the full parameter documentation, the definition is nearly sufficient; the only meaningful omission is any statement about auth or prerequisites for listing challenges.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: all five parameters are explained, including match semantics (exact for category, case-insensitive substring for search), boolean polarity for solved, 1-based page numbering, and a 1-100 range for per_page.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource ('List challenges') plus its scope (optional filters and pagination). It does not explicitly distinguish itself from the singular sibling 'challenge', but the list-vs-single distinction is strongly implied.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the filter set: browse/search challenges, narrow by category, search text, or solved status. There is no explicit when-to-use guidance versus siblings like 'challenge' or 'progress', though the note that page only applies 'when no filters are applied' is a useful conditional hint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

download_fileA

Download a challenge attachment to the local machine.

Challenge detail (challenge tool) returns a files array with site-relative paths like /files/<hash>/<name> (signed URLs on some deployments). Pass one of those values here.

Args: file_url: absolute http(s) URL or site-relative path to the file. dest_dir: optional local directory to store the file in (default: CTFD_DOWNLOAD_DIR or ./downloads).

ParametersJSON Schema
NameRequiredDescriptionDefault
dest_dirNo
file_urlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It usefully discloses accepted URL forms (absolute http(s) or site-relative like /files/<hash>/<name>, sometimes signed) and the dest_dir default resolution, but says nothing about authentication requirements, whether existing files are overwritten, or side effects on disk.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, followed by a targeted pointer to the source of the input and a compact Args block. Every line earns its place, though the Args block partly restates schema fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. The description covers the workflow link, both parameters, and the default directory, leaving only auth and overwrite behavior unstated for a simple two-parameter download tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does for both parameters: file_url's accepted formats and dest_dir's optionality plus the CTFD_DOWNLOAD_DIR/./downloads default, which the schema only shows as null. It stops short of path/filename collision or directory-creation semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (download a challenge attachment to the local machine) and ties it to the sibling 'challenge' tool that produces the input. An agent can distinguish it immediately from challenge, challenges, or instance_info.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: get the files array from the 'challenge' tool, then pass one of those values here. It gives the condition that supplies the input, though it never states when this tool should not be used (e.g., non-challenge URLs).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

healthA

Perform a health check: CTFd reachability, API status and authentication state.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It does disclose the three things inspected, which is meaningful behavioral context, but it never states that the call is a read-only, side-effect-free probe or what happens when a check fails (error vs. degraded status field).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence that states the operation first and then the three checks. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not describe return values, and it correctly focuses on what is checked. The only gap is the absence of guidance on what to do with the result or how it relates to auth_status.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline of 4 applies. No parameter information is needed or missing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific operation (health check) and enumerates what it verifies: CTFd reachability, API status, and authentication state. It is clear what the tool does, though it never explicitly distinguishes itself from the sibling auth_status, which likely overlaps on the authentication-state portion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the nature of a diagnostic check; there is no statement of when to call it (e.g. before other calls, after set_base_url) and no mention of alternatives such as auth_status. An agent can infer the intent but must guess the conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

instance_infoA

Return safe, public metadata about the configured CTFd instance.

No secrets are included.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It usefully discloses that output is safe/public and contains no secrets, but omits other relevant traits such as read-only nature, authentication requirements, or prerequisites like set_base_url.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core purpose and followed by a useful safety note. Every sentence earns its place with no waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity, zero parameters, and an existing output schema, the description is largely complete about what it returns. It could be strengthened with usage context relative to sibling tools, but no critical information is missing for invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description adds no parameter semantics, but none are needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Return safe, public metadata about the configured CTFd instance.' This is clear, though it does not explicitly distinguish the tool from siblings like health or auth_status that also return instance-oriented information.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool versus alternatives. The description does not say when to call it, when not to, or how it relates to siblings such as health or auth_status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

loginB

Log in to CTFd with a username and password (kept in memory only).

Creates a session cookie; the password is never returned.

Args: username: CTFd account name. password: CTFd account password.

ParametersJSON Schema
NameRequiredDescriptionDefault
passwordYes
usernameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose useful traits: the password is kept in memory only, a session cookie is created, and the password is never returned. However, it says nothing about failure modes, error handling, or whether the session persists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and key security behavior, followed by a short Args block. Efficient overall, though the Args lines add little beyond the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be explained. The description covers purpose and the security posture adequately, but omits when to prefer this over the other auth siblings, leaving a gap for an auth-related tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does map both params (username = CTFd account name, password = CTFd account password). The added meaning is minimal and largely restates the parameter names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Log in to CTFd') and adds the security detail that credentials are kept in memory only. An agent can tell this is the authentication step, though it is not explicitly distinguished from siblings like set_token or set_cookie that also establish auth.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use login versus the sibling auth tools (set_token, set_cookie, auth_status). Usage is only implied by the name; there are no exclusions or preconditions stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

progressA

Return the authenticated user's progress (score and solved challenges).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavioral burden. It discloses that the result is scoped to the authenticated user and lists the returned fields, implicitly signalling an auth requirement, but says nothing about caching/freshness, rate limits, or what happens if unauthenticated, leaving real gaps for a read tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence with no filler; the scoping and returned fields are front-loaded. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read tool with an output schema that already documents the return shape, the description covers what is needed to call it correctly. The only shortfall is the absence of any sibling disambiguation from 'scoreboard' and the lack of behavioral notes that, with no annotations, would have added value.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, which is the baseline-4 case per the rubric. There is nothing for the description to clarify beyond the implicit scoping to the authenticated user.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Return') and resource ('authenticated user's progress') and even names the payload ('score and solved challenges'), so the agent knows exactly what it gets. It does not, however, differentiate itself from the sibling 'scoreboard', which an agent could easily confuse with this per-user progress view.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'authenticated user's progress' implies the usage context (fetching the calling user's own stats rather than a global ranking), which is enough to infer when to reach for it over 'scoreboard'. But no explicit when-to-use or when-not-to-use guidance, prerequisites, or alternative routing is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scoreboardA

Return the public CTFd scoreboard (top standings).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It does usefully disclose that the scoreboard is 'public' (implying no token/login required), but says nothing about result size, pagination, rate limiting, or whether it reflects live scoring. An output schema exists, so return-value structure is covered elsewhere.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short sentence with the resource front-loaded and a clarifying parenthetical. Nothing is wasted and nothing important is buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless read tool with an output schema, the description covers what is returned and that it is public. The only real gap is guidance on when in the workflow to call it, which is minor given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to clarify beyond the schema. Baseline 4 applies for a parameterless tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: 'Return the public CTFd scoreboard (top standings)'. The parenthetical clarifies what a scoreboard returns (top standings), so the agent knows exactly what it gets. It does not need to differentiate from siblings since none of the other tools (challenges, submit_flag, login, etc.) overlap with fetching standings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: there are no alternatives to route between, and the word 'public' hints that no authentication is required. However, the description never says when to call it (e.g., after login, to check rank) or whether auth state matters, leaving the trigger condition to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_base_urlB

Configure the CTFd instance this server talks to.

Args: url: absolute http(s) URL of the CTFd instance, e.g. https://ctf.example.com

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden, and it says nothing about whether the setting persists across calls, whether the URL is validated or the connection tested, what happens on an unreachable host, or whether it requires prior authentication. For a stateful configuration mutation with zero annotation coverage, this is a substantial gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short lines, front-loaded with the action and followed by the parameter constraint and example. No filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema covers return values, so the description needn't explain them. However, for a one-shot global configuration tool with no annotations, the description omits persistence semantics, validation behavior, and ordering relative to auth siblings, leaving it adequate but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the schema only declares a bare string, so the description must compensate, and it does: it constrains the value to an absolute http(s) URL and gives a concrete example (https://ctf.example.com). This adds real meaning beyond the schema, though it doesn't cover trailing slashes or path handling.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: configure the CTFd instance this server talks to, which is unambiguous and distinct from siblings like set_token, set_cookie, and login. It stops short of explicitly contrasting itself with those sibling configuration tools, but the resource is clear enough that an agent can pick it out.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this must be called before other CTFd operations, but there is no statement of when to use it, when not to, prerequisites, or how it relates to set_token/set_cookie/login. Implied context only.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_tokenB

Use an API token for authentication (stored in memory only, never logged).

Args: token: CTFd API access token.

ParametersJSON Schema
NameRequiredDescriptionDefault
tokenYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does add genuine behavioral context: the token is 'stored in memory only, never logged.' However, it omits whether it overwrites an existing token, whether it is validated against the server, or how it affects the current session.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One front-loaded sentence with the security-relevant behavior stated up front, followed by a minimal Args block. No padding, though the Args section adds little beyond the parameter name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the memory-only disclosure covers the key safety concern. Still missing for a state-mutating auth tool: replacement semantics, validation behavior, and any failure modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the schema only repeats the property title 'Token'. The description adds a modest gloss ('CTFd API access token'), clarifying the source of the credential, but no format, prefix, or validation expectations for the single required parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: configure authentication with an API token. It is distinguishable from siblings like login and set_cookie by naming the credential type, though it never explicitly contrasts itself with those alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says to 'Use an API token for authentication' but gives no when-to-use guidance relative to login or set_cookie, nor any prerequisite (e.g., that a token must first be obtained from CTFd). Usage is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

submit_flagA

Submit a flag for a challenge.

Safety: requires confirm=True. Provide exactly one of challenge_id or challenge_name. The flag value is never logged.

Args: flag: the flag to submit. challenge_name: name of the challenge to submit against. challenge_id: numeric id of the challenge to submit against. confirm: must be set to True as an explicit submission opt-in.

ParametersJSON Schema
NameRequiredDescriptionDefault
flagYes
confirmNo
challenge_idNo
challenge_nameNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose meaningful traits: an explicit confirm opt-in is required before submission, exactly one identifier must be supplied, and the flag value is never logged. It does not describe what a success/failure response looks like, though an output schema exists to cover returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The safety and exclusivity constraints are front-loaded in the first two lines, then the Args list fills the 0%-coverage schema gap without padding. Every sentence serves selection or invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating submission tool with a confirm gate and an existing output schema, the description covers the safety prerequisite, parameter exclusivity, and privacy behavior. Return handling is delegated to the output schema, so what remains is minimal.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the Args block is doing real work: it documents all four parameters and adds semantics beyond the schema's bare titles, notably that confirm must be True (not merely default) and that challenge_id and challenge_name are mutually exclusive. This mutual-exclusion rule is not encoded in the schema and is genuinely useful.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource ('Submit a flag for a challenge'), so the agent knows exactly what the tool does. It does not explicitly distinguish itself from siblings like unlock_hint or scoreboard, but the action is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete preconditions: 'requires confirm=True' and 'Provide exactly one of challenge_id or challenge_name.' That tells the agent how to call it safely. It stops short of naming when an alternative tool should be used instead, so it is clear context without full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unlock_hintA

Unlock a challenge hint and return its content.

WARNING: on CTFd a hint with a non-zero cost deducts that many points from your account. When two hint IDs are needed (e.g. a hint's prerequisites), unlock them in order.

Args: hint_id: numeric id of the hint (see the challenge tool result).

ParametersJSON Schema
NameRequiredDescriptionDefault
hint_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and it discloses the most important hidden behavior: point deduction on cost-bearing hints and ordering constraints for dependent hints. It omits auth/permission requirements and what happens on a repeat unlock, but the risky side effect is surfaced.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, the cost warning follows immediately, and the Args block is a single line. Slightly redundant with the schema's required-field declaration but not wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter action with an output schema, the description covers what the tool does, the key side effect, and where the ID comes from; return values need not be explained. Missing only edge cases like re-unlocking or error behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate; it does so by explaining that hint_id is the numeric id available in the 'challenge' tool result, which is more useful than a bare type declaration. It adds no validation or format detail beyond that, so not a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Unlock a challenge hint') plus the side effect of returning content, which is enough to separate it from siblings like 'challenge' and 'challenges'. The reference to hint IDs coming from the 'challenge' tool ties it into the workflow explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete context for use: hints cost points when 'cost' is non-zero, and prerequisite hint IDs must be unlocked in order. It does not name an alternative tool or state when *not* to unlock, but the operational conditions are clear.

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.

  1. 14 tool updatesv1.0.4
    • First observedauth_status
    • First observedchallenge
    • First observedchallenges
    • First observeddownload_file
    • First observedhealth
    • First observedinstance_info
    • First observedlogin
    • First observedprogress
    • First observedscoreboard
    • First observedset_base_url
    • First observedset_cookie
    • First observedset_token
    • First observedsubmit_flag
    • First observedunlock_hint

TDQS

A3.6/5.0

Scored across 14 tools

Disambiguation4/5

Most tools have clearly distinct purposes, but the authentication group (set_token, set_cookie, login, auth_status) plus health overlap around session/state checking, and challenge vs challenges differ only by singular/plural which can cause misselection. Descriptions do help disambiguate the intended usage.

Naming Consistency3/5

A mix of conventions: verb_noun tools (set_token, submit_flag, download_file, unlock_hint) coexist with bare-noun tools (challenges, challenge, scoreboard, progress, instance_info, health). Each name is readable in isolation, but there is no single predictable pattern.

Tool Count5/5

14 tools is well within a healthy range and each earns its place, covering setup, auth, challenge interaction, and status without bloat.

Completeness4/5

For a player-facing CTFd client the surface is strong: auth, listing/reading challenges, flag submission, file download, hint unlock, scoreboard, and progress. Minor gaps remain (e.g. category listing, team/teammate endpoints), but core workflows have no dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers