diff --git a/tests/tools/test_mcp_preflight_content_type.py b/tests/tools/test_mcp_preflight_content_type.py index ae9e7173bd6..54e0b21b903 100644 --- a/tests/tools/test_mcp_preflight_content_type.py +++ b/tests/tools/test_mcp_preflight_content_type.py @@ -305,6 +305,41 @@ def test_run_skips_preflight_for_oauth(monkeypatch): ) +def test_run_skips_preflight_when_skip_preflight_set(monkeypatch): + """``skip_preflight: true`` in server config bypasses the probe entirely. + + Escape hatch for valid Streamable HTTP servers whose HEAD/GET answers a + non-MCP content type (and whose POST probe still can't be validated, e.g. + non-OAuth auth schemes the probe headers don't satisfy). + """ + import tools.mcp_tool as _mcp + + preflight_calls: list[str] = [] + + async def _inner(): + async def _fake_preflight(self, url, **kwargs): + preflight_calls.append(url) + + async def _fake_run_http(self, config): + raise asyncio.CancelledError() + + monkeypatch.setattr(_mcp, "_validate_remote_mcp_url", lambda n, u: None) + monkeypatch.setattr(_mcp.MCPServerTask, "_preflight_content_type", _fake_preflight) + monkeypatch.setattr(_mcp.MCPServerTask, "_run_http", _fake_run_http) + + task = _mcp.MCPServerTask("skip-preflight-test") + with pytest.raises(asyncio.CancelledError): + await task.run({ + "url": "https://mcp.example.com/mcp", + "skip_preflight": True, + }) + + asyncio.run(_inner()) + assert preflight_calls == [], ( + "_preflight_content_type must not be called when skip_preflight is set" + ) + + def test_ssl_verify_and_cert_forwarded(monkeypatch): captured: dict = {} diff --git a/tools/mcp_tool.py b/tools/mcp_tool.py index b6279f70215..98edbd0e00c 100644 --- a/tools/mcp_tool.py +++ b/tools/mcp_tool.py @@ -34,6 +34,10 @@ Example config:: headers: Authorization: "Bearer sk-..." timeout: 180 + skip_preflight: true # bypass the content-type probe for a valid + # Streamable HTTP endpoint that answers HEAD/GET + # with a non-MCP content type but serves real + # MCP over POST. Default: false. searxng: url: "http://localhost:8000/sse" transport: sse # use SSE transport instead of Streamable HTTP