Skip to content

fix(codex-runtime): advertise strict hermes-tools MCP schemas - #26432

Open
lidge-jun wants to merge 1 commit into
NousResearch:mainfrom
lidge-jun:codex/26010-hermes-tools-strict-mcp-schemas
Open

fix(codex-runtime): advertise strict hermes-tools MCP schemas#26432
lidge-jun wants to merge 1 commit into
NousResearch:mainfrom
lidge-jun:codex/26010-hermes-tools-strict-mcp-schemas

Conversation

@lidge-jun

Copy link
Copy Markdown
Contributor

Summary

  • Preserve Hermes' authoritative tool parameter schema when exposing tools through the codex-runtime hermes-tools MCP callback.
  • Normalize advertised MCP input schemas for strict clients by recursively adding additionalProperties: false to object schemas.
  • Add focused unit coverage for the schema normalizer and FastMCP registration path.

Refs #26010 (T15).

Verification

  • python3 -m py_compile agent/transports/hermes_tools_mcp_server.py tests/agent/transports/test_hermes_tools_mcp_server.py
  • ../hermes-pr-8733-wecom-media-path-boundary/.venv/bin/python -m py_compile agent/transports/hermes_tools_mcp_server.py tests/agent/transports/test_hermes_tools_mcp_server.py
  • ../hermes-pr-8733-wecom-media-path-boundary/.venv/bin/python -m pytest -o addopts='' tests/agent/transports/test_hermes_tools_mcp_server.py -q — 11 passed
  • ../hermes-pr-8733-wecom-media-path-boundary/.venv/bin/python -m ruff check agent/transports/hermes_tools_mcp_server.py tests/agent/transports/test_hermes_tools_mcp_server.py
  • git diff --check

Real behavior proof

Behavior addressed: hermes-tools MCP callback tools now advertise Hermes' original JSON parameter schema with strict object metadata instead of FastMCP's generic **kwargs-derived schema.

Real environment tested: Local macOS checkout using the existing sibling Hermes .venv because this new worktree did not have its own virtualenv. No live Codex turn was required for the schema advertisement proof.

Exact steps or command run after this patch:

../hermes-pr-8733-wecom-media-path-boundary/.venv/bin/python - <<'PY'
import asyncio
from agent.transports.hermes_tools_mcp_server import _build_server

async def main():
    server = _build_server()
    tools = await server.list_tools()
    print('tool_count', len(tools))
    names = [tool.name for tool in tools]
    print('tool_names', ','.join(names))
    tool = tools[0]
    schema = tool.inputSchema
    print('sample_tool', tool.name)
    print('sample_root_additionalProperties', schema.get('additionalProperties'))
    print('sample_has_properties', isinstance(schema.get('properties'), dict))

asyncio.run(main())
PY

Evidence after fix: The server registered 13 available local tools and browser_navigate advertised an object input schema with additionalProperties set to False and a real properties object.

Observed result after fix: A local MCP list-tools path sees strict schema metadata on advertised Hermes callback tools. The optional local environment was missing websockets, so some browser-dialog dependent tools were skipped by existing discovery behavior, but the server still registered available tools and exposed strict schemas for them.

What was not tested: A full live Codex app-server MCP call was not run, and the full repository test suite was not run.

@daimon-nous daimon-nous Bot added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint labels May 15, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for targeting a real Codex MCP interoperability problem. The advertised-schema change is not sufficient on its own because it leaves the execution contract split.

Problems

  • agent/transports/hermes_tools_mcp_server.py:180-186 builds FastMCP's tool from _dispatch(**kwargs) and then replaces only .parameters. FastMCP 1.26.0 validates calls through the separate fn_metadata generated from that callable, so direct arguments allowed by the advertised Hermes schema can fail before handle_function_call. The isolated live smoke recorded in #29821 reproduced this on this PR head as kwargs Field required.
  • tests/agent/transports/test_hermes_tools_mcp_server.py:143-198 checks only a fake manager's advertised schema; it never invokes FastMCP's actual validation/dispatch path.

Suggested changes

  • Align the execution-time FastMCP argument model with the authoritative Hermes schema, or install a raw validated-arguments adapter rather than changing .parameters alone.
  • Add an actual FastMCP call-path regression test proving direct arguments reach handle_function_call.

Automated hermes-sweeper review.

description=description,
)
if hasattr(tool, "parameters"):
tool.parameters = input_schema

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This only changes tools/list: FastMCP still validates calls through fn_metadata, which was generated from the **kwargs handler at registration. A call using the newly advertised direct fields can therefore fail with kwargs Field required before Hermes dispatches it. Update the execution-time argument model/adapter too, and cover a real call_tool invocation.

@teknium1 teknium1 added 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 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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.

2 participants