Topic 2: Defining tools
What a tool is made of
A tool is a function the server offers and the model decides to call. The model never sees your Python. It sees a tool definition, a small JSON object the client fetches with tools/list, and it answers with a name and a set of arguments that the client forwards in tools/call.
A definition has these parts:
| Field | Who reads it | What it is for |
|---|---|---|
name | The model and the client | The identifier the model writes in its tool call. Unique within one server. |
title | People, in the host's UI | A friendly display name such as "Search notes". Optional. |
description | The model | Plain-language instructions: what the tool does, when to use it, what comes back. |
inputSchema | The model and the SDK | A JSON Schema for the arguments. The model uses it to fill arguments, the SDK uses it to reject bad ones. |
outputSchema | The client application | A JSON Schema for structuredContent, the typed result. Optional. |
annotations | The host | Hints about behavior: read-only, destructive, idempotent, open world. |
A JSON Schema is a JSON document that describes the allowed shape of other JSON: which properties exist, their types, which are required, and limits such as a maximum length. Structured content is the typed JSON half of a tool result, meant for code rather than for the model.
In the Python SDK you rarely write any of that JSON by hand. @mcp.tool() reads the function name, the docstring, the type hints, and the return annotation, and builds the definition for you. That convenience is also the trap: whatever you write carelessly becomes the model's instructions.