langchain-ai/deepagents · error · ValueError

Server '{server_name}' has type 'stdio' but also declares a

Error message

Server '{server_name}' has type 'stdio' but also declares a 'url' field. Remove 'url' or set `"type": "http"` (or `"sse"`) for a remote server.

What it means

A `stdio` server is a local subprocess launched with `command`/`args`, while `url` only applies to remote transports (http/sse). Declaring both is contradictory, so `_validate_server_config` raises this ValueError to force an unambiguous transport choice.

Source

Thrown at libs/code/deepagents_code/mcp_tools.py:919

            for name, value in headers.items():
                if not isinstance(value, str):
                    error_msg = (
                        f"Server '{server_name}' header {name!r} must be "
                        f"a string, got {type(value).__name__}"
                    )
                    raise TypeError(error_msg)
    elif server_type == "stdio":
        if "command" not in server_config:
            error_msg = f"Server '{server_name}' missing required 'command' field"
            raise ValueError(error_msg)

        if "url" in server_config:
            error_msg = (
                f"Server '{server_name}' has type 'stdio' but also declares "
                "a 'url' field. Remove 'url' or set "
                '`"type": "http"` (or `"sse"`) for a remote server.'
            )
            raise ValueError(error_msg)

        if "args" in server_config and not isinstance(server_config["args"], list):
            error_msg = f"Server '{server_name}' 'args' must be a list"
            raise TypeError(error_msg)

        if "env" in server_config and not isinstance(server_config["env"], dict):
            error_msg = f"Server '{server_name}' 'env' must be a dictionary"
            raise TypeError(error_msg)
    else:
        error_msg = (
            f"Server '{server_name}' has unsupported transport type '{server_type}'. "
            "Supported types: stdio, sse, http"
        )
        raise ValueError(error_msg)

    auth = server_config.get("auth")
    if auth is not None:
        if auth != "oauth":

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Remove the `url` field from the stdio server entry if it should run locally.
  2. Alternatively set `"type": "http"` (or `"sse"`) and keep `url`, removing `command`/`args` if the server is remote.
  3. Ensure only one transport shape remains: (type http/sse + url) or (type stdio/omitted + command).
  4. Re-run `resolve_and_load_mcp_tools` to confirm the fixed entry validates.

Example fix

// before
{"fs": {"type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], "url": "https://mcp.example.com"}}
// after
{"fs": {"type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}}
Defensive patterns

Strategy: validation

Validate before calling

def validate_no_transport_mixing(name: str, cfg: dict) -> None:
    stype = cfg.get("type", "stdio")
    if stype == "stdio" and "url" in cfg:
        raise ValueError(f"Server '{name}' has type 'stdio' but also declares a 'url' field")

Type guard

def has_single_transport_shape(cfg: dict) -> bool:
    stype = cfg.get("type", "stdio")
    if stype in ("http", "sse"):
        return "url" in cfg and "command" not in cfg
    if stype == "stdio":
        return "command" in cfg and "url" not in cfg
    return False

Try / catch

try:
    tools = resolve_and_load_mcp_tools(config)
except ValueError as e:
    if "but also declares a 'url' field" in str(e):
        name = extract_server_name(str(e))
        config["servers"][name].pop("url", None)  # keep local stdio form
        tools = resolve_and_load_mcp_tools(config)
    else:
        raise

Prevention

When it happens

Trigger: A server entry resolving to type `stdio` contains a `url` key — e.g. `{"type": "stdio", "command": "npx", "args": [...], "url": "https://..."}` — validated via `select_server`, `resolve_and_load_mcp_tools`, or the batch config validators.

Common situations: Copying a config template that kept `url` when switching between remote and local forms; adding `url` 'just in case' alongside command config; a server that moved from remote hosting to a local binary without cleaning up the old fields; merged config files from two setups.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/8ec6c3b99631ac3d. Report an issue: GitHub.