TLDR: If you’re building MCP servers, let users disable individual tools. It’s simple to implement and your context window will thank you.

alt text

Agents often don’t need every tool a MCP server provides. Allowing individual tools to be disabled can not just vastly improve token usage, it aids with tool use reliability, the quality of the model’s output and your security posture.

  • Optimises context use by reducing token count when running many MCP servers
  • Reduces context rot - we know that model performance grows increasingly unreliable as input length grows and that irrelevant information acts as distractors that degrade performance
  • Improves security posture by reducing attack surface - disable risky operations in production while keeping read-only tools available
  • Enables finer-grained control over tool access for organisational compliance

Want the AWS Terraform server but you don’t use Terragrunt? Disable the Terragrunt tool (save 1.1k tokens). Want web search but not video and maps search? Disable the maps and video tools.

The Problem is Real

MCP servers add invaluable capabilities to LLMs and agents, however - unchecked the impact of their many tools quickly becomes apparent.

The numbers are worse than you think:

MCP ServerTool NameTokens
AWS Terraform6.4k (7 tools)
ExecuteTerragruntCommand1.1k
SearchAwsccProviderDocs1.1k
SearchAwsProviderDocs905
SearchUserProvidedModule894
RunCheckovScan806
SearchSpecificAwsIaModules849
ExecuteTerraformCommand743
AWS Cost Explorer9.1k (7 tools)
get_cost_and_usage2.2k
get_cost_comparison_drivers1.9k
get_cost_and_usage_comparisons1.5k
get_cost_forecast1.4k
get_dimension_values910
get_tag_values699
get_today_date469
Playwright9.7k (21 tools)
browser_take_screenshot631
browser_fill_form593
browser_type545
browser_click516
browser_select_option501
…plus 16 more tools390-469
Markdownifypptx-to-markdown4.0k (10 tools)
406
bing-search-to-markdown405
audio-to-markdown404
docx-to-markdown403
image-to-markdown402
…plus 5 more tools394-400
ShadCN UIget_directory_structure3.0k (7 tools)
478
get_component_demo427
get_component422
get_component_metadata422
list_blocks405
…plus 2 more tools376-467

That’s over 32k tokens just for tool descriptions & annotations - before you’ve written a line of code.

Individual tools range from lightweight (387 tokens for basic memory operations) to massive (2.7k tokens for AWS’s documentation generator). The AWS Cost Explorer’s get_cost_and_usage tool alone burns 2.2k tokens describing parameters you might never use.

Fortunately, implementing selective tool disabling is straightforward and the benefits are immediate.

Implementation Advice

Start simple. The conditional registration approach requires minimal code and covers most use cases. If you need runtime flexibility later, you can always refactor to a registry pattern.

  • Parse once: Process environment variables at startup, not per-request
  • Normalise input: Handle whitespace, case variations, and naming conventions (underscore_tool vs hyphen-tool)
  • Use map lookups: O(1) performance with map[string]bool over slice iteration
  • Case insensitivity: Match both ToolName and toolname
  • Whitespace: " tool1 , tool2 " should be equivalent to "tool1,tool2"
  • Empty strings: DISABLED_TOOLS=",tool1,,tool2," should work
  • Non-existent tools: Disabling "non-existent_tool" shouldn’t break anything
  • Fail gracefully: Invalid tool names shouldn’t crash your server

Example Implementation Approaches

I’ve implemented tool disabling in both my mcp-devtools server with a registry based approach,and recently raised a PR to AWS’s MCP servers with a simpler conditional utility. Both work well and take slightly different approaches.

Simple Conditional Registration

In my PR to AWS’s MCP servers, I used straightforward conditional registration. Here’s the pattern:

from awslabs.common.config import tool_enabled

if tool_enabled('ExecuteTerraformCommand'):
    @mcp.tool(name='ExecuteTerraformCommand')
    async def execute_terraform_command(...):
        # existing implementation unchanged

The utility function parses a comma-separated environment variable:

def disabled_tools() -> Set[str]:
    disabled_tools = os.environ.get('DISABLED_TOOLS', '')
    if not disabled_tools:
        return set()
    return {tool.strip() for tool in disabled_tools.split(',') if tool.strip()}

def tool_enabled(tool_name: str) -> bool:
    return tool_name not in disabled_tools()

Configuration is simple:

{
  "env": {
    "DISABLED_TOOLS": "ExecuteTerraformCommand,RunCheckovScan"
  }
}

Registry-Based Runtime Filtering

My MCP DevTools server uses a more sophisticated approach with runtime filtering:

// Tools register normally during init
func init() {
    registry.Register(&ThinkTool{})
}

// But filtering happens at retrieval
func GetTool(name string) (tools.Tool, bool) {
    if disabledFunctions[name] {
        return nil, false
    }
    return toolRegistry[name], true
}

This approach allows for more complex filtering logic and better separation of concerns. The trade-off is slightly more implementation complexity.

Just Do It

Having a pattern for selective tool disabling is something I now add to all MCP servers that I develop and recommend to others. The implementation effort is minimal, but the user value - and performance improvement - is significant.

If you’re maintaining an MCP server, add this feature. Your users are already thinking about their token budgets and context quality - help them optimise both.


Appendix - A Note On The Worst Offender: Github

GitHub’s MCP server is a masterclass in context pollution.

Where other servers hover around 3-10k tokens, The GitHub MCP consumes a staggering 46k tokens across 91 different tools that cannot be individually enabled or disabled. GitHub alone consumes nearly a quarter of Claude Sonnet / Opus 4’s context window - before you even write a single line of code.

For comparison - MCP-DevTools provides the most useful GitHub functionality in just 1.6k tokens with a single tool.

Github’s MCP fails to:

  • Group functionality into broader tools (e.g. list_issues, search_issues, update_issue could be a single issue_management tool).
  • Keep tool description and parameter annotations concise.
  • Provide any mechanism to only enable individual tools.

Github’s Horrible MCP Server