Tools are the most commonly used MCP primitive. They represent actions that an AI model can invoke -- querying a database, sending an email, creating a file, calling an API. Each tool has a name, a description that helps the model understand when to use it, and an input schema that defines the arguments it accepts. When the model decides to use a tool, the client sends a tools/call request to the server with the tool name and arguments. The server validates the input, executes the tool logic, and returns a structured result. Tools can return text, images, or references to resources. Unlike resources, tools are expected to have side effects -- they do things in the world rather than just exposing data.
Zod schemas provide rich validation and self-documenting inputs. The .describe() method on each field generates descriptions in the JSON Schema that help the model understand what values to provide. Optional fields, enums, and defaults give the model flexibility while constraining inputs to valid values.
The Python SDK infers the input schema from type annotations and the docstring. Union types with None create optional fields, Enum types create enum constraints, and default values are included in the schema. The docstring Args section generates field descriptions. This approach keeps the schema definition close to the implementation.
Tools can return multiple content items of different types in a single response. Text content is the most common, but image content (base64-encoded) is useful for charts, screenshots, and diagrams. The content array lets you combine text analysis with visual output in one tool call, giving the model richer context.
There are two error strategies: soft errors (returning an error message as text content) and hard errors (raising an exception). Soft errors let the model reason about the problem and try again with different inputs -- for example, trying a different user ID. Hard errors indicate unrecoverable failures like network issues. Choose soft errors for user-correctable problems and hard errors for infrastructure failures.
Long-running tools should report progress so the client can display status updates to the user. The context object (ctx) provides a reportProgress method that sends progress notifications to the client. This is especially important for batch operations, file processing, or API calls that may take several seconds.
Writing vague tool descriptions like 'handles data' or 'does operations', which cause the AI model to select the wrong tool or pass incorrect arguments.
Write specific, action-oriented descriptions: 'Search the orders database by customer email, date range, or order status. Returns up to 100 matching orders with their details.' Include what the tool does, what inputs it expects, and what it returns.
Not validating tool inputs beyond the schema, trusting that schema validation alone prevents all bad inputs (e.g., path traversal in file paths, SQL injection in query parameters).
Schema validation checks types and formats but not security constraints. Add business logic validation inside the handler: sanitize file paths, parameterize database queries, and validate that IDs reference existing records.
Returning raw error stack traces to the client when a tool throws an unhandled exception, exposing internal implementation details.
Catch exceptions in your handler and return user-friendly error messages. Log the full stack trace server-side for debugging, but send only a descriptive message to the client: 'Database connection failed' rather than the full connection string and stack.
Defining too many tools on a single server (50+), which overwhelms the model's tool selection and degrades accuracy.
Keep each server focused with 5-15 well-defined tools. If you need more capabilities, split them across multiple servers by domain (one for database operations, one for file management, one for API calls).
Making tool handlers synchronous and blocking, which prevents the server from handling other requests while a long-running tool executes.
Always use async handlers. For CPU-intensive work, offload to a worker thread or subprocess. For I/O-bound work (API calls, database queries), use async/await to keep the event loop free.
MCP tools are the action primitives of the protocol -- they let AI models invoke functions, query databases, call APIs, and modify state. Each tool is defined with a name, description, and input schema. The SDKs handle input validation, JSON-RPC serialization, and error formatting. In TypeScript, use registerTool with Zod schemas; in Python, use the @mcp.tool() decorator with type hints. Write specific descriptions to guide model selection, validate inputs beyond the schema for security, return structured content, and use async handlers for all I/O operations.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.