langchain-ai/deepagents · info · MCPLoginCancelledError

MCP login was cancelled before the prompt could be shown.

Error message

MCP login was cancelled before the prompt could be shown.

What it means

_await_input shows the MCP login modal's input prompt. If the modal was already cancelled before the prompt could be presented, it raises MCPLoginCancelledError with this message rather than waiting on an input that will never arrive. A separate RuntimeError guards against two concurrent prompts.

Source

Thrown at libs/code/deepagents_code/tui/widgets/mcp_login.py:428

        self._history_widget.mount(
            Static(line, classes="ml-history-line", markup=False)
        )
        self._history_widget.scroll_end(animate=False)

    async def _await_input(self, prompt: str) -> str:
        """Show `prompt`, wait for `Enter`, and return the typed value.

        Returns:
            The raw input value the user submitted.

        Raises:
            MCPLoginCancelledError: When the modal is cancelled before or
                during submission.
            RuntimeError: When a concurrent prompt is already active.
        """
        if self._cancelled:
            msg = "MCP login was cancelled before the prompt could be shown."
            raise MCPLoginCancelledError(msg)
        if self._pending_input is not None:
            msg = (
                "MCP login modal cannot have two concurrent input prompts; "
                "the previous prompt was not resolved."
            )
            raise RuntimeError(msg)

        loop = asyncio.get_running_loop()
        future: asyncio.Future[str] = loop.create_future()
        self._pending_input = future
        if self._prompt_widget is not None:
            self._prompt_widget.display = True
            self._prompt_widget.update(prompt)
        if self._input_widget is not None:
            self._input_widget.value = ""
            self._input_widget.display = True
            self._input_widget.focus()
        try:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Check the modal's cancelled state before requesting the callback URL and abort the login flow early.
  2. Catch MCPLoginCancelledError around request_callback_url and treat it as a normal user cancellation (no error UI).
  3. Ensure a single login flow owns the modal so cancel and prompt paths don't race.

Example fix

// before
url = await modal.request_callback_url()  # raises if cancelled
// after
try:
    url = await modal.request_callback_url()
except MCPLoginCancelledError:
    return  # user cancelled login
Defensive patterns

Strategy: try-catch

Validate before calling

if modal.is_cancelled:
    return  # skip request_callback_url entirely
url = await modal.request_callback_url()

Try / catch

try:
    url = await modal.request_callback_url()
except MCPLoginCancelledError:
    return  # user cancelled; exit login flow quietly

Prevention

When it happens

Trigger: Calling request_callback_url (which awaits _await_input) after the user has already dismissed/cancelled the MCP login modal — self._cancelled is True at entry.

Common situations: User presses Esc/closes the modal while a login step is being prepared; an auth flow that retries a prompt after cancellation; a timeout path cancelling the modal then code continuing to request input.

Related errors


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