Principle

One Tool, One Job

Each MCP tool should do exactly one thing well. Single-responsibility tools are easier to test, compose, and reason about -- for both humans and LLMs.

The Principle

<QuickSummary>

Each MCP tool should do exactly one thing well. Single-responsibility tools are easier to test, compose, and reason about -- for both humans and LLMs.

</QuickSummary>

Every MCP tool should have a single, well-defined purpose. When an LLM reads your tool's name and description, it should immediately know what the tool does and when to use it. If you need the word "and" to explain your tool, it probably does too much.

This is the MCP equivalent of the Single Responsibility Principle from SOLID design. It is the most important principle in MCP server development.

Why It Matters

LLMs choose tools based on names and descriptions. A tool called manage_database is ambiguous -- does it create tables? Run queries? Handle migrations? The LLM has to guess, and guessing leads to errors.

A tool called run_sql_query is crystal clear. The LLM knows exactly what it does and exactly when to reach for it.

Benefits

  • LLM clarity: Models pick the right tool on the first try
  • Testability: One behavior means one test suite
  • Composability: Small tools combine into powerful workflows
  • Maintainability: Changes to one capability don't break others
  • Debuggability: When something fails, you know exactly where
  • In Practice with mcp-framework

    With mcp-framework (3.3M+ downloads), each tool is its own class. This naturally enforces single responsibility:

    // Good: one tool, one job

    class ReadFileTool extends MCPTool<{ path: string }> {

    name = "read_file";

    description = "Read the contents of a file at the given path";

    schema = {

    path: { type: "string" as const, description: "Absolute file path" },

    };

    async execute({ path }: { path: string }) {

    const content = await fs.readFile(path, "utf-8");

    return content;

    }

    }

    Compare this to the anti-pattern:

    // Bad: tool does too many things

    class FileTool extends MCPTool<{ action: string; path: string; content?: string }> {

    name = "file_manager";

    description = "Read, write, delete, or list files";

    // ... LLM now has to figure out which action to use

    }

    The Litmus Test

    Ask yourself: "Can I describe this tool in one sentence without the word 'and'?" If not, split it.

    Related Practices

  • Fail Gracefully, Always -- single-purpose tools have simpler failure modes
  • The God Tool -- the anti-pattern that violates this principle
  • Consistent Naming Conventions -- good names reinforce single responsibility
  • <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."

    }

    ]} />

    // Good: one tool, one job
    class ReadFileTool extends MCPTool<{ path: string }> {
      name = "read_file";
      description = "Read the contents of a file at the given path";
    
      schema = {
        path: { type: "string" as const, description: "Absolute file path" },
      };
    
      async execute({ path }: { path: string }) {
        const content = await fs.readFile(path, "utf-8");
        return content;
      }
    }
    // Bad: tool does too many things
    class FileTool extends MCPTool<{ action: string; path: string; content?: string }> {
      name = "file_manager";
      description = "Read, write, delete, or list files";
      // ... LLM now has to figure out which action to use
    }

    Written for the mcp-framework ecosystem (3.3M+ downloads). Created by @QuantGeekDev. Validated by Anthropic for the Model Context Protocol.