feat(gateway): propagate per-run mcp_meta to MCP tools/call - #64938
astraltrekkin wants to merge 2 commits into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for adding the run-scoped MCP metadata path. The capability remains needed: current main The PR captures the value before crossing into the dedicated MCP loop ( Automated hermes-sweeper review. |
syzby
left a comment
There was a problem hiding this comment.
I independently validated this design against a real multi-user gateway -> Hermes -> MCP deployment. The concrete requirement is to carry a per-user, short-lived signed assertion to the MCP server without exposing it to model messages or tool arguments, and without mutating headers on Hermes' shared long-lived MCP connection. Per-run MCP _meta is the right generic seam and avoids the cross-user race inherent in shared dynamic headers.
I also exercised the equivalent API binding and MCP forwarding paths on Windows 11 + WSL2 using the repository test wrapper: 248 targeted tests passed, including concurrent run isolation and unchanged calls when metadata is absent.
One operational security clarification would help in the docs: downstream MCP servers must treat client-supplied _meta as untrusted unless they validate a signed assertion (including expiry, audience, and scope). Hermes forwarding the object must not itself confer authority. This is consistent with the PR's “no signing or validation” contract, but spelling it out would reduce unsafe deployments.
Keep mcp_meta ContextVar bind/reset on /v1/runs and fold in main's profile_scope re-entry plus unregister_gateway_notify cleanup. Co-authored-by: Cursor <cursoragent@cursor.com>
SummaryOne PR addresses #64890. #64938 implements the missing run-scoped correlation path by accepting Related pull requests
Suggested consolidationKeep #64938 open with a salvage path: preserve its validated run-scoped Complex graphflowchart 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
I64890(["issue #64890 (open)"])
P64938["PR #64938 (open)"]
P64938 -->|best fix| I64890
class I64890 open
class P64938 open
class P64938 best
class P64938 target
click I64890 "https://github.com/NousResearch/hermes-agent/issues/64890"
click P64938 "https://github.com/NousResearch/hermes-agent/pull/64938"
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: 21 kB of PR diffs, 6 kB of issue/PR text, 2 kB of discussion (2 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
Adapt the per-run MCP metadata transport from NousResearch#64938 to the current Runs and MCP handler modules. Target exact configured servers, validate bounded JSON, preserve metadata across retries and native delegation, and advertise the API contract. Add HTTP-to-MCP SDK coverage and document the trust boundary. Bind the originating profile with the immutable run metadata. Refuse unknown, foreign, or replaced MCP destinations before lazy acquisition, queued dispatch, and recovery; do not retarget credentials when a child enters another profile. Use the canonical protocol-owned metadata predicate. The fail-closed guard is not a replacement for the profile-qualified MCP registry proposed in NousResearch#99594. Based on rainbowgits' contribution in astraltrekkin/hermes-agent; retained authorship and adapted implementation, tests, and documentation by Diadems Tech. (cherry picked from commit 36ed7f3) Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Diadems Tech <194491654+DiademsTech@users.noreply.github.com>
What does this PR do?
Adds optional opaque
mcp_metaonPOST /v1/runsand relays it as MCPtools/callparams._metafor that run's lifetime (includingdelegate_tasksubagents). Multi-tenant MCP servers can correlate tool calls with the triggering run without trusting model-supplied arguments or relying on a shared static bearer alone.Approach: run-scoped ContextVar → snapshot on the agent thread →
ClientSession.call_tool(..., meta=...); re-bind into delegation workers (pools don't inherit ContextVars). Absent field = current behavior. No Hermes signing/verification — caller-owned passthrough.v1 intentionally omits
mcp_headersand chat/completions / responses. Shares themeta=seam with open #47175 / #59081; this PR only forwards client-supplied run meta and should compose additively.Related Issue
Fixes #64890
Type of Change
Changes Made
gateway/platforms/api_server.py— parse/validatemcp_meta; bind/reset ContextVar around the run executortools/mcp_run_meta.py— ContextVar helperstools/mcp_tool.py— forward run meta viacall_tool(..., meta=)(soft-fallback if kwarg unsupported)tools/delegate_tool.py— snapshot + re-bind meta on subagent workerswebsite/docs/user-guide/features/api-server.md— document the fieldtests/tools/test_mcp_run_meta.py,tests/tools/test_mcp_tool.py,tests/tools/test_delegate.py,tests/gateway/test_api_server_runs.pyHow to Test
pytest tests/tools/test_mcp_run_meta.py tests/tools/test_mcp_tool.py::TestToolHandler tests/tools/test_delegate.py::TestDelegateMcpRunMeta tests/gateway/test_api_server_runs.py::TestStartRun -qPOST /v1/runswith"mcp_meta": {"run_token": "..."}and confirm the MCP server seesparams._meta.run_tokenontools/callmcp_meta—call_toolshape unchanged;"mcp_meta": "x"→ 400 with no run allocated; a run thatdelegate_tasks into MCP still forwards the same metaChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
N/A — API/MCP passthrough; covered by unit tests and SDK wire probe (
params._meta).