MCP Server Integration#
RAGFlow ships an MCP (Model Context Protocol) server that exposes RAGFlow capabilities — retrieval, dataset listing, and chat assistant discovery — as tools consumable by any MCP-compatible client (e.g. Claude Desktop, Cursor).
The server lives at mcp/server/server.py and runs as an independent process alongside the main RAGFlow backend. It communicates with the backend over HTTP (default: http://127.0.0.1:9380) and exposes its own endpoint on port 9382 .
Architecture#
The server is built on mcp.server.lowlevel.Server with a Starlette ASGI layer. It supports two transports simultaneously by default :
| Transport | Endpoint | Flag |
|---|---|---|
| Legacy SSE | /sse + /messages/ | --transport-sse-enabled |
| Streamable HTTP | /mcp | --transport-streamable-http-enabled |
All backend calls go through the RAGFlowConnector class, which wraps httpx.AsyncClient .
Launch Modes#
The server supports two authentication modes :
self-host— single-tenant; a static API key is passed via--api-keyorRAGFLOW_MCP_HOST_API_KEY. All requests use this key.host— multi-tenant; each request must include aBearertoken orx-api-keyheader. AnAuthMiddlewarevalidates presence on/sse,/messages/, and/mcppaths .
Minimal launch (self-host):
uv run mcp/server/server.py --host=127.0.0.1 --port=9382 \
--base-url=http://127.0.0.1:9380 \
--mode=self-host --api-key=ragflow-xxxxx
See docs/develop/mcp/launch_mcp_server.md for full launch documentation.
MCP Tools Exposed#
Three tools are registered via list_tools():
| Tool | Description |
|---|---|
ragflow_retrieval | Semantic/keyword search across datasets; supports dataset_ids, document_ids, pagination, similarity threshold, and reranking |
ragflow_list_datasets | Lists accessible knowledge bases with IDs and descriptions |
ragflow_list_chats | Lists accessible chat assistants with IDs, names, and descriptions |
Tool descriptions are dynamically enriched at startup by calling list_datasets() and list_chats() and appending their output to the description string . This means a failure in either method at tools/list time will crash discovery of all three tools.
Chat Assistant Discovery (list_chats)#
list_chats() calls GET /api/v1/chats and returns newline-delimited JSON — one {"id", "name", "description"} record per line .
/chats API Response Format#
The backend /chats endpoint returns a paginated dict envelope :
{
"code": 0,
"data": {
"chats": [ { "id": "...", "name": "...", ... } ],
"total": 5
}
}
This differs from the /datasets endpoint, which uses a flat data list with total at the top level .
Envelope Handling Bug (Fixed in PR #16639)#
Before PR #16639, list_chats() assumed data was always a list and iterated it directly. Because data is actually a dict, Python yielded the dict's keys (strings), causing 'str' object has no attribute 'get' and crashing tools/list entirely.
The fix adds an isinstance check :
_chats_data = res_json.get("data", [])
if isinstance(_chats_data, dict):
_chats_data = _chats_data.get("chats", [])
This guards against both the current dict envelope and any future flat-list format.
Retrieval Tool Details#
retrieval() posts to /api/v1/retrieval. When dataset_ids is omitted, it auto-resolves all accessible datasets via resolve_dataset_ids() .
Results are enriched with document and dataset metadata from a two-level TTL cache :
- Dataset cache: 32-entry LRU, TTL ~300 s ± 30 s random jitter
- Document cache: per-dataset, same TTL policy
Use force_refresh: true to bypass the cache when fresh metadata is needed .
Key Configuration#
All options can be set via CLI flags or environment variables :
| Env Var | CLI Flag | Default |
|---|---|---|
RAGFLOW_MCP_BASE_URL | --base-url | http://127.0.0.1:9380 |
RAGFLOW_MCP_HOST | --host | 127.0.0.1 |
RAGFLOW_MCP_PORT | --port | 9382 |
RAGFLOW_MCP_LAUNCH_MODE | --mode | self-host |
RAGFLOW_MCP_HOST_API_KEY | --api-key | (empty) |
RAGFLOW_MCP_TRANSPORT_SSE_ENABLED | --transport-sse-enabled | true |
RAGFLOW_MCP_TRANSPORT_STREAMABLE_ENABLED | --transport-streamable-http-enabled | true |
RAGFLOW_MCP_JSON_RESPONSE | --json-response | true |