hermes - 💡(How to fix) Fix [Bug]: MCP OAuth login times out at 40s; per-server connect_timeout silently ignored

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

hermes mcp login <name> (and hermes mcp add --auth oauth) fail with MCP call timed out after 40.0s (configured timeout: 40.0s) for any OAuth-based remote MCP server where the user needs more than ~30 seconds to complete the browser authorization flow. The per-server connect_timeout field in ~/.hermes/config.yaml is silently ignored — setting it to 300 produces no observable change in behaviour.

Root Cause

In hermes_cli/mcp_config.py, cmd_mcp_login calls _probe_single_server(name, server_config) without overriding the default connect_timeout:

def _probe_single_server(
    name: str, config: dict, connect_timeout: float = 30   # ← hard-coded default
) -> List[Tuple[str, str]]:
    ...
    async def _probe():
        server = await asyncio.wait_for(
            _connect_server(name, config), timeout=connect_timeout   # ← 30s
        )
    ...
    _run_on_mcp_loop(_probe(), timeout=connect_timeout + 10)   # ← 40s total

The function never reads config.get("connect_timeout", ...), so the per-server YAML field has no effect on the login path.

Fix Action

Fix / Workaround

Workable workaround (for other affected users)

Code Example

hermes mcp add supabase --url https://mcp.supabase.com/mcp --auth oauth
# - or -
hermes mcp login supabase

---

mcp_servers:
  supabase:
    url: https://mcp.supabase.com/mcp
    auth: oauth
    connect_timeout: 300   # ← silently ignored
    enabled: false

---

Starting OAuth flow for 'supabase'...
Authentication failed: MCP call timed out after 40.0s (configured timeout: 40.0s)

---

def _probe_single_server(
    name: str, config: dict, connect_timeout: float = 30   # ← hard-coded default
) -> List[Tuple[str, str]]:
    ...
    async def _probe():
        server = await asyncio.wait_for(
            _connect_server(name, config), timeout=connect_timeout   # ← 30s
        )
    ...
    _run_on_mcp_loop(_probe(), timeout=connect_timeout + 10)   # ← 40s total

---

def _probe_single_server(
    name: str, config: dict, connect_timeout: float | None = None
) -> List[Tuple[str, str]]:
    if connect_timeout is None:
        connect_timeout = float(config.get("connect_timeout", 300))
    ...

---

# 1. Run mcp-remote directly; complete OAuth at your own pace in the browser.
npx -y mcp-remote https://mcp.supabase.com/mcp
# (process exits when stdin closes; tokens cached.)

# 2. Wrap the same command for Hermes.
cat > ~/.local/bin/supabase-mcp-launcher <<'EOF'
#!/bin/sh
exec npx -y mcp-remote https://mcp.supabase.com/mcp
EOF
chmod +x ~/.local/bin/supabase-mcp-launcher

# 3. Register with Hermes — probe spawns wrapper, mcp-remote uses cached
#    tokens, connects in ~5s, well under the 40s ceiling.
hermes mcp add supabase --command ~/.local/bin/supabase-mcp-launcher
RAW_BUFFERClick to expand / collapse

Summary

hermes mcp login <name> (and hermes mcp add --auth oauth) fail with MCP call timed out after 40.0s (configured timeout: 40.0s) for any OAuth-based remote MCP server where the user needs more than ~30 seconds to complete the browser authorization flow. The per-server connect_timeout field in ~/.hermes/config.yaml is silently ignored — setting it to 300 produces no observable change in behaviour.

Reproducer

Tested against https://mcp.supabase.com/mcp (Supabase's official OAuth-based MCP endpoint):

hermes mcp add supabase --url https://mcp.supabase.com/mcp --auth oauth
# - or -
hermes mcp login supabase

In a fresh browser (not already signed into Supabase), the OAuth-flow URL Hermes prints requires the user to sign in to Supabase, click Authorize, and return to the loopback callback. This realistically takes longer than 40 seconds.

Even after adding connect_timeout: 300 to the server entry in ~/.hermes/config.yaml:

mcp_servers:
  supabase:
    url: https://mcp.supabase.com/mcp
    auth: oauth
    connect_timeout: 300   # ← silently ignored
    enabled: false

…the runtime still aborts at 40s with the same message.

Symptom (verbatim)

Starting OAuth flow for 'supabase'...
✗ Authentication failed: MCP call timed out after 40.0s (configured timeout: 40.0s)

(Server is then saved in disabled state.)

Root cause

In hermes_cli/mcp_config.py, cmd_mcp_login calls _probe_single_server(name, server_config) without overriding the default connect_timeout:

def _probe_single_server(
    name: str, config: dict, connect_timeout: float = 30   # ← hard-coded default
) -> List[Tuple[str, str]]:
    ...
    async def _probe():
        server = await asyncio.wait_for(
            _connect_server(name, config), timeout=connect_timeout   # ← 30s
        )
    ...
    _run_on_mcp_loop(_probe(), timeout=connect_timeout + 10)   # ← 40s total

The function never reads config.get("connect_timeout", ...), so the per-server YAML field has no effect on the login path.

Suggested fix

In _probe_single_server (or in cmd_mcp_login), read connect_timeout from the server config and fall back to a larger default suited for browser-mediated OAuth flows:

def _probe_single_server(
    name: str, config: dict, connect_timeout: float | None = None
) -> List[Tuple[str, str]]:
    if connect_timeout is None:
        connect_timeout = float(config.get("connect_timeout", 300))
    ...

A larger default (e.g., 300s) better matches the realistic time for a browser-mediated OAuth handshake; honoring config.get("connect_timeout") lets advanced users tune further.

Workable workaround (for other affected users)

Skip Hermes's native --auth oauth path entirely. Pre-authenticate via mcp-remote standalone (writes tokens to ~/.mcp-auth/<version>/), then register via stdio wrapper:

# 1. Run mcp-remote directly; complete OAuth at your own pace in the browser.
npx -y mcp-remote https://mcp.supabase.com/mcp
# (process exits when stdin closes; tokens cached.)

# 2. Wrap the same command for Hermes.
cat > ~/.local/bin/supabase-mcp-launcher <<'EOF'
#!/bin/sh
exec npx -y mcp-remote https://mcp.supabase.com/mcp
EOF
chmod +x ~/.local/bin/supabase-mcp-launcher

# 3. Register with Hermes — probe spawns wrapper, mcp-remote uses cached
#    tokens, connects in ~5s, well under the 40s ceiling.
hermes mcp add supabase --command ~/.local/bin/supabase-mcp-launcher

This sidesteps the broken login path but requires a wrapper script per OAuth-based server, defeating the convenience of hermes mcp add --auth oauth.

Environment

  • Hermes Agent v0.13.0 (2026.5.7)
  • Python: 3.11.15
  • OpenAI SDK: 2.36.0
  • macOS Darwin 25.4.0 (Apple Silicon)
  • Tested against https://mcp.supabase.com/mcp (Supabase's OAuth-based MCP server)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING