The MCP Guide
Build a server

Defining tools in an MCP server

Tools are the primitive the model actually calls, so they deserve the most care. A well-defined tool is discoverable, unambiguous, and safe to invoke.

The anatomy of a tool #

Every tool needs three things: a name the model references, a description that tells the model what it does and when to use it, and an input schema (JSON Schema) that constrains the arguments.

python@mcp.tool()
def create_issue(repo: str, title: str, body: str = "") -> str:
    """Open a GitHub issue.

    Use this when the user asks to file a bug or feature request.
    repo must be in "owner/name" form.
    """
    ...

Write the description for the model #

The model chooses tools from their descriptions alone. Be prescriptive about when to call the tool, not just what it does. "Open a GitHub issue. Use this when the user asks to file a bug" beats "creates an issue." Name parameters clearly and describe each one.

Return useful results and errors #

Return content the model can act on. When something fails, return an error the model can recover from: "repo not found, check owner/name" is far more useful than "400." Good error text turns a dead end into a retry.

Keep tools focused

One tool, one job. A narrow tool with a tight schema is easier for the model to select correctly than a broad multi-purpose one. Split "manage_repo" into "create_issue", "list_issues", and so on.

Resources & further reading

  • MCP specification MCPThe authoritative protocol spec: messages, capabilities, transports, and lifecycle.
  • Python SDK GitHubThe official Python SDK for building MCP servers and clients.