Uh oh!
There was an error while loading. Please reload this page.
feat(router): support runtime disabling of tools - #809
Conversation
Add methods to disable/enable tools at runtime. Disabled tools are hidden from listing, lookup, and execution, including in composed routers. Closesmodelcontextprotocol#477
There was a problem hiding this comment.
@lutz-grex How should clients learn about runtime disable/enable? I'm worried that the list_tools results will go stale until the client re-lists. I believe the MCP spec has notifications/tools/list_changed for this.
https://modelcontextprotocol.io/specification/2025-11-25/server/tools#list-changed-notification
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Thanks for addressing my inline comments, @lutz-grex but I think you might've missed my concern in #809 (review) I'm curious about your thoughts on the |
lutz-grex
commented
Apr 21, 2026
Yes, I overlooked these - good catch. I’ve now added automatic tools/list_changed notifications. When using Router, this is handled transparently: Router::new() registers a deferred notifier that activates after InitializedNotification. From that point on, enable_route and disable_route emit a notification whenever the visible tool set actually changes. The router also advertises tools.listChanged: true in its capabilities. |
DaleSeo
left a comment
There was a problem hiding this comment.
Thanks, @lutz-grex! I just have minor suggestions.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Add methods to disable/enable tools at runtime.
Disabled tools are hidden from listing, lookup,
and execution, including in composed routers.
Closes#477
Motivation and Context
Users of the
#[tool]+#[tool_handler]macro system had no way to disable specific tools at runtime. The only workaround was manually implementingServerHandler, losing all macro convenience, or usingremove_routewhich permanently destroys the tool.This change adds reversible disable/enable support directly to
ToolRouter, composing naturally with the existing macro workflow:How Has This Been Tested?
test_tool_routers.rscovering:disable, enable, builder pattern, merge preservation,
remove cleanup, pre-disable before add, iterator
filtering, and full invisibility across all query methods
cargo test -p rmcp)disable_routeandenable_routedo not compile on the baseline and workcorrectly after the change
cargo clippy --all-targets --all-featurescleancargo +nightly fmt --allcleanBreaking Changes
has_routenow returnsfalsefor disabled tools (previouslyit only checked map membership). Code relying on
has_routeto test structural presence regardless of enabled state should
use
is_disabledinstead. TheToolRouterstruct is#[non_exhaustive], so adding the privatedisabledfield isnot a breaking change.
Types of changes
Checklist
Additional context
Three files changed:
crates/rmcp/src/handler/server/router/tool.rs— corefeature:
disabledHashSet field, disable/enable/is_disabled/with_disabled methods, updated list_all/call/get/has_route
/merge/remove_route/IntoIterator
crates/rmcp/src/handler/server/router.rs— one-line fix:transparent_when_not_founddispatch now checksis_disabledso disabled tools cannot leak through to the inner service
crates/rmcp/tests/test_tool_routers.rs— 9 new tests