Skip to content

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (#23997) - #50117

Merged
kshitijk4poor merged 2 commits into
mainfrom
salvage/f5-cron-mcp-per-job
Jun 22, 2026
Merged

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (#23997)#50117
kshitijk4poor merged 2 commits into
mainfrom
salvage/f5-cron-mcp-per-job

Conversation

@kshitijk4poor

@kshitijk4poor kshitijk4poor commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Problem

A cron job that set enabled_toolsets to native toolsets (e.g. ["web", "terminal"]) silently got zero MCP tools, while a job with no per-job list got every globally-enabled MCP server. _resolve_cron_enabled_toolsets returned the per-job list verbatim, bypassing the MCP-merge that the platform-fallback branch does via _get_platform_tools. discover_mcp_tools() registered the MCP tools into the registry, but get_tool_definitions(enabled_toolsets=...) kept only the named native toolsets — the agent rejected every mcp_* call as "Unknown tool". (R2 of #23997)

Fix

_merge_mcp_into_per_job_toolsets layers MCP membership onto a per-job allowlist with the same semantics as _get_platform_tools:

  • no_mcp sentinel → no MCP servers
  • one or more MCP server names already listed → treat as an allowlist (add nothing further)
  • otherwise → union in every globally-enabled MCP server

To avoid duplicating the "which MCP servers are enabled" computation (the original PR re-implemented it), this extracts a shared enabled_mcp_server_names(config) helper in hermes_cli.tools_config and has BOTH the gateway/CLI platform resolver and the cron per-job resolver call it — so every path agrees on MCP membership (extend, don't duplicate).

Scope — what was already fixed on main

The issue's headline (bare MCP server names rejected, registry never includes them in cron) was already fixed on main before the issue was filed (commits c10fea8d2 server-alias + 04918345e discover-MCP-before-cron-agent). This PR closes the remaining cron-specific gap (R2). Two smaller residuals are tracked separately, not in scope here:

Salvage / credit

Salvaged from #32788 by @sherman-yang (authorship preserved). Reworked to reuse the shared enabled_mcp_server_names helper instead of re-implementing the MCP membership set in cron/scheduler.py (the DRY concern flagged in review).

Tests

tests/cron/test_scheduler.py — per-job native allowlist unions in enabled MCP; no_mcp opts out; explicit MCP name acts as allowlist. Full tests/cron/: 517 passed; tests/hermes_cli/test_tools_config.py: 97 passed (the gateway path still resolves MCP identically after the helper extraction).

Closes

Fixes #23997


Review-driven changes (/hermes-pr-review, 3 reviewers — verdict: Approve/ship-ready, no Critical)

  • Strengthened the fall-through test: test_resolver_empty_per_job_falls_through_to_platform now stubs _get_platform_tools and asserts the platform branch is actually taken with platform="cron" and its result returned — was previously a near-tautology (result is None or isinstance(result, list)).
  • Documented the enabled-flag semantics: the shared enabled_mcp_server_names docstring now notes a server is enabled unless explicitly falsey (false/0/no/off via _parse_enabled_flag); a missing/unrecognized flag is treated as enabled — matching prior gateway behavior.

Reviewers confirmed: the enabled_mcp_server_names extraction is behavior-identical for the gateway (verbatim move of the inline computation, same _parse_enabled_flag); the 3 merge branches are correct with proper allowlist exclusion of unnamed enabled servers; merge runs on the per-job branch only (no double-merge with the platform fallback); the lazy import poses no circular-import risk (cron already imports from hermes_cli widely); disabled-toolset subtraction reliably runs last so a disabled MCP server can't sneak back. Both files pass in isolation (cron 517, tools_config 97).

Note: tests assert the resolved toolset-name list (the contract of these pure resolver functions), not end-to-end tool registration — consistent with the existing resolver tests.

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: salvage/f5-cron-mcp-per-job vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11352 on HEAD, 11348 on base (🆕 +4)

🆕 New issues (3):

Rule Count
unresolved-attribute 2
invalid-argument-type 1
First entries
tests/cron/test_scheduler.py:76: [invalid-argument-type] invalid-argument-type: Argument to `set.__init__` is incorrect: Expected `Iterable[str]`, found `list[str] | None`
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
run_agent.py:2984: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`

✅ Fixed issues (1):

Rule Count
invalid-assignment 1
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`

Unchanged: 5964 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management comp/cli CLI entry point, hermes_cli/, setup wizard tool/mcp MCP client and OAuth P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jun 21, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #32788 — both fix #23997 with the same mechanism: a _merge_mcp_into_per_job_toolsets() helper layering globally-enabled MCP servers onto a per-job enabled_toolsets allowlist (no_mcp sentinel -> none; explicit MCP names -> allowlist; otherwise -> union all enabled). #32788 (open, 2026-05-26) is the earlier of the two. This PR additionally extracts a shared enabled_mcp_server_names() helper into hermes_cli/tools_config.py, but the core cron/scheduler.py fix is the same approach. Linking for reviewer dedup; not a knock on the work.

@kshitijk4poor
kshitijk4poor force-pushed the salvage/f5-cron-mcp-per-job branch from 0dd3da8 to 121301b Compare June 21, 2026 11:18
sherman-yang and others added 2 commits June 22, 2026 15:52
A cron job that sets `enabled_toolsets` to a list of *native* toolsets (e.g.
`["web", "terminal"]`) silently got ZERO MCP tools, while a job with no
per-job list got every globally-enabled MCP server. `_resolve_cron_enabled_
toolsets` returned the per-job list verbatim, bypassing the MCP-merge that the
platform-fallback branch performs via `_get_platform_tools`. So
`discover_mcp_tools()` registered the MCP tools into the registry, but
`get_tool_definitions(enabled_toolsets=...)` kept only the named native
toolsets — the agent then rejected every `mcp_*` call as "Unknown tool". (R2
of #23997.)

Fix: `_merge_mcp_into_per_job_toolsets` layers MCP membership onto a per-job
allowlist with the SAME semantics as `_get_platform_tools`:
  * `no_mcp` sentinel present -> no MCP servers (sentinel stripped)
  * one or more MCP server names already listed -> treat as an allowlist
  * otherwise -> union in every globally-enabled MCP server

To avoid duplicating the "which MCP servers are enabled" computation (it
already existed inline in `_get_platform_tools`), this extracts a shared
`enabled_mcp_server_names(config)` helper in `hermes_cli.tools_config` and has
BOTH the gateway/CLI platform resolver and the cron per-job resolver call it —
so every path agrees on MCP membership (extend, don't duplicate).

Note: the issue's *headline* — bare MCP server names rejected, registry never
includes them — was already fixed on main (commits c10fea8 + 0491834,
both before the issue was filed). This PR closes the remaining cron-specific
gap (R2). The `server:*` / `mcp:server` alias-notation rejection (R1) and the
quiet-mode silent-drop (R3) are tracked separately.

Salvaged from #32788 by sherman-yang (credited below). Reworked to reuse the
shared `enabled_mcp_server_names` helper instead of re-implementing the MCP
membership set in cron/scheduler.py.

Fixes #23997

Co-authored-by: sherman-yang <58446328+sherman-yang@users.noreply.github.com>
@kshitijk4poor
kshitijk4poor force-pushed the salvage/f5-cron-mcp-per-job branch from 121301b to 5bd3dae Compare June 22, 2026 10:24
@kshitijk4poor
kshitijk4poor merged commit 0e87c0a into main Jun 22, 2026
34 of 35 checks passed
@kshitijk4poor
kshitijk4poor deleted the salvage/f5-cron-mcp-per-job branch June 22, 2026 10:33
jasontangzs0 added a commit to GRAIL-innovationai/hermes-agent that referenced this pull request Jun 30, 2026
A cron job with a native-only enabled_toolsets (e.g.
["file","skills","terminal"]) silently stripped every MCP server's tools
from the scheduled run — the allowlist named no MCP servers, so scheduled
jobs ran with builtin tools only while interactive runs had the full MCP
set. (Upstream NousResearch/hermes-agent NousResearch#23997; fixed there by NousResearch#50117.)

_resolve_cron_enabled_toolsets now runs a per-job allowlist through
_merge_mcp_into_per_job_toolsets, which unions globally-enabled MCP server
names in (matching the _get_platform_tools default), honors a `no_mcp`
opt-out sentinel, and leaves a list that already names an MCP server as an
explicit allowlist. enabled_mcp_server_names() is extracted in
tools_config.py and shared so the platform-default and cron paths cannot
diverge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…on-mcp-per-job

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (NousResearch#23997)
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…on-mcp-per-job

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (NousResearch#23997)
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…on-mcp-per-job

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (NousResearch#23997)
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…on-mcp-per-job

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (NousResearch#23997)
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…on-mcp-per-job

fix(cron): layer enabled MCP servers onto per-job enabled_toolsets (NousResearch#23997)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists 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.

[Bug] enabled_toolsets silently rejects MCP server names — MCP tools absent in cron sessions

3 participants