fix(oneshot): join MCP discovery before the one-shot tool snapshot (bounded, gated, warns) - #61944
fix(oneshot): join MCP discovery before the one-shot tool snapshot (bounded, gated, warns)#61944100yenadmin wants to merge 1 commit into
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating the one-shot startup race; current main confirms the missing join before the agent's tool snapshot (hermes_cli/main.py:12442-12449, hermes_cli/oneshot.py:206-235, agent/agent_init.py:1159-1163).
Problems
hermes_cli/oneshot.py:102pins the join to 30 seconds, but the shared MCP startup policy is configurable and defaults to 1.5 seconds (hermes_cli/mcp_startup.py:53-71,hermes_cli/config.py:1372). TUI also calls the shared wait without overriding it (tui_gateway/server.py:4481-4489).- The wait is gated by configured MCP names rather than the effective one-shot toolset (
hermes_cli/oneshot.py:94-96,259). Explicit non-MCP--toolsetsand configno_mcpcan therefore wait for tools that will not be exposed (hermes_cli/tools_config.py:1875-1893).
Suggested changes
- Reuse the configured shared timeout and gate the wait on the resolved effective MCP selection.
- Add coverage for explicit non-MCP toolsets,
no_mcp, and a temp-HERMES_HOMEone-shot snapshot regression.
Automated hermes-sweeper review.
852779b to
535bed1
Compare
|
Both review objections are fixed and pushed (rebased onto current
Tests: the reviewer-requested cases are all in Also re-verified none of #38456 / #43544 / #60017 landed an equivalent join on current main — the race is still live there. Consolidation offer stands. |
535bed1 to
5ce9c7a
Compare
|
Refreshed onto current main dd241cf at head 5ce9c7a448b62eddf730a727a7ee2da10622a38d. Both existing review findings remain fixed: the one-shot wait uses the shared configured MCP discovery timeout, and it is gated by the invocation effective MCP selection (including explicit non-MCP toolsets and no_mcp). The stale late-binding-refresh docstring claim was also corrected because one-shot has no interactive refresh. Proof: scripts/run_tests.sh tests/hermes_cli/test_oneshot_mcp_wait.py tests/hermes_cli/test_mcp_startup.py tests/hermes_cli/test_mcp_tools_config.py -q (11 passed); git diff --check passes. The two inline threads are resolved/outdated on this head. |
Join background MCP discovery before the one-shot tool snapshot only when the invocation's effective toolset can use an enabled MCP server. Resolve the shared mcp_discovery_timeout from config, report that bound in warnings, and cover explicit, no_mcp, timeout, and snapshot-order regressions.
5ce9c7a to
770dddc
Compare
|
Rebased the reviewed one-commit patch without conflicts from old base dd241cf / old head 5ce9c7a448b62eddf730a727a7ee2da10622a38d onto exact fetched base c581ad4. New head: 770dddc. Proof on the new head:
Exact-head CI at posting: GitHub reports no check runs yet and mergeStateStatus BLOCKED. The PR base branch has since advanced to 9650f55, but this requested rebase intentionally used the already-fetched exact c581ad4 and did not fetch again. |
|
Current-main follow-up: after the exact rebase base Remaining gate: exact-head CI is |
|
Closing — superseded by 3572d4b ( |
The bug
hermes -zstarts MCP discovery on a background thread (_prepare_agent_startup→start_background_mcp_discovery) but never joins it — the one-shot tool snapshot is built immediately, so configuredmcp_serverstools are silently absent from the turn. The model then answers without them; with capable models this produces convincing fake tool-call output (we reproduced this — the tell is zero tool-role messages in the session).Every other entrypoint already joins: the interactive CLI (
cli.pywait_for_mcp_discovery()), the agent-setup mixin, and the TUI (bounded 30s join). One-shot is the only gap — and it's the mode where the user can't notice mid-run.The fix
In
run_oneshot, before the tool snapshot and before stderr is redirected: if any enabledmcp_serversare configured,wait_for_mcp_discovery(timeout=30.0)(the TUI's bound — one-shot has no late-binding refresh, so it's this turn or nothing). On timeout, one stderr warning names the servers that may still be pending, and the run proceeds. Zero cost when no MCP servers are configured — the wait is gated on the same config read the--toolsetsresolver uses (now factored into a shared_read_mcp_server_names()helper instead of two inline copies).Relationship to the open PRs in this area
#38456, #43544, and #60017 attack overlapping symptoms; posting this because the approaches differ on points we think matter: this one is bounded (30s, TUI-parity — not an unbounded wait or a raised global timeout), gated (no cost on the no-MCP path), placed before the stderr redirect so the pending-server warning actually reaches the terminal (warnings emitted after
run_oneshot'sredirect_stderr(devnull)are swallowed — worth checking in any variant), and covered by targeted tests (wait-called / not-called / timeout-warns-and-proceeds). Happy to consolidate with any of the other authors — one of these four should land, this is a sharp-edged silent failure.Tests
tests/hermes_cli/test_oneshot_mcp_wait.py(3) +test_oneshot_usage_file+test_mcp_startup(14 total) +test_tui_resume_flow(48, covers the resolver refactor) — green viascripts/run_tests.sh, re-verified after rebasing onto today's main.