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
- Remove the `url` field from the stdio server entry if it should run locally.
- Alternatively set `"type": "http"` (or `"sse"`) and keep `url`, removing `command`/`args` if the server is remote.
- Ensure only one transport shape remains: (type http/sse + url) or (type stdio/omitted + command).
- 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
- Decide the transport first: local binary (stdio + command) or remote URL (http/sse + url); never include both field sets.
- When converting a remote server to local (or vice versa), delete the obsolete fields in the same edit.
- Avoid 'just in case' fields in server configs.
- Schema-validate config files with a JSON Schema that forbids cross-field combinations.
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
- {prefix}.args must be a list, got {type(args).__name__}
- Server '{server_name}' missing required 'command' field
- Server '{server_name}' 'args' must be a list
- Server '{server_name}' 'env' must be a dictionary
- Server '{server_name}' uses stdio transport; 'auth: oauth' i
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/8ec6c3b99631ac3d.
Report an issue: GitHub.