langchain-ai/deepagents · error · MCPReauthRequiredError

MCPReauthRequiredError({server_name})

Error message

MCPReauthRequiredError({server_name})

What it means

In non-interactive (server) mode, the OAuth redirect handler must not block on input(); instead it raises MCPReauthRequiredError carrying the server name. This signals callers (e.g. the MCP tooling layer) that the user must run an interactive login elsewhere. Raised from the generated `redirect` handler returned by the non-interactive handler factory.

Source

Thrown at libs/code/deepagents_code/mcp_auth.py:1137

        self.server_name = server_name
        super().__init__(
            f"MCP server {server_name!r} needs re-authentication. "
            f"Run `/mcp login {server_name}` in the TUI, or "
            f"`dcode mcp login {server_name}` from the shell.",
        )


def _make_reauth_required_handlers(
    server_name: str,
) -> tuple[RedirectHandler, CallbackHandler]:
    """Return OAuth handlers that refuse to prompt and raise instead.

    Used in non-interactive server mode so that a missing or expired token
    surfaces as `MCPReauthRequiredError` rather than hanging on `input()`.
    """

    async def redirect(_auth_url: str) -> None:  # noqa: RUF029
        raise MCPReauthRequiredError(server_name)

    async def callback() -> tuple[str, str | None]:  # noqa: RUF029
        raise MCPReauthRequiredError(server_name)

    return redirect, callback


def _make_paste_back_handlers(
    *,
    extra_auth_params: dict[str, str] | None = None,
    ui: OAuthInteraction | None = None,
) -> tuple[RedirectHandler, CallbackHandler]:
    """Create paste-back redirect and callback handlers for OAuth.

    Args:
        extra_auth_params: Extra query params to append to the auth URL.
        ui: Interaction surface for the auth URL display and the
            pasted-back callback URL prompt.

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Run `/mcp login <server>` in the interactive TUI (or `dcode mcp login <server>` in a terminal) once, then retry the server session.
  2. Ensure a valid, non-expired token exists in the token store before starting non-interactive mode.
  3. Handle MCPReauthRequiredError in the server harness and surface it to the user instead of retrying the request.

Example fix

// before
result = await mcp_client.call_tool(...)  # raises MCPReauthRequiredError
// after
try:
    result = await mcp_client.call_tool(...)
except MCPReauthRequiredError as e:
    print(f"Run 'dcode mcp login {e.server_name}' interactively first.")
Defensive patterns

Strategy: try-catch

Validate before calling

# before starting non-interactive mode, ensure tokens exist and are fresh
store = McpTokenStore(server_name, url)
if not store.path.exists():
    raise SystemExit(f"Run 'dcode mcp login {server_name}' before starting server mode.")

Try / catch

from deepagents_code.mcp_auth import MCPReauthRequiredError
try:
    result = await run_mcp_session(server_name)
except MCPReauthRequiredError as e:
    log.warning("MCP server %s requires interactive login", e.server_name)
    return ExitCode.needs_auth

Prevention

When it happens

Trigger: An MCP OAuth flow starts in non-interactive/server mode and the provider redirects the browser to the callback URL with no user available to approve the device/paste-back flow, so `redirect` fires and raises.

Common situations: Running dcode as a headless server/agent process where no TTY or browser session exists, an expired token triggering a fresh OAuth redirect during an automated session, or CI runs that need MCP auth but cannot prompt.

Related errors


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