feat(mcp): dynamic tool discovery via notifications/tools/list_changed#3812
Merged
feat(mcp): dynamic tool discovery via notifications/tools/list_changed#3812
Conversation
When a connected MCP server sends a ToolListChangedNotification (per the MCP spec), Hermes now automatically re-fetches the tool list, deregisters removed tools, and registers new ones — without requiring a restart. This enables MCP servers with dynamic toolsets (e.g. GitHub MCP with GITHUB_DYNAMIC_TOOLSETS=1) to add/remove tools at runtime. Changes: - registry.py: add ToolRegistry.deregister() for nuke-and-repave refresh - mcp_tool.py: extract _register_server_tools() from _discover_and_register_server() as a shared helper for both initial discovery and dynamic refresh - mcp_tool.py: add _make_message_handler() and _refresh_tools() on MCPServerTask, wired into all 3 ClientSession sites (stdio, new HTTP, deprecated HTTP) - Graceful degradation: silently falls back to static discovery when the MCP SDK lacks notification types or message_handler support - 8 new tests covering registration, refresh, handler dispatch, and deregister Salvaged from PR #1794 by shivvor2.
14 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implement MCP spec's
notifications/tools/list_changednotification handler. When a connected MCP server sends this notification (e.g., GitHub MCP withGITHUB_DYNAMIC_TOOLSETS=1), Hermes automatically re-fetches the tool list, deregisters removed tools, and registers new ones — without requiring a gateway restart or/mcp refresh.Changes
tools/registry.pyToolRegistry.deregister(name)— removes a tool and cleans up its toolset check if it was the last tool in that toolset. Used by the nuke-and-repave refresh strategy.tools/mcp_tool.pyToolListChangedNotification,ServerNotification, etc.) with graceful degradation for older SDK versions_check_message_handler_support()— inspectsClientSessionconstructor to verify the SDK version acceptsmessage_handler_register_server_tools()— extracted from_discover_and_register_server()as a shared helper used by both initial discovery and dynamic refresh. Handles filtering, collision guards, utility tools, toolset creation, and hermes-* injection.MCPServerTask._make_message_handler()— builds a notification callback that dispatches on type;ToolListChangedNotificationtriggers refresh, prompt/resource changes are logged stubsMCPServerTask._refresh_tools()— nuke-and-repave under_refresh_lock: fetch new tools, remove old from registry + hermes-* toolsets, re-register freshmessage_handlerwired into all 3ClientSessionconstruction sites (stdio, new HTTP, deprecated HTTP)tests/tools/test_mcp_dynamic_discovery.py(new, 8 tests)deregister()edge casesBackward compatibility
message_handlersupport, the feature silently degrades to existing static-discovery behaviormcp_serversconfig format is unchangedSalvaged from PR #1794 by @shivvor2.