Feature/add enable disable methods tools
Added the ability to dynamically enable and disable tools at runtime with client notifications.
Motivation and Context
This change allows developers to temporarily restrict access to specific tools without removing them from the tool manager. This is useful for implementing feature flags, managing resource availability, or controlling access to functionality based on runtime conditions.
How Has This Been Tested?
- Added unit tests for enabling/disabling tools
- Verified that disabled tools don't appear in tool listings and cannot be called
- Tested re-enabling previously disabled tools
Breaking Changes
The tool list now includes the enabled state of each tool. However, all tools are initialized with enabled=True by default, maintaining backward compatibility with existing code.
Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation update
Checklist
- [x] I have read the MCP Documentation
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
I believe it needs a spec change as well. Do we already have a PR for it?
I've added it to the README in this commit: https://github.com/modelcontextprotocol/python-sdk/pull/728/commits/fd71115ed5ad04202ad3c8882a74851ee8781460#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R253
Thank you for this contribution. While dynamic tool enabling/disabling could be useful for testing, we're closing this PR because:
- It creates API confusion (disabled vs non-existent tools)
- Requires MCP protocol changes to be added to SDK
- Adds maintenance burden without clear production benefits
For testing, we recommend using different server configurations or mocking at the application level instead.
@ihrpr
I understand concerns about API complexity, but I'd like to offer a real-world perspective.
The TypeScript MCP SDK already implements this pattern via the RegisteredTool type with methods like enable(), disable(), and update().
Their docs show a practical example for progressive auth:
const putMessageTool = server.tool("putMessage", /* ... */);
putMessageTool.disable(); // User must authenticate first
const upgradeAuthTool = server.tool("upgradeAuth", /* ... */, async ({ permission }) => {
const { ok, previous } = await upgradeAuthAndStoreToken(permission);
if (previous === "read") putMessageTool.enable();
if (permission === "admin") upgradeAuthTool.remove();
});
This approach cleanly supports stateful logic, e.g., enabling tools based on auth state or feature flags, without complex conditions or restarts. It’s not just for testing; it solves real production needs where server behavior must adapt dynamically.
Added the ability to dynamically enable and disable tools at runtime with client notifications.
Please can you expand on this?
The Typescript Feature mentioned is for Dynamic Servers, is the intention here to support it in Python SDK?
Added the ability to dynamically enable and disable tools at runtime with client notifications.
Please can you expand on this?
The Typescript Feature mentioned is for Dynamic Servers, is the intention here to support it in Python SDK?
Yes, this feature implements the same Dynamic Servers capability from the TypeScript sdk.
- enable/disable tools without server restart
- tools appear/disappear based on context (auth, resources, etc.)
- automatic updates when tool lists change
Implementation:
- Added enabled: bool field to tools
- enable()/disable() methods with client notifications
- Filtered tool listing (only enabled tools shown)
- Runtime validation preventing disabled tool execution
@davila7 , @bzsurbhi , I hope you will check the one failing test and approve this PR soon.
Hi @davila7 thank you for this contribution!
I believe this would constitute an enhancement of the actual MCP spec and would therefore need to go through a SEP to make sure we keep SDKs in sync and equivalent.
However, I understand this is actually trying to create parity between Typescript and Python SDKs. Is this a feature we introduced in Typescript without it being in the actual MCP Spec? I at least can't find this explicit capability in the spec itself.
@dsp-ant @ihrpr any thoughts in this case where we had a feature added to one SDK that may have been done before the SEP process was clearly established? Should we block on actually adding the feature to the spec here or prefer parity between SDKs?
Coming back to this one again, I believe we have a similar PR up that's more recent with more engagement: https://github.com/modelcontextprotocol/python-sdk/pull/1322
I'm going to close this one as a potential duplicate - feel free to chime in on that PR or submit another if you disagree.