Skip to content

feat(mcp): CIMD client identification for OAuth MCP (salvage #84050) - #89566

Merged
teknium1 merged 2 commits into
mainfrom
salvage/mcp-cimd
Aug 19, 2026
Merged

feat(mcp): CIMD client identification for OAuth MCP (salvage #84050)#89566
teknium1 merged 2 commits into
mainfrom
salvage/mcp-cimd

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Hermes now identifies itself to OAuth MCP servers with a published Client ID Metadata Document (CIMD) — the client-identification mechanism the MCP 2026-07-28 spec adopted in place of per-install Dynamic Client Registration — falling back to DCR automatically on servers that don't advertise or that reject it.

Salvage of #84050 by @rob-maron, rebased onto current main (post mcp 2.x SDK migration), with one hardening fix on top.

Changes

  • website/static/oauth/client-metadata.json: the published CIMD document (client_id = its own github.io URL, 10 loopback redirect URIs)
  • tools/mcp_oauth.py: CIMD eligibility (_maybe_use_cimd), pinned callback ports 27890-27894 (spec requires exact redirect-URI match), pinned-socket parking, durable .cimd-off rejection marker, CIMD-aware timeout message
  • tools/mcp_oauth_manager.py: forwards client_metadata_url to the provider; on invalid_client rejection of the document, drops to DCR and records the marker
  • scripts/ci/classify_changes.py: the static JSON is python-relevant (cross-artifact test asserts on it)
  • website/docs/: CIMD/DCR reference section + feature-page note
  • Follow-up (ours): the reservation-FIFO eviction cap no longer closes parked pinned CIMD sockets — only ephemeral reservations are evicted, so a pinned flow can't be silently converted back into a stealable-port window (fix: TOCTOU port race between _find_free_port() and HTTPServer bind #22161 class)

Validation

Result
tests/tools/test_mcp_cimd.py (43 tests, incl. new eviction test) pass
tests/tools/test_mcp_oauth.py pass (2 pre-existing failures on the local pre-2.x SDK venv reproduce identically on origin/main — not from this PR)
tests/ci/test_classify_changes.py pass
Conflict resolution mcp 2.x waiter signature/timeout semantics kept from main; CIMD url threaded through both provider build sites

Contributor authorship preserved via cherry-pick. Closes #84050; implements the CIMD half of #75576.

Infographic

CIMD client identification infographic

@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 90ee4de — fix: never evict pinned CIMD sockets from the callback reser

⚠️ Warnings

OSV vulnerability scan · View job

7 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 8m13s vs 7m4s (+16.3%). 14 job(s) slower, 11 faster,

  • Python tests / Run tests slice 11/12: -137.0s
  • Python tests / Run tests slice 3/12: +57.0s
  • Python tests / Run tests slice 7/12: +48.0s
  • Python tests / Run tests slice 5/12: +37.0s
  • Python tests / Run tests slice 2/12: +32.0s

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/tools Tool registry, model_tools, toolsets tool/mcp MCP client and OAuth area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation labels Aug 18, 2026
rob-maron and others added 2 commits August 18, 2026 19:53
The _MAX_RESERVED_SOCKETS cap applied to pinned CIMD sockets too, so under
heavy concurrency an ephemeral-reservation churn could close a parked pinned
socket before _wait_for_callback adopted it, silently reopening the
port-stealing window the pin exists to prevent (#22161). Eviction now skips
the pinned range; it is already bounded by _CIMD_PORTS.

Follow-up to the #84050 salvage.
@teknium1
teknium1 merged commit 5dd1587 into main Aug 19, 2026
84 of 86 checks passed
@teknium1
teknium1 deleted the salvage/mcp-cimd branch August 19, 2026 03:03
teknium1 added a commit that referenced this pull request Aug 19, 2026
…75576)

Some authorization servers and WAFs reject httpx's default User-Agent on
the OAuth token endpoint. mcp_servers.<name>.oauth.user_agent now stamps a
custom User-Agent onto the two token-endpoint requests (authorization-code
exchange and refresh) on both provider construction paths. Opt-in,
per-server, token requests only — never MCP traffic or discovery, and no
other headers are configurable. Empty/null/non-string values are ignored.

Completes the second half of #75576 (the CIMD half landed via #89566).
lisajlau pushed a commit to lisajlau/hermes-agent that referenced this pull request Aug 20, 2026
…ousResearch#75576)

Some authorization servers and WAFs reject httpx's default User-Agent on
the OAuth token endpoint. mcp_servers.<name>.oauth.user_agent now stamps a
custom User-Agent onto the two token-endpoint requests (authorization-code
exchange and refresh) on both provider construction paths. Opt-in,
per-server, token requests only — never MCP traffic or discovery, and no
other headers are configurable. Empty/null/non-string values are ignored.

Completes the second half of NousResearch#75576 (the CIMD half landed via NousResearch#89566).
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
…ousResearch#75576)

Some authorization servers and WAFs reject httpx's default User-Agent on
the OAuth token endpoint. mcp_servers.<name>.oauth.user_agent now stamps a
custom User-Agent onto the two token-endpoint requests (authorization-code
exchange and refresh) on both provider construction paths. Opt-in,
per-server, token requests only — never MCP traffic or discovery, and no
other headers are configurable. Empty/null/non-string values are ignored.

Completes the second half of NousResearch#75576 (the CIMD half landed via NousResearch#89566).
bobaba76 pushed a commit to bobaba76/hermes-agent that referenced this pull request Aug 27, 2026
…ousResearch#75576)

Some authorization servers and WAFs reject httpx's default User-Agent on
the OAuth token endpoint. mcp_servers.<name>.oauth.user_agent now stamps a
custom User-Agent onto the two token-endpoint requests (authorization-code
exchange and refresh) on both provider construction paths. Opt-in,
per-server, token requests only — never MCP traffic or discovery, and no
other headers are configurable. Empty/null/non-string values are ignored.

Completes the second half of NousResearch#75576 (the CIMD half landed via NousResearch#89566).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data 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.

3 participants