langchain-ai/deepagents · error · MCPConfigError
{str(exc)}
Error message
{str(exc)} What it means
`login` resolves the server's `${VAR}` env references and field types via `resolve_mcp_server_env` before starting the OAuth flow. If that resolution raises `RuntimeError` (unset env var / malformed `${...}`) or `TypeError` (wrong field type), login re-raises it as `MCPConfigError` (a `ValueError`) so existing config-error handling and `format_login_failure` keep the actionable, field-scoped message instead of collapsing it to a bare `RuntimeError`/`TypeError`.
Source
Thrown at libs/code/deepagents_code/mcp_auth.py:2200
# OAuth login is discovery-based (RFC 9728), so it works for any remote
# http/sse server — whether the config opted in with `auth: oauth` or the
# server was auto-detected as needing auth via a 401 challenge. Only the
# transport needs gating; stdio servers can't speak OAuth.
transport = _resolve_server_type(server_config)
if transport not in {"http", "sse"}:
msg = (
f"Server '{server_name}' uses {transport!r} transport; "
"OAuth login is only valid for http/sse."
)
raise ValueError(msg)
try:
resolved_config = resolve_mcp_server_env(server_name, server_config)
except (RuntimeError, TypeError) as exc:
# Re-raise as MCPConfigError (a ValueError) so callers' existing
# config-error handling catches it, and `format_login_failure`
# preserves the actionable, field-scoped message instead of
# collapsing it to a bare "RuntimeError"/"TypeError".
raise MCPConfigError(str(exc)) from exc
from deepagents_code.mcp_providers import resolve_provider
storage = FileTokenStorage(server_name, server_url=resolved_config["url"])
policy = resolve_provider(resolved_config["url"])
result = await policy.run_login(
server_name=server_name,
server_url=resolved_config["url"],
storage=storage,
ui=ui,
)
success_message = f"Logged in to MCP server '{server_name}'."
if is_env_truthy(DEBUG):
success_message += f" Tokens saved to {storage.path}."
if result.completed:
await ui.show_success(success_message)View on GitHub (pinned to a1af029e6e)
Solutions
- Fix the underlying config error named in the message: export the missing env var, correct the `${...}` syntax to `${VAR}` or `${VAR:-default}`, or fix the field's type.
- Catch `MCPConfigError` (it is a `ValueError`) around `login` and surface the message via `format_login_failure`, which already renders the field-scoped detail.
- Add a `${VAR:-default}` fallback in the config if the variable is optional.
Example fix
// before
await login("myserver", {"url": "${MY_API_URL}"}, ui) # MY_API_URL unset
// after
$ export MY_API_URL=https://api.example.com
# or in config:
{"url": "${MY_API_URL:-https://api.example.com}"} Defensive patterns
Strategy: try-catch
Validate before calling
import os, re
REF = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^{}]*))?\}")
def validate_config(cfg: dict) -> list[str]:
errs = []
for f in ("command", "url"):
if f in cfg and not isinstance(cfg[f], str):
errs.append(f"{f} must be a string")
if not isinstance(cfg.get("args", []), list):
errs.append("args must be a list")
for f in ("env", "headers"):
for k, v in cfg.get(f, {}).items():
if not isinstance(v, str):
errs.append(f"{f}.{k} must be a string")
return errs Type guard
def is_str_or_str_list(v: object) -> TypeGuard[str | list[str]]:
return isinstance(v, str) or (isinstance(v, list) and all(isinstance(x, str) for x in v)) Try / catch
try:
await login(server_name, server_config, ui)
except (MCPConfigError, ValueError) as exc: # MCPConfigError subclasses ValueError
ui.show_error(format_login_failure(server_name, exc))
except RuntimeError as exc: # device-flow/handshake failures
... Prevention
- Run `resolve_mcp_server_env` on your config in a preflight check before triggering OAuth
- Use `${VAR:-default}` for optional variables
- Keep the env vars referenced by mcpServers entries in your shell profile so they are set in every session
When it happens
Trigger: Calling `login(server_name, server_config, ui)` for an http/sse server whose config contains a `${VAR}` reference to an unset env var, a malformed `${...}` reference, or a supported field (`command`, `url`, `args`, `env`, `headers`) with the wrong type.
Common situations: Running `/mcp login` (or `dcode mcp login`) against a server entry whose `url` or `headers` interpolates an env var that is not exported in the current shell, or whose config was hand-edited and a field type drifted (e.g. `args` as a string).
Related errors
- {field} references unset env var {name}. Set {name} in the e
- Server '{server_name}' has unsupported auth value {auth!r}.
- Server '{server_name}' uses stdio transport; 'auth: oauth' i
- Server '{server_name}' cannot combine 'auth: oauth' with an
- MCPReauthRequiredError({server_name})
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/70ad37ab5d0f7b52.
Report an issue: GitHub.