deer-flow-mcp
Provides control over LangGraph-based DeerFlow runs, including starting runs with a configurable recursion limit and inspecting run status.
Connects to a deployed DeerFlow instance through its nginx entry point over HTTP to drive research and thread/run/artifact operations.
The MCP server runs on Node.js, requiring version >= 20.18.1.
The deer-flow-mcp server is published on npm and can be run directly with npx without a local build.
DeerFlow runs are driven by models; the server lists available models (OpenAI-compatible) via the internal-token mode.
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., "@deer-flow-mcp start a deep research on the future of renewable energy and send me the report"
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.
deer-flow-mcp
An MCP (Model Context Protocol) server that drives a deployed DeerFlow instance over its HTTP API. It exposes DeerFlow's capabilities — deep research, model listing, and full thread/run/artifact control — as MCP tools, so any MCP-compatible client (Kilo, Claude Code, Cursor, VS Code, and others) can use them.
How it works
deer-flow-mcp is a thin, stateless adapter. It does not run DeerFlow itself; it talks to an
already-deployed DeerFlow instance (the nginx entry point) using the credentials you configure.
Each MCP tool maps to one or more DeerFlow HTTP routes and returns the result as MCP content.
Related MCP server: mcp-flowise
Capabilities
Deep research — kick off a DeerFlow "super agent" run on a topic and get back a structured, cited report saved as an artifact.
Model listing — list the models available to DeerFlow (email/password or internal-token mode).
Thread / run / artifact control — create threads, start and inspect runs, track status, and retrieve artifacts and reports.
Requirements
Node.js >= 20.18.1
A deployed DeerFlow instance reachable at
DEERFLOW_BASE_URL
Install
deer-flow-mcp is published on npm and runs directly with npx — no local build required:
npx -y deer-flow-mcp --versionTo build from source (for development or contribution), see Development.
Configuration
All configuration is environment-driven — there is no config file and no .env loading. The
server reads process.env directly, so an MCP client must pass the DeerFlow variables through its
own env / environment field (see Install in an MCP client).
The server fails fast with a descriptive error at startup if required values are missing, so the MCP client gets a clean error instead of a cryptic first-request failure.
Variable | Required | Description |
| yes | Base URL of the deployed DeerFlow instance (trailing slashes ignored) |
| one of three | Account email; used with |
| one of three | Account password; used with |
| one of three | Personal Access Token (starts with |
| one of three | Gateway internal token; full access (models + artifact files) |
| no | Used only with internal-token mode |
| no | Default model when a tool call omits |
| no | Default LangGraph recursion limit (default |
| no | Per-request HTTP timeout in ms (default |
| no | Base URL for "open in DeerFlow" links (defaults to |
| no | Seconds without activity before a running run is reported as stalled (default |
| no | Softer "between steps" signal, below the stall threshold (default |
| no | Cap on |
| no | How often a |
| no | How often the client polls the DeerFlow API when the SSE join stream is unavailable (default |
Authentication
deer-flow-mcp authenticates to DeerFlow one of three ways — a discriminated union, so set
exactly one of the credential modes (email/password is tried first, then PAT, then internal
token):
Email/password (
DEERFLOW_EMAIL+DEERFLOW_PASSWORD) — logs in like the web UI (POST /api/v1/auth/login/local) and carries the resulting session cookie (plus the CSRF token) on every call. This is the same credential you type into the browser: it works on every deployment (no DB, no internal secret) and grants full user access, including models and artifact files. Both variables must be set together; the login happens lazily on first use and is retried once if the session expires.PAT (
DEERFLOW_PAT) — a per-user Personal Access Token (dfp_…), sent asAuthorization: Bearer dfp_…. Restricted to the thread/run lifecycle routes;deerflow_list_modelsanddeerflow_get_artifactreturn 403 for PAT callers.Internal token (
DEERFLOW_INTERNAL_TOKEN) — the deployment-levelDEER_FLOW_INTERNAL_AUTH_TOKENshared secret, sent asX-DeerFlow-Internal-Token(optionally withX-DeerFlow-Owner-User-Id). Full access, including models and artifact files.
All three target the same entry point: the nginx reverse proxy, default http://<host>:2026
(the port is configurable via the PORT env var). That is the URL you put in
DEERFLOW_BASE_URL.
Getting a Personal Access Token (DEERFLOW_PAT)
A PAT is a per-user credential created from the Gateway API while you are logged in. There is
no dedicated page for it in the web UI, and it requires a database-backed deployment (SQLite
or PostgreSQL) — a memory-only instance rejects Bearer tokens and the PAT routes return 503.
Sign in to the web UI. Open your DeerFlow instance.
First boot: open
/setupand create the first admin account (email + password).Afterwards: open
/loginand sign in with your email and password (or your SSO provider). A successful login sets theaccess_tokensession cookie.
Create the token from the API. Copy your
access_tokencookie value (browser DevTools → Application → Cookies, or theCookieheader of any request in Network), then:curl -s -X POST "$DEERFLOW_BASE_URL/api/v1/auth/pats" \ -H "Content-Type: application/json" \ -H "Cookie: access_token=<ACCESS_TOKEN>" \ -d '{ "name": "deer-flow-mcp", "scopes": ["threads:read", "threads:write", "runs:create", "runs:read", "runs:cancel"], "expires_in_days": 365 }'The
tokenfield in the response is yourdfp_…value. It is shown exactly once and cannot be retrieved again — only its SHA-256 digest is stored. Save it immediately.Use it. Put that value in
DEERFLOW_PAT.
The scopes above cover every deer-flow-mcp tool except deerflow_list_models and
deerflow_get_artifact (both 403 for PAT callers — use email/password or an internal token if
you need them).
You can list your tokens with GET /api/v1/auth/pats and revoke one with
DELETE /api/v1/auth/pats/{pat_id}; revocation is immediate.
Getting the internal token (DEERFLOW_INTERNAL_TOKEN)
The internal token is a deployment-level secret set on the Gateway — it is not tied to any
user and is not created from the web UI. Its value is the Gateway's DEER_FLOW_INTERNAL_AUTH_TOKEN
environment variable.
Docker (
make up/ the bundled deploy script) — the token is generated automatically and persisted to$DEER_FLOW_HOME/.internal-auth-token(mode600).DEER_FLOW_HOMEdefaults to<repo>/backend/.deer-flowon the host (mounted into the container at/app/backend/.deer-flow), so read it with:cat backend/.deer-flow/.internal-auth-token # or from the running gateway container: docker compose exec gateway printenv DEER_FLOW_INTERNAL_AUTH_TOKENHelm / Kubernetes — it is stored in the chart's app Secret under the key
DEER_FLOW_INTERNAL_AUTH_TOKEN(the Secret name is printed in the install NOTES):kubectl -n <namespace> get secret <app-secret> \ -o jsonpath='{.data.DEER_FLOW_INTERNAL_AUTH_TOKEN}' | base64 -dManual — set
DEER_FLOW_INTERNAL_AUTH_TOKENto a long random secret in your.envand restart the stack, then use that same value here.
Put the value in DEERFLOW_INTERNAL_TOKEN. To isolate runs under a specific owner, also set
DEERFLOW_OWNER_USER_ID (sent as X-DeerFlow-Owner-User-Id).
Install in an MCP client
deer-flow-mcp is a local stdio server started with npx -y deer-flow-mcp. In every client
config below the server is launched via npx, and you must pass at least DEERFLOW_BASE_URL and
one credential (DEERFLOW_EMAIL + DEERFLOW_PASSWORD, DEERFLOW_PAT, or
DEERFLOW_INTERNAL_TOKEN) through the env / environment field. For remote/shared access over
Streamable HTTP instead, see Usage.
Kilo
Kilo reads MCP servers from kilo.json. Use the project file ./kilo.json (or .kilo/kilo.json)
for a single project, or the global ~/.config/kilo/kilo.json for all projects.
{
"mcp": {
"deerflow": {
"type": "local",
"command": ["npx", "-y", "deer-flow-mcp"],
"environment": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
},
"enabled": true
}
}
}Notes:
commandis an array; the first element is the executable (npx), the rest are its args.Environment variables go in the
environmentobject (KEY: value).Email/password is the simplest full-access option and is tried first. As alternatives:
DEERFLOW_PAT(threads/runs routes only) orDEERFLOW_INTERNAL_TOKEN(deployment-level full access, optionally withDEERFLOW_OWNER_USER_ID).Restart Kilo (or reload MCP servers) to pick up the change.
Add it with the CLI (user scope, so it is available across projects):
claude mcp add --scope user \
--env DEERFLOW_BASE_URL=https://deerflow.example.com \
--env DEERFLOW_EMAIL=you@example.com \
--env DEERFLOW_PASSWORD=... \
--transport stdio \
deerflow -- npx -y deer-flow-mcpOr add a deerflow entry under mcpServers in a project .mcp.json (shared with your team) or
in ~/.claude.json (user scope):
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Verify with claude mcp get deerflow or /mcp inside a session.
Add a deerflow entry under mcpServers in ~/.cursor/mcp.json (global) or .cursor/mcp.json
(per project):
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Add a deerflow entry under servers in .vscode/mcp.json (per project) or in your user
mcp.json:
{
"servers": {
"deerflow": {
"type": "stdio",
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Add a [mcp_servers.deerflow] table to ~/.codex/config.toml (or a project-scoped
.codex/config.toml):
[mcp_servers.deerflow]
command = "npx"
args = ["-y", "deer-flow-mcp"]
[mcp_servers.deerflow.env]
DEERFLOW_BASE_URL = "https://deerflow.example.com"
DEERFLOW_EMAIL = "you@example.com"
DEERFLOW_PASSWORD = "..."Or add it with the CLI:
codex mcp add deerflow \
--env DEERFLOW_BASE_URL=https://deerflow.example.com \
--env DEERFLOW_EMAIL=you@example.com \
--env DEERFLOW_PASSWORD=... \
-- npx -y deer-flow-mcpVerify with codex mcp list or /mcp in the TUI.
Add a deerflow entry under mcpServers in ~/.gemini/settings.json:
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Add a deerflow entry under context_servers in your Zed settings.json:
{
"context_servers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Add a deerflow entry under mcpServers in .cline/mcp_settings.json (or add it from the Cline
MCP Servers UI):
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
},
"disabled": false,
"autoApprove": []
}
}
}Add a deerflow entry under mcpServers in your Roo Code MCP configuration:
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Add a deerflow entry under mcpServers in your claude_desktop_config.json:
{
"mcpServers": {
"deerflow": {
"command": "npx",
"args": ["-y", "deer-flow-mcp"],
"env": {
"DEERFLOW_BASE_URL": "https://deerflow.example.com",
"DEERFLOW_EMAIL": "you@example.com",
"DEERFLOW_PASSWORD": "..."
}
}
}
}Restart Claude Desktop after saving.
Available MCP tools
Tool | Description |
| Start a deep-research run on a fresh thread. Args: |
| Send a message to a DeerFlow thread and start a run. Args: |
| Check a run's status, optionally waiting up to |
| Get live progress: status, live counters, recent activity (one-line event summaries), the plan-mode todo checklist, and stall/quiet detection. Args: |
| Block server-side until new activity, a terminal status, or timeout — one call replaces many polls. Args: |
| Fetch the synthesized report (title, assistant message, artifact paths). Args: |
| List recent threads. Args: optional |
| Cancel (interrupt) an in-flight run. Args: |
| List artifact file paths produced by a thread. Args: |
| Fetch one artifact (inline text, or a URL for binary files). Args: |
| List configured models (name, display name, capability flags). No args. Not available with a PAT (email/password or internal token required). |
The server also advertises MCP instructions that walk a client through the typical deep-research
flow: deerflow_research → wait with deerflow_wait_activity (loop on last_event_seq) →
deerflow_get_report → deerflow_get_artifact, with deerflow_run_status / deerflow_run_progress
for quick non-blocking checks and the report + each artifact also exposed as MCP resources
(deerflow://threads/{thread_id}/report, deerflow://threads/{thread_id}/artifacts/{path}).
Design decisions
No MCP Tasks extension (SEP-1686)
The MCP Tasks extension (tasks/get|result|list|cancel) is intentionally not implemented.
SDK 2.0.0 ships no Tasks runtime (TaskRequestMethod is excluded from the typed method surface),
and a DeerFlow run is already a durable, addressable job keyed by thread_id / run_id —
deerflow_wait_activity (long-poll) and deerflow_run_status (poll) are the spec's async-job
surface, and deerflow_get_report plus the resources read the result. Revisit only if/when the
SDK adds a Tasks runtime.
Usage
Run over stdio (the default MCP transport for local clients):
npx -y deer-flow-mcpRun over Streamable HTTP for remote or shared access (default port 3000, override with
--port):
npx -y deer-flow-mcp --transport http --port 3000For a remote instance, a client points at the resulting URL (e.g. http://localhost:3000) with a
url / remote entry instead of launching a local command.
Or, after a local build, use the package binary:
deer-flow-mcp --transport httpCLI options:
Flag | Description | Default |
| Transport type |
|
| Port for the HTTP transport |
|
| Print the version | — |
Development
To build from source:
pnpm install # install dependencies
pnpm build # compile to dist/
pnpm typecheck # tsc --noEmit
pnpm lint # eslint
pnpm test # vitest run
pnpm format # prettier --write .Run the built server locally:
node dist/index.js # stdio
node dist/index.js --transport http --port 3000 # Streamable HTTPThe same targets are available via the Makefile (see make help):
make install
make build
make check # typecheck + lint + test
make start # build then run the HTTP serverPublishing
npm publish # or: pnpm publishThe prepublishOnly script runs typecheck, lint, test, and build automatically before publishing,
so the published package is always built and verified.
Security
Never commit
.envor secrets; only.env.exampleis tracked.Tokens are credentials — they are sent as auth headers and must never be logged.
All outbound traffic goes to
DEERFLOW_BASE_URL.
Available Tools
11 toolsdeerflow_cancel_runCancel RunAIdempotent
Cancel an in-flight DeerFlow run (interrupts it). Returns the accepted status.
Inputs: run_id (required), thread_id (required). Returns: run_id, status, thread_id
deerflow_chatSend Chat MessageA
Send a message to a DeerFlow thread and start a run. Omit thread_id to create a new thread, or pass an existing thread_id to continue a conversation. Returns immediately with the thread/run ids and a web URL; poll deerflow_run_status, then deerflow_get_report.
Inputs: message (required), model, thread_id, recursion_limit. Returns: run_id, status, web_url, thread_id
deerflow_get_artifactGet ArtifactARead-onlyIdempotent
Fetch a single artifact file from a DeerFlow thread. Text-like files (markdown, json, csv, plain text) are returned inline as content; binary files return a URL reference instead. Note: with a Personal Access Token this endpoint is not in the PAT route allowlist — an internal token is required.
Inputs: path (required), thread_id (required). Returns: url, note, path, content, +1 more
deerflow_get_reportGet ReportARead-onlyIdempotent
Fetch the synthesized report for a DeerFlow thread: the most recent assistant message, its title, and any produced artifact file paths. Resolves the report text through a fallback chain (run messages → thread state → summary) and, when no assistant message exists, auto-inlines the first text artifact (≤256 KB) as the report. Also reports the run's terminal status and where the text came from (report_source). Call after a run reaches a terminal status. Optionally pass run_id to scope the report to a specific run.
Inputs: thread_id (required), run_id. Returns: title, report, web_url, terminal, +5 more
deerflow_list_artifactsList ArtifactsARead-onlyIdempotent
List the artifact file paths produced by a DeerFlow thread (e.g. reports, generated files). Pass a path to deerflow_get_artifact to read its content.
Inputs: thread_id (required). Returns: artifacts
deerflow_list_modelsList ModelsARead-onlyIdempotent
List the models configured on the DeerFlow instance (name, display name, and capability flags). Use a returned name for the model argument of deerflow_research / deerflow_chat. Note: with a Personal Access Token this endpoint is not in the PAT route allowlist — an internal token is required.
Inputs: no named parameters. Returns: models
deerflow_list_threadsList ThreadsARead-onlyIdempotent
List recent DeerFlow threads (id, title, status, timestamps). Use the returned thread_id with deerflow_chat to continue a conversation or deerflow_get_report to read a finished one.
Inputs: limit, include_archived. Returns: threads
deerflow_researchStart Deep ResearchA
Kick off a long-running deep-research run on a fresh DeerFlow thread. Returns immediately with the thread/run ids and a web URL; poll deerflow_run_status until it reaches a terminal status, then call deerflow_get_report to read the findings. Deep research takes minutes to ~45 minutes and never blocks this call.
Inputs: topic (required), focus, model, recursion_limit. Returns: run_id, status, web_url, thread_id
deerflow_run_progressGet Run ProgressARead-onlyIdempotent
Get live progress for a DeerFlow run: status + live counters (llm_call_count, message_count, total_tokens), recent activity (the latest events as one-line summaries, e.g. tool calls and their results), the plan-mode todo checklist, and stall/quiet detection (stalled: true when no activity for longer than the stall threshold; quiet: true for a softer 'between steps' signal; next_step: a human hint pointing at the web UI and deerflow_cancel_run). Pass since_seq (the last_event_seq from a previous response) to return only new events. Requires session or internal-token auth: the event stream and thread state are not reachable with a Personal Access Token.
Inputs: run_id (required), thread_id (required), since_seq, activity_limit. Returns: hint, error, quiet, todos, +18 more
deerflow_run_statusGet Run StatusARead-onlyIdempotent
Check the status of a DeerFlow run. Optionally wait up to wait_seconds (capped at 30s) for it to reach a terminal status before returning, to reduce polling round-trips. Terminal statuses: success, error, timeout, interrupted. Also returns live counters (llm_call_count, message_count, total_tokens) and elapsed/last-update times: the counters advance while the run is working, so if they stop moving for several minutes the run may be stalled — use deerflow_run_progress or deerflow_wait_activity for event-level detail.
Inputs: run_id (required), thread_id (required), wait_seconds. Returns: error, run_id, status, terminal, +8 more
deerflow_wait_activityWait for Run ActivityARead-onlyIdempotent
Block server-side until the run produces new activity, reaches a terminal status, or the timeout elapses — one call replaces many status polls. The server joins the run's live event stream (falling back to polling when the stream is unavailable), so it returns the moment new activity appears rather than on a fixed tick. Returns reason ('terminal' | 'activity' | 'timeout'), waited_seconds, timeout_seconds, the new activity since since_seq (one-line summaries), the plan-mode todo checklist, quiet/stall detection, and a next_step hint. Pass the returned last_event_seq as since_seq on the next call to continue from where you left off. While waiting it emits MCP progress notifications (elapsed/timeout) when the client supplies a progress token. Cancelling the request from the client aborts the wait and returns stop_reason 'cancelled_by_client'. Requires session or internal-token auth.
Inputs: run_id (required), thread_id (required), since_seq, timeout_seconds. Returns: hint, error, quiet, todos, +21 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Most tools target distinct lifecycle stages, but deerflow_run_status, deerflow_run_progress, and deerflow_wait_activity all revolve around checking run state and overlap in returned data (status, counters, activity). The descriptions do provide clear usage guidance, distinguishing polling, detailed progress, and blocking waits, so confusion is limited but possible. deerflow_research and deerflow_chat also both start runs, though the fresh-thread deep-research vs. continuation-chat distinction is clear.
Every tool uses the same deerflow_ prefix and snake_case, with predictable action-oriented names like get_report, list_threads, cancel_run, and wait_activity. The only minor variation is research/chat lacking an explicit object noun, but the pattern remains overwhelmingly consistent and readable.
Eleven tools is well within the ideal 3-15 range and maps tightly to the deep-research lifecycle: starting runs, monitoring them, retrieving reports/artifacts, listing threads/models, and cancelling work. Each tool has a clear role, and no tool feels redundant or trivial.
The lifecycle is well covered: start research/chat, monitor status/progress/wait, cancel, fetch reports, list/get artifacts, and list threads/models. Minor gaps include no operation to delete threads/artifacts or fetch full details for a single thread beyond list output, but agents can work around these in most workflows.
Maintenance
Related MCP Connectors
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Connect AI clients to your Dactic work context through a hosted MCP service.
Host any HTTP API as a standard MCP server; auto-distribute to 12+ mainstream agent platforms.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes DeerFlow's multi-agent capabilities (deep research, data analysis, chart visualization, PPT/image generation, consulting) via the Model Context Protocol, enabling any MCP client to invoke these skills through a thin server wrapper.1MIT
- AlicenseAqualityDmaintenanceExposes local Flowise chatflows as MCP tools, enabling listing and running chatflows from any MCP client.243 npmMIT
- AlicenseNot gradedqualityDmaintenanceConverts any MCP server into simple HTTP endpoints, enabling AI agents that only support HTTP (like ChatGPT Custom GPT or web_fetch) to use MCP tools.MIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables remote MCP access to tools for URL-to-markdown conversion, web and image search, academic search, embeddings, reranking, classification, deduplication, and PDF extraction.Apache 2.0