Skip to content

fix(mcp): coerce numeric tool args defensively in mcp_serve#21329

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-b625eb32
May 7, 2026
Merged

fix(mcp): coerce numeric tool args defensively in mcp_serve#21329
teknium1 merged 2 commits into
mainfrom
hermes/hermes-b625eb32

Conversation

@teknium1

@teknium1 teknium1 commented May 7, 2026

Copy link
Copy Markdown
Contributor

Salvage of #21055 by @qWaitCrypto onto current main. Cherry-picked clean.

Summary

Hermes' MCP server (mcp_serve.py) exposes several tools that annotate parameters as int but then feed them directly into slicing (conversations[:limit]), min(timeout_ms, 300000), and bridge calls. External MCP clients are free to send "50", null, floats, or garbage — which crash at runtime with TypeError: slice indices must be integers or None.

Add _coerce_int(value, default, minimum, maximum) that converts to int with fallback to default, clamps to range, and apply it to the four external-facing tool parameters.

Bug repro (verified live on main)

input behavior
conversations[:"50"] TypeError
conversations[:"bad"] TypeError
conversations[:50.5] TypeError
min(None, 300000) TypeError
conversations[:None] OK (Python accepts None as slice index)

Changes

  • mcp_serve.py: +19 lines for _coerce_int helper, +8 lines applying it at 4 tool boundaries (conversations_list.limit, messages_read.limit, events_poll.after_cursor/limit, events_wait.after_cursor/timeout_ms).
  • tests/test_mcp_serve.py: +101 lines of coercion regression coverage (5 tests).
  • scripts/release.py: AUTHOR_MAP entry for @qWaitCrypto.

Validation

Result
scripts/run_tests.sh tests/test_mcp_serve.py 84/84 passed (+5 new)
Live bug repro on main confirmed TypeError on "50", "bad", 50.5
E2E _coerce_int with 8 edge cases (strings, None, floats, out-of-range, negative) all correctly coerced or clamped

Closes #21055. @qWaitCrypto's authorship preserved via rebase-merge.

@teknium1 teknium1 merged commit 1baab87 into main May 7, 2026
10 of 11 checks passed
@teknium1 teknium1 deleted the hermes/hermes-b625eb32 branch May 7, 2026 14:17
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-b625eb32 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: 7611 on HEAD, 7611 on base (➖ 0)

🆕 New issues (3):

Rule Count
invalid-argument-type 3
First entries
run_agent.py:12365: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
run_agent.py:6504: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
run_agent.py:12368: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown, Unknown] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 3 union elements`

✅ Fixed issues (3):

Rule Count
invalid-argument-type 3
First entries
run_agent.py:6504: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown | str, Unknown | str | dict[str, str]] | Any | ... omitted 3 union elements`
run_agent.py:12365: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown | str, Unknown | str | dict[str, str]] | Any | ... omitted 3 union elements`
run_agent.py:12368: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown | str, Unknown | str | dict[str, str]] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 3 union elements`

Unchanged: 4001 pre-existing issues carried over.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have 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.

3 participants