From cad2569360346abdada63a8a1a2dd00f7eb3bdf6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Dec 2025 16:44:01 +0000 Subject: [PATCH] Add mcp-context-warning plugin to warn about high MCP context usage This plugin warns users when their MCP servers are consuming significant context (>20k tokens). Many users don't realize MCP servers take up context space, which can lead to unexpectedly fast context exhaustion. The plugin: - Runs a SessionStart hook to check MCP configurations - Estimates token usage based on server and tool counts - Shows a warning with server breakdown if estimated usage > 20k tokens - Provides guidance on how to disable unused MCP servers Slack thread: https://anthropic.slack.com/archives/C07VBSHV7EV/p1765989316572149 --- .claude-plugin/marketplace.json | 11 ++ .../.claude-plugin/plugin.json | 9 + .../hooks/check_mcp_context.py | 164 ++++++++++++++++++ plugins/mcp-context-warning/hooks/hooks.json | 17 ++ 4 files changed, 201 insertions(+) create mode 100644 plugins/mcp-context-warning/.claude-plugin/plugin.json create mode 100755 plugins/mcp-context-warning/hooks/check_mcp_context.py create mode 100644 plugins/mcp-context-warning/hooks/hooks.json diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d0601412..08f5c367 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -102,6 +102,17 @@ "source": "./plugins/learning-output-style", "category": "learning" }, + { + "name": "mcp-context-warning", + "description": "Warns users when MCP servers are consuming significant context (>20k tokens), helping prevent unexpected context exhaustion", + "version": "1.0.0", + "author": { + "name": "Anthropic", + "email": "support@anthropic.com" + }, + "source": "./plugins/mcp-context-warning", + "category": "productivity" + }, { "name": "plugin-dev", "description": "Comprehensive toolkit for developing Claude Code plugins. Includes 7 expert skills covering hooks, MCP integration, commands, agents, and best practices. AI-assisted plugin creation and validation.", diff --git a/plugins/mcp-context-warning/.claude-plugin/plugin.json b/plugins/mcp-context-warning/.claude-plugin/plugin.json new file mode 100644 index 00000000..b35ceeee --- /dev/null +++ b/plugins/mcp-context-warning/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "mcp-context-warning", + "version": "1.0.0", + "description": "Warns users when MCP servers are consuming significant context (>20k tokens), helping prevent unexpected context exhaustion", + "author": { + "name": "Anthropic", + "email": "support@anthropic.com" + } +} diff --git a/plugins/mcp-context-warning/hooks/check_mcp_context.py b/plugins/mcp-context-warning/hooks/check_mcp_context.py new file mode 100755 index 00000000..f2f64c0f --- /dev/null +++ b/plugins/mcp-context-warning/hooks/check_mcp_context.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +""" +MCP Context Warning Hook for Claude Code + +This hook runs at session start and warns users when their MCP servers +are consuming significant context (>20k tokens). This helps users understand +why they might be burning through context quickly. +""" + +import json +import os +import sys +from pathlib import Path + +# Threshold in tokens for showing a warning +TOKEN_WARNING_THRESHOLD = 20000 + +# Estimated tokens per MCP tool (based on real-world data: +# Asana: ~836/tool, Gmail: ~833/tool, Google Calendar: ~1867/tool, Google Drive: ~1260/tool) +# Using 1000 as a conservative average +TOKENS_PER_TOOL_ESTIMATE = 1000 + +# Base overhead per MCP server (connection info, auth, etc.) +BASE_TOKENS_PER_SERVER = 500 + + +def find_mcp_configs(cwd: str) -> list[tuple[str, dict]]: + """ + Find all MCP configuration files that might be loaded. + + Returns list of (path, config) tuples. + """ + configs = [] + + # Check project-level .mcp.json + project_mcp = Path(cwd) / ".mcp.json" + if project_mcp.exists(): + try: + with open(project_mcp) as f: + configs.append((str(project_mcp), json.load(f))) + except (json.JSONDecodeError, IOError): + pass + + # Check user-level MCP config (~/.claude/.mcp.json) + user_mcp = Path.home() / ".claude" / ".mcp.json" + if user_mcp.exists(): + try: + with open(user_mcp) as f: + configs.append((str(user_mcp), json.load(f))) + except (json.JSONDecodeError, IOError): + pass + + return configs + + +def count_servers_and_estimate_tools(configs: list[tuple[str, dict]]) -> tuple[dict, int]: + """ + Count MCP servers and estimate their tool counts. + + Returns (server_info dict, total_estimated_tokens). + """ + server_info = {} + + for path, config in configs: + # MCP config format: {"mcpServers": {"server-name": {...}}} + mcp_servers = config.get("mcpServers", {}) + + for server_name, server_config in mcp_servers.items(): + if server_name in server_info: + continue # Skip duplicates + + # Try to get tool count from config if available + # Otherwise use a default estimate + tool_count = server_config.get("toolCount", 10) # Default 10 tools + + server_info[server_name] = { + "source": path, + "estimated_tools": tool_count, + } + + # Calculate total estimated tokens + total_tokens = 0 + for server_name, info in server_info.items(): + server_tokens = BASE_TOKENS_PER_SERVER + (info["estimated_tools"] * TOKENS_PER_TOOL_ESTIMATE) + info["estimated_tokens"] = server_tokens + total_tokens += server_tokens + + return server_info, total_tokens + + +def format_warning_message(server_info: dict, total_tokens: int) -> str: + """Format a warning message about MCP context usage.""" + + # Build server breakdown table + lines = [ + f"Your MCP servers are using an estimated ~{total_tokens:,} tokens of context.", + "", + "Server breakdown:", + ] + + # Sort servers by token usage (highest first) + sorted_servers = sorted( + server_info.items(), + key=lambda x: x[1]["estimated_tokens"], + reverse=True + ) + + for server_name, info in sorted_servers: + tokens = info["estimated_tokens"] + tools = info["estimated_tools"] + lines.append(f" - {server_name}: ~{tokens:,} tokens ({tools} tools)") + + lines.extend([ + "", + "Consider disabling MCP servers you're not actively using to conserve context.", + "You can manage MCP servers with `/mcp disable ` or by editing .mcp.json.", + ]) + + return "\n".join(lines) + + +def main(): + """Main hook function.""" + # Read input from stdin + try: + raw_input = sys.stdin.read() + input_data = json.loads(raw_input) if raw_input.strip() else {} + except json.JSONDecodeError: + # If we can't parse input, exit silently + sys.exit(0) + + # Get current working directory from hook input or environment + cwd = input_data.get("cwd", os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())) + + # Find MCP configurations + configs = find_mcp_configs(cwd) + + if not configs: + # No MCP configs found, nothing to warn about + sys.exit(0) + + # Count servers and estimate tokens + server_info, total_tokens = count_servers_and_estimate_tools(configs) + + if not server_info: + # No servers configured + sys.exit(0) + + # Check if we're over the warning threshold + if total_tokens >= TOKEN_WARNING_THRESHOLD: + warning_message = format_warning_message(server_info, total_tokens) + + # Output JSON with systemMessage for Claude to see + output = { + "continue": True, + "systemMessage": warning_message + } + print(json.dumps(output)) + + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/plugins/mcp-context-warning/hooks/hooks.json b/plugins/mcp-context-warning/hooks/hooks.json new file mode 100644 index 00000000..f039ace5 --- /dev/null +++ b/plugins/mcp-context-warning/hooks/hooks.json @@ -0,0 +1,17 @@ +{ + "description": "Warns users when MCP servers consume significant context (>20k tokens)", + "hooks": { + "SessionStart": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/check_mcp_context.py", + "timeout": 10 + } + ] + } + ] + } +}