diff --git a/backend/packages/harness/deerflow/config/extensions_config.py b/backend/packages/harness/deerflow/config/extensions_config.py index 425da12b84..18b8cd5e2d 100644 --- a/backend/packages/harness/deerflow/config/extensions_config.py +++ b/backend/packages/harness/deerflow/config/extensions_config.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Any, Literal -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict, Field, model_validator from deerflow.config.runtime_paths import existing_project_file @@ -47,6 +47,24 @@ class McpServerConfig(BaseModel): description: str = Field(default="", description="Human-readable description of what this MCP server provides") model_config = ConfigDict(extra="allow") + @model_validator(mode="before") + @classmethod + def _accept_transport_alias(cls, data: Any) -> Any: + """Accept the MCP-spec ``transport`` field as an alias for ``type``. + + The official MCP configuration schema uses ``transport`` to indicate + the transport mechanism (``stdio``/``sse``/``http``). Earlier versions + of this project only honored ``type``, which caused remote SSE/HTTP + servers configured with just ``transport`` to be incorrectly treated as + ``stdio`` (the default). This validator normalizes the two so either + spelling works, with ``type`` taking precedence when both are provided. + """ + if isinstance(data, dict): + transport = data.get("transport") + if transport and not data.get("type"): + data = {**data, "type": transport} + return data + class SkillStateConfig(BaseModel): """Configuration for a single skill's state.""" diff --git a/backend/tests/test_mcp_client_config.py b/backend/tests/test_mcp_client_config.py index ca4d0de597..3216b59fa8 100644 --- a/backend/tests/test_mcp_client_config.py +++ b/backend/tests/test_mcp_client_config.py @@ -83,6 +83,41 @@ def test_build_server_params_rejects_unsupported_transport(): build_server_params("bad-transport", config) +@pytest.mark.parametrize("transport", ["sse", "http"]) +def test_mcp_server_config_accepts_transport_alias(transport: str): + """The MCP-spec ``transport`` field should be accepted as an alias for ``type``. + + Regression test for https://github.com/bytedance/deer-flow/issues/3238 — a + remote MCP server configured with only ``transport: sse`` was previously + misidentified as ``stdio`` (the default for ``type``). + """ + config = McpServerConfig.model_validate( + { + "transport": transport, + "url": "https://example.com/mcp", + } + ) + + assert config.type == transport + + params = build_server_params("aliased-server", config) + assert params["transport"] == transport + assert params["url"] == "https://example.com/mcp" + + +def test_mcp_server_config_type_takes_precedence_over_transport(): + """When both ``type`` and ``transport`` are provided, ``type`` wins.""" + config = McpServerConfig.model_validate( + { + "type": "http", + "transport": "sse", + "url": "https://example.com/mcp", + } + ) + + assert config.type == "http" + + def test_build_servers_config_returns_empty_when_no_enabled_servers(): extensions = ExtensionsConfig( mcp_servers={