Skip to content

v0.1.6: non-blocking login_browser for chat clients#4

Merged
hculap merged 1 commit into
mainfrom
feat/v0.1.6-login-browser-nonblocking
May 19, 2026
Merged

v0.1.6: non-blocking login_browser for chat clients#4
hculap merged 1 commit into
mainfrom
feat/v0.1.6-login-browser-nonblocking

Conversation

@hculap
Copy link
Copy Markdown
Owner

@hculap hculap commented May 19, 2026

Why

You hit the exact problem: in Claude Desktop, `login_browser` always times out at ~60s because the client doesn't support `resetTimeoutOnProgress`. The server WAS doing the right thing (binding port, opening browser), but the tool call got killed before the user could submit credentials — so even on successful login, the token never came back through that call.

Fix

`login_browser` defaults to `wait=False` now:

  • `wait=False` (DEFAULT, recommended for Claude Desktop / Cursor chat / Continue / Cline / Zed): returns the URL in <1s. Server keeps running in a daemon thread for `timeout` seconds. When user submits, token is persisted to `config.json` + keychain in the background. Agent then polls `whoami` to detect `token_present: true`.

  • `wait=True` (opt-in for Claude Code / Codex CLI / any agent supporting long-running tools): blocks until complete, returns full `{email, user_id, ...}` inline. Same behavior as before.

Refactor in web_auth.py

Decomposed the previously monolithic `web_login_flow` into:

  • `start_login_server(...)` → bind + open browser + return `LoginSession` handle (non-blocking)
  • `wait_for_login(session, timeout=...)` → block until result, raise `LoginFlowError`
  • `cancel_login(session)` → clean abandonment

`web_login_flow` now composes these — terminal CLI (`emodul auth login --browser`) unchanged.

Verified end-to-end

  • `wait=False` returns in 0.21s via real MCP stdio client (vs prior 60s timeout)
  • Background thread completes login and persists token correctly on user submit
  • `wait=True` path preserved (smoke tested via existing CLI flow)
  • 16 tools still register
  • Updated `instructions` field tells agents NOT to pass `wait=True` in chat contexts
  • Ruff clean

Release

After merge: tag v0.1.6 → OIDC publish → `pipx upgrade emodul` → restart Claude Desktop → next login flow takes 1s, you open URL, type password, agent polls whoami.

Claude Desktop / Cursor chat / Continue / Cline don't support
`resetTimeoutOnProgress`, so any tool call exceeding ~60s gets killed
client-side even if the server is still working. The previous
login_browser blocked until the user submitted the form (5min ceiling) —
in practice always timing out before the user finished typing.

New behavior:

- login_browser(wait=False) — DEFAULT for chat clients. Binds the local
  127.0.0.1 server, opens the browser, returns the URL in <1s. The
  server keeps running in a daemon thread for `timeout` seconds. On
  user submit, the token is saved to config.json and (best-effort) the
  password is stored in OS keychain — exactly like the wait=True path.
  Agent shows URL to user, polls whoami afterwards to detect completion.

- login_browser(wait=True) — opt-in for CLI/IDE agents that DO support
  long-running tools (Claude Code, Codex CLI). Same blocking behavior
  as before; returns full result inline with email/user_id.

Refactor in web_auth.py to support this:
- new `LoginSession` handle class
- `start_login_server(...)` — non-blocking, returns LoginSession
- `wait_for_login(session, timeout=...)` — blocks, raises LoginFlowError
- `cancel_login(session)` — abandons cleanly
- `web_login_flow(...)` now composes start + wait (existing API
  preserved for terminal CLI)

Updated server `instructions` to tell agents NOT to pass wait=True in
chat contexts and to poll whoami after the non-blocking call.

Tested end-to-end via real MCP stdio client: wait=False returns in
~0.2s vs previous 60s+ timeout. Background thread persists token
correctly on user submit.
@hculap hculap merged commit cf1abaf into main May 19, 2026
9 checks passed
@hculap hculap deleted the feat/v0.1.6-login-browser-nonblocking branch May 19, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant