Skip to content

feat(gateway): propagate per-run mcp_meta to MCP tools/call - #64938

Open
astraltrekkin wants to merge 2 commits into
NousResearch:mainfrom
astraltrekkin:feat/runs-mcp-meta-passthrough
Open

astraltrekkin wants to merge 2 commits into
NousResearch:mainfrom
astraltrekkin:feat/runs-mcp-meta-passthrough

Conversation

@astraltrekkin

@astraltrekkin astraltrekkin commented Jul 15, 2026 •

Copy link
Copy Markdown

What does this PR do?

Adds optional opaque mcp_meta on POST /v1/runs and relays it as MCP tools/call params._meta for that run's lifetime (including delegate_task subagents). 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_headers and chat/completions / responses. Shares the meta= seam with open #47175 / #59081; this PR only forwards client-supplied run meta and should compose additively.

Related Issue

Fixes #64890

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Security fix
  • Documentation update
  • Tests (adding or improving test coverage)
  • Refactor (no behavior change)
  • New skill (bundled or hub)

Changes Made

  • gateway/platforms/api_server.py — parse/validate mcp_meta; bind/reset ContextVar around the run executor
  • tools/mcp_run_meta.py — ContextVar helpers
  • tools/mcp_tool.py — forward run meta via call_tool(..., meta=) (soft-fallback if kwarg unsupported)
  • tools/delegate_tool.py — snapshot + re-bind meta on subagent workers
  • website/docs/user-guide/features/api-server.md — document the field
  • Tests: tests/tools/test_mcp_run_meta.py, tests/tools/test_mcp_tool.py, tests/tools/test_delegate.py, tests/gateway/test_api_server_runs.py

How to Test

  1. 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 -q
  2. POST /v1/runs with "mcp_meta": {"run_token": "..."} and confirm the MCP server sees params._meta.run_token on tools/call
  3. Omit mcp_meta — call_tool shape unchanged; "mcp_meta": "x" → 400 with no run allocated; a run that delegate_tasks into MCP still forwards the same meta

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS (darwin)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

N/A — API/MCP passthrough; covered by unit tests and SDK wire probe (params._meta).

Co-authored-by: Cursor <cursoragent@cursor.com>
@alt-glitch alt-glitch added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint tool/mcp MCP client and OAuth tool/delegate Subagent delegation P3 Low — cosmetic, nice to have labels Jul 15, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for adding the run-scoped MCP metadata path. The capability remains needed: current main tools/mcp_tool.py:4107 calls ClientSession.call_tool without metadata.

The PR captures the value before crossing into the dedicated MCP loop (tools/mcp_tool.py:4143-4165), validates mcp_meta before allocating API run state (gateway/platforms/api_server.py:4368 in the PR diff), and rebinds the snapshot in delegation workers. The pinned MCP SDK supports the keyword-only meta argument (pyproject.toml:207; inspected ClientSession.call_tool signature). The PR's API, MCP-handler, and delegation tests cover the stated paths, and its GitHub checks are passing.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 16, 2026

@syzby syzby left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

One PR addresses #64890. #64938 implements the missing run-scoped correlation path by accepting mcp_meta on POST /v1/runs, carrying it across executor and delegation boundaries, and forwarding it as MCP tools/call _meta while preserving behavior when metadata is absent.

Related pull requests

Suggested consolidation

Keep #64938 open with a salvage path: preserve its validated run-scoped _meta propagation, thread-boundary handling, delegation support, and focused tests, and ask the author to add the downstream-verification clarification identified in review. There are no competing PRs or duplicates to close.

Complex graph

flowchart 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"
Loading

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.

DiademsTech added a commit to DiademsTech/hermes-agent that referenced this pull request Sep 7, 2026
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>

This branch has not been deployed

No deployments
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 comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/delegate Subagent delegation tool/mcp MCP client and OAuth type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: propagate per-run metadata from POST /v1/runs to MCP tools/call requests

5 participants