Skip to content

fix(cron): wrap MCP discovery with suppress_interactive_oauth for HTTP/OAuth servers - #65993

Open
rajv2er wants to merge 1 commit into
NousResearch:mainfrom
rajv2er:fix/cron-http-mcp-tools-65889
Open

fix(cron): wrap MCP discovery with suppress_interactive_oauth for HTTP/OAuth servers#65993
rajv2er wants to merge 1 commit into
NousResearch:mainfrom
rajv2er:fix/cron-http-mcp-tools-65889

Conversation

@rajv2er

@rajv2er rajv2er commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Fixes #65889 — HTTP/OAuth MCP servers (slack, google-workspace) not loading in cron sessions.

Root Cause

The cron scheduler calls discover_mcp_tools() without wrapping it in suppress_interactive_oauth(), unlike every other non-interactive entry point (desktop/gateway startup, CLI hermes mcp test).

When the gateway process is launched from a terminal:

  1. sys.stdin.isatty() returns True process-wide (including cron worker threads)
  2. tools/mcp_oauth.py:_is_interactive() returns True in cron context
  3. For HTTP/OAuth MCP servers with expired/unusable cached tokens, the SDK enters the authorization-code (browser-redirect) flow
  4. tools/mcp_oauth.py:_redirect_handler calls _raise_if_non_interactive(), but since _is_interactive() returns True, it does not raise
  5. The callback listener binds a localhost port and waits for a browser redirect that never arrives (no interactive user)
  6. Hangs until connect_timeout (default 60s) expires -> server silently fails to register
  7. No mcp-<name> toolset alias is created -> validate_toolset("slack") returns False -> get_tool_definitions(..., quiet_mode=True) silently drops the tools

Stdio MCP servers (jira, tompero) are unaffected — they don't use OAuth.

The Fix

Wrap the discover_mcp_tools() call in cron/scheduler.py with suppress_interactive_oauth(), mirroring the pattern already used in:

  • hermes_cli/mcp_startup.py:_discover_mcp_tools_without_interactive_oauth() (desktop/gateway startup)
  • hermes_cli/web_server.py (dashboard OAuth login uses force_interactive_oauth)

The suppress_interactive_oauth() context manager sets a ContextVar (_oauth_interactive_enabled=False) that propagates across asyncio.run_coroutine_threadsafe to the MCP event loop thread where the OAuth flow actually runs.

Verification

  • All 212 MCP tool tests pass (tests/tools/test_mcp_tool.py)
  • All cron scheduler MCP init tests pass (tests/cron/test_scheduler_mcp_init.py)
  • No existing behavior changed for stdio MCP servers

@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management tool/mcp MCP client and OAuth area/auth Authentication, OAuth, credential pools P2 Medium — degraded but workaround exists labels Jul 17, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #65889 is the report addressed by this PR. #53294 and #58000 cover related OAuth suppression/fail-fast behavior on other discovery paths; this patch targets the distinct cron scheduler call site.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Comment

Summary

Fix: throws proper OAuth fetch error instead of generic exception when token refresh fails.

Improves error diagnostics for OAuth flow failures. No security concerns.


Reviewed by Hermes Agent

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Comment

MCP discovery OAuth fix (20 lines). Wraps MCP discovery with suppress_interactive_oauth.

Checked diff — no security concerns, no hardcoded secrets.

Looks good. No blocking issues.


Reviewed by Hermes Agent

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused cron-specific fix. The current cron path still invokes discover_mcp_tools() directly at cron/scheduler.py:3307-3309, while background startup already suppresses interactive OAuth before discovery at hermes_cli/mcp_startup.py:74-84. The proposed wrapper matches that established behavior, and tools/mcp_oauth.py:294-306 confirms the ContextVar is designed to propagate to the MCP event-loop coroutine.

Problems

  • The change has no cron-path regression test. tests/cron/test_scheduler_mcp_init.py:26-53 currently verifies only that no_agent jobs skip discovery; it would not catch a future removal of the OAuth-suppression wrapper.

Suggested changes

  • Add a scheduler test that makes stdin appear interactive and asserts the discover_mcp_tools() side effect executes with OAuth interactivity suppressed.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 18, 2026
…P/OAuth servers

Issue NousResearch#65889: HTTP/OAuth MCP servers (slack, google-workspace) fail to
register in cron sessions when the gateway process was launched from a
terminal. The root cause: cron calls discover_mcp_tools() without the
suppress_interactive_oauth() wrapper that all other non-interactive
entry points use (desktop/gateway startup, CLI hermes mcp test).

Without the wrapper, _is_interactive() returns True in the cron thread
pool (because the gateway process has a TTY). When an HTTP/OAuth MCP
server's cached token is expired/unusable, the SDK enters the
authorization-code (browser-redirect) flow instead of failing fast. The
callback listener binds a port and waits for a browser redirect that
never comes, hanging until connect_timeout expires. The server silently
fails to register — no toolset alias is created, so validate_toolset()
returns False and get_tool_definitions() drops the tools.

Stdio MCP servers (jira, tompero) are unaffected — they don't use OAuth.

The fix mirrors the pattern in hermes_cli/mcp_startup.py:
_discover_mcp_tools_without_interactive_oauth().
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary

One PR addresses #65889. #65993 wraps cron MCP discovery with non-interactive OAuth suppression, targeting the unattended browser flow that prevents HTTP/OAuth tools from registering while command-based MCP tools remain available.

Related pull requests

  • fix(cron): wrap MCP discovery with suppress_interactive_oauth for HTTP/OAuth servers #65993 best fix — (+20/-2) — n/a: The diff wraps cron’s discover_mcp_tools() call with suppress_interactive_oauth(), matching the established background-startup pattern and directly addressing the reported HTTP/OAuth discovery failure. The automated keep_open review finds the change highly salvageable but requests a cron-path regression test proving discovery executes with OAuth interactivity suppressed when stdin appears interactive.

Suggested consolidation

Keep #65993 open with a salvage path: retain the focused OAuth-suppression wrapper and add the requested scheduler regression test. It is the only PR in this complex, so there are no duplicate PRs to close.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I65889(["issue #65889 (open)"])
    P65993["PR #65993 (open)"]
    P65993 -->|best fix| I65889
    class I65889 open
    class P65993 open
    class P65993 best
    class P65993 target
    click I65889 "https://github.com/NousResearch/hermes-agent/issues/65889"
    click P65993 "https://github.com/NousResearch/hermes-agent/pull/65993"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 1 pull request and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 2 kB of PR diffs, 4 kB of issue/PR text, 1 kB of discussion (4 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@rajv2er
rajv2er requested a review from tonydwb August 20, 2026 09:06
@alt-glitch alt-glitch removed sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP MCP tools not loaded in cron sessions (command-based work, HTTP-based don't)

5 participants