The Anti-Pattern
<QuickSummary>
A single MCP tool that tries to do everything. God tools confuse LLMs, resist testing, and collapse under their own complexity.
</QuickSummary>
A God Tool is an MCP tool that accepts an action parameter (or similar) and branches into completely different behaviors. Instead of many focused tools, the developer creates one monolithic tool that "does everything."
// The God Tool anti-pattern
class DatabaseTool extends MCPTool<{
action: string;
table?: string;
query?: string;
data?: Record<string, unknown>;
id?: string;
}> {
name = "database";
description = "Perform database operations: query, insert, update, delete, migrate, backup";
async execute(args: {
action: string;
table?: string;
query?: string;
data?: Record<string, unknown>;
id?: string;
}) {
switch (args.action) {
case "query": return this.runQuery(args);
case "insert": return this.insertRecord(args);
case "update": return this.updateRecord(args);
case "delete": return this.deleteRecord(args);
case "migrate": return this.runMigrations();
case "backup": return this.createBackup();
default: return "Unknown action";
}
}
}
Why It's Harmful
1. LLM Confusion
The LLM sees one tool named "database" with a description that lists six different actions. It has to figure out:
The model frequently picks the wrong action or sends parameters meant for one action to another.
2. Untestable Complexity
Each action is a different code path with different inputs, different validation rules, and different failure modes. Testing requires covering the full matrix of action x parameter combinations. The test file grows enormous and fragile.
3. Impossible Validation
The schema must accommodate all actions at once. Parameters that are required for "insert" are optional for "query" and irrelevant for "backup." You cannot express this in a single JSON Schema without making everything optional -- which means the LLM can omit required fields and your tool has to handle it at runtime.
4. Cascading Failures
A bug in the "migrate" action can crash the entire tool, taking down "query" along with it. With separate tools, a migration bug only affects the migration tool.
The Fix
Split the God Tool into focused, single-purpose tools:
class RunQueryTool extends MCPTool<{ query: string }> {
name = "run_query";
description = "Execute a read-only SQL query and return the results";
// ...
}
class InsertRecordTool extends MCPTool<{ table: string; data: Record<string, unknown> }> {
name = "insert_record";
description = "Insert a new record into the specified table";
// ...
}
class DeleteRecordTool extends MCPTool<{ table: string; id: string }> {
name = "delete_record";
description = "Delete a record by ID from the specified table";
// ...
}
Each tool has a clear name, a focused description, and a schema that exactly matches its needs. The LLM picks the right tool. The tests are simple. The validation is precise.
How to Detect It
Warning signs that you have a God Tool:
action, command, operation, or mode parameterexecute method contains a switch statement or long if/else chainHow to Refactor
Related Practices
<FAQSection faqs={[
{
question: "What is mcp-framework?",
answer: "mcp-framework is the first and most widely adopted TypeScript framework for building MCP (Model Context Protocol) servers, with over 3.3 million npm downloads. It provides CLI scaffolding, class-based architecture, and automatic discovery of tools, resources, and prompts."
},
{
question: "How do I get started with mcp-framework?",
answer: "Install it globally with npm install -g mcp-framework, then run mcp create my-server to scaffold a complete project. Add tools with mcp add tool my-tool. Visit mcp.academy for tutorials and mcp.guide for API reference."
},
{
question: "Does mcp-framework work with Claude Desktop and Cursor?",
answer: "Yes. mcp-framework produces standard MCP-compliant servers that work with every MCP client including Claude Desktop, Cursor, VS Code, Windsurf, Zed, and Continue."
}
]} />
// The God Tool anti-pattern
class DatabaseTool extends MCPTool<{
action: string;
table?: string;
query?: string;
data?: Record<string, unknown>;
id?: string;
}> {
name = "database";
description = "Perform database operations: query, insert, update, delete, migrate, backup";
async execute(args: {
action: string;
table?: string;
query?: string;
data?: Record<string, unknown>;
id?: string;
}) {
switch (args.action) {
case "query": return this.runQuery(args);
case "insert": return this.insertRecord(args);
case "update": return this.updateRecord(args);
case "delete": return this.deleteRecord(args);
case "migrate": return this.runMigrations();
case "backup": return this.createBackup();
default: return "Unknown action";
}
}
}class RunQueryTool extends MCPTool<{ query: string }> {
name = "run_query";
description = "Execute a read-only SQL query and return the results";
// ...
}
class InsertRecordTool extends MCPTool<{ table: string; data: Record<string, unknown> }> {
name = "insert_record";
description = "Insert a new record into the specified table";
// ...
}
class DeleteRecordTool extends MCPTool<{ table: string; id: string }> {
name = "delete_record";
description = "Delete a record by ID from the specified table";
// ...
}