From 90359344323856ca31ba4b5e528ffa1c63782551 Mon Sep 17 00:00:00 2001 From: George Pickett Date: Sun, 6 Sep 2026 07:54:32 -0700 Subject: [PATCH] feat(mcp): add optional Parallel Search server (#5028) * feat(mcp): add optional Parallel Search server * docs(mcp): document Parallel Search opt-in and data sharing * docs(mcp): address Parallel Search review feedback --- backend/docs/MCP_SERVER.md | 37 +++++++++++++++++++++++++ backend/tests/test_mcp_client_config.py | 23 +++++++++++++++ extensions_config.example.json | 6 ++++ 3 files changed, 66 insertions(+) diff --git a/backend/docs/MCP_SERVER.md b/backend/docs/MCP_SERVER.md index d4de6df15..f2ecd58fb 100644 --- a/backend/docs/MCP_SERVER.md +++ b/backend/docs/MCP_SERVER.md @@ -80,6 +80,43 @@ For Docker, point `url` at the OpenViking address reachable from the Gateway container, such as `http://openviking:1933/mcp` for a shared Compose network or `http://host.docker.internal:1933/mcp` for a host-installed server. +## Parallel Search (optional) + +The `parallel-search` entry in `extensions_config.example.json` is disabled by +default. To opt in, copy that entry into `mcpServers` in your root +`extensions_config.json`, set `"enabled": true`, and restart DeerFlow. It connects +to `https://search.parallel.ai/mcp` over HTTP and adds Parallel's search and fetch +tools. With DeerFlow's default tool-name prefix, the agent sees +`parallel-search_web_search` and `parallel-search_web_fetch`. Existing search +providers and defaults stay unchanged. + +This is a third-party service operated by Parallel.ai. Search calls send +objectives and queries to Parallel; fetch calls send requested page URLs and +any extraction objective. These inputs can contain information from your +conversation, so enable it only if you are comfortable sending that data to +Parallel. + +Access is anonymous by default: no API key or authentication headers are needed. +For higher rate limits, optionally add this `headers` field to the +`parallel-search` entry in your local `extensions_config.json`: + +```json +{ + "headers": { + "Authorization": "$PARALLEL_AUTHORIZATION" + } +} +``` + +Set `PARALLEL_AUTHORIZATION` in the DeerFlow backend's environment to the full +value `Bearer `, then restart DeerFlow. Include `Bearer ` +in the environment variable because DeerFlow expands only whole-string +`$ENV_VAR` references, not `Bearer $ENV_VAR`. Keep the actual key out of committed +files. Remove the `headers` field and restart DeerFlow to return to anonymous +access. See the +[Parallel Search MCP documentation](https://docs.parallel.ai/integrations/mcp/search-mcp) +for details. + ## Routing Hints Use `routing` when an MCP server should be preferred for specific requests, such diff --git a/backend/tests/test_mcp_client_config.py b/backend/tests/test_mcp_client_config.py index 5d3d28650..0a79eb26a 100644 --- a/backend/tests/test_mcp_client_config.py +++ b/backend/tests/test_mcp_client_config.py @@ -230,3 +230,26 @@ def test_build_server_params_excludes_tool_call_timeout(): "command": "npx", "args": ["-y", "my-mcp-server"], } + + +def test_parallel_search_example_is_explicitly_opt_in_and_uses_anonymous_http_transport(): + """The shipped example must not enable or authenticate the optional free server.""" + import json + from pathlib import Path + + example = json.loads((Path(__file__).parents[2] / "extensions_config.example.json").read_text()) + parallel = example["mcpServers"]["parallel-search"] + + assert parallel["enabled"] is False + assert parallel["type"] == "http" + assert parallel["url"] == "https://search.parallel.ai/mcp" + assert "headers" not in parallel + + config = ExtensionsConfig.model_validate(example) + assert "parallel-search" not in build_servers_config(config) + + config.mcp_servers["parallel-search"].enabled = True + assert build_servers_config(config)["parallel-search"] == { + "transport": "http", + "url": "https://search.parallel.ai/mcp", + } diff --git a/extensions_config.example.json b/extensions_config.example.json index f2c701cdd..ac336e7ac 100644 --- a/extensions_config.example.json +++ b/extensions_config.example.json @@ -20,6 +20,12 @@ "tool_call_timeout": 60, "description": "GitHub MCP server for repository operations" }, + "parallel-search": { + "enabled": false, + "type": "http", + "url": "https://search.parallel.ai/mcp", + "description": "Optional anonymous Parallel Search tools for web search and fetching requested URLs" + }, "openviking": { "enabled": false, "type": "http",