diff --git a/docs/webui.md b/docs/webui.md index 82eb12dd..56fe2936 100644 --- a/docs/webui.md +++ b/docs/webui.md @@ -88,6 +88,12 @@ nanobot can call from a chat. CLI Apps install local adapters that nanobot runs on your machine; they do not modify the native apps themselves. MCP presets add predefined MCP server configurations. +Some MCP presets connect to hosted keyless endpoints. For example, the Firecrawl +preset uses Firecrawl's hosted MCP endpoint for search, scrape, crawl, and +extraction tools without requiring an API key. This does not replace nanobot's +built-in web search provider; mention the Firecrawl MCP preset with `@` when a +turn needs Firecrawl's richer web data tools. + After an App or MCP preset is available, mention it from the composer with `@` to attach that capability to the next message. diff --git a/nanobot/webui/mcp_presets_api.py b/nanobot/webui/mcp_presets_api.py index d982feb6..5c3f31b8 100644 --- a/nanobot/webui/mcp_presets_api.py +++ b/nanobot/webui/mcp_presets_api.py @@ -173,25 +173,19 @@ MCP_PRESETS: tuple[McpPreset, ...] = ( category="web", description="Scrape, crawl, search, and extract web pages through Firecrawl's MCP server.", docs_url="https://docs.firecrawl.dev/use-cases/developers-mcp", - transport="stdio", + transport="streamableHttp", install_supported=True, brand_domain="firecrawl.dev", brand_color="#EB5E28", - requires="Node.js, npx, and Firecrawl API key", + requires="Network access", server=MCPServerConfig( - type="stdio", - command="npx", - args=["-y", "firecrawl-mcp"], + type="streamableHttp", + url="https://mcp.firecrawl.dev/v2/mcp", tool_timeout=60, ), - fields=( - McpPresetField( - name="firecrawl_api_key", - label="Firecrawl API key", - target=("env", "FIRECRAWL_API_KEY"), - env_var="FIRECRAWL_API_KEY", - placeholder="fc-...", - ), + note=( + "Uses Firecrawl Keyless through the hosted MCP endpoint. No API key is required for " + "the built-in preset; use a custom MCP server URL if you want account-specific limits." ), ), McpPreset( diff --git a/tests/webui/test_mcp_presets_api.py b/tests/webui/test_mcp_presets_api.py index 471aee95..f1bd12e0 100644 --- a/tests/webui/test_mcp_presets_api.py +++ b/tests/webui/test_mcp_presets_api.py @@ -135,26 +135,29 @@ def test_enable_no_auth_remote_presets_write_url(tmp_path, monkeypatch: pytest.M mcp_presets_action("enable", {"name": ["microsoft-learn"]}) mcp_presets_action("enable", {"name": ["exa"]}) + mcp_presets_action("enable", {"name": ["firecrawl"]}) config = load_config() assert config.tools.mcp_servers["microsoft-learn"].url == "https://learn.microsoft.com/api/mcp" assert config.tools.mcp_servers["exa"].url == "https://mcp.exa.ai/mcp" + assert config.tools.mcp_servers["firecrawl"].url == "https://mcp.firecrawl.dev/v2/mcp" -def test_enable_firecrawl_writes_scrubbed_env(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None: +def test_firecrawl_preset_is_keyless(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None: _use_config(tmp_path, monkeypatch) - payload = mcp_presets_action( - "enable", - { - "name": ["firecrawl"], - "firecrawl_api_key": ["fc-secret"], - }, - ) + payload = mcp_presets_action("enable", {"name": ["firecrawl"]}) - assert "fc-secret" not in str(payload) + row = next(item for item in payload["presets"] if item["name"] == "firecrawl") + assert row["transport"] == "streamableHttp" + assert row["requires"] == "Network access" + assert row["required_fields"] == [] + assert row["configured"] is True + assert "Keyless" in row["note"] config = load_config() - assert config.tools.mcp_servers["firecrawl"].env["FIRECRAWL_API_KEY"] == "fc-secret" + assert config.tools.mcp_servers["firecrawl"].type == "streamableHttp" + assert config.tools.mcp_servers["firecrawl"].url == "https://mcp.firecrawl.dev/v2/mcp" + assert config.tools.mcp_servers["firecrawl"].env == {} def test_remove_mcp_preset_updates_config(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None: