MCP Tools
Tools are callable functions an MCP server exposes to LLMs. The server declares tools via tools/list with a name, description, and JSON Schema inputSchema. The LLM reads the description to decide when to call. The client invokes via tools/call with validated arguments.
Tool Definition
An MCP tool is defined by a name (unique identifier), description (for the LLM to decide when to call it), and inputSchema (JSON Schema defining accepted arguments). Servers expose tools via tools/list. Optional annotations (readOnlyHint, destructiveHint, idempotentHint) describe side effects.
A tool definition is what the MCP server publishes via tools/list. The LLM reads the name and description to decide whether to call the tool. The inputSchema (JSON Schema Draft 7) defines valid arguments.
The description is the most important field – it is the only thing the LLM uses to decide when and how to call the tool. Vague descriptions produce incorrect calls. Specific descriptions with examples produce reliable ones.
Annotations (added in MCP 2025-03-26) are metadata that tell the LLM about side effects without requiring inference from the description: readOnlyHint (no state changes), destructiveHint (may delete data), idempotentHint (safe to retry), openWorldHint (contacts external services).
// tools/list response
{
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a location. Returns temperature, conditions, and wind speed. Use when the user asks about weather in a specific place.",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name. Example: 'London' or 'Paris, France'"
},
"units": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit. Defaults to celsius."
}
},
"required": ["location"]
},
"annotations": {
"readOnlyHint": true,
"idempotentHint": true,
"openWorldHint": true
}
}
]
}tools/list
tools/list returns all tools exposed by an MCP server. Clients call this after initialize to discover available tools. If the server declared listChanged capability, clients receive notifications/tools/list_changed when the tool set changes and should re-call tools/list.
tools/list is how the MCP client discovers what tools a server provides. The client calls this after the initialize handshake. The server returns all tool definitions.
The listChanged capability enables dynamic tool discovery: when tools change, the server sends notifications/tools/list_changed and the client re-fetches.
Large tool lists have a cost – the LLM processes all descriptions on every turn. Servers should only expose tools relevant to the current context.
// tools/list request
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
// Response
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_weather",
"description": "Get current weather...",
"inputSchema": {"type":"object","properties":{"location":{"type":"string"}},"required":["location"]}
},
{
"name": "search_web",
"description": "Search the web...",
"inputSchema": {"type":"object","properties":{"query":{"type":"string"}},"required":["query"]}
}
]
}
}
// Server notifies client when tools change
{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}tools/call
tools/call invokes a specific MCP tool with arguments. The client sends the tool name and arguments object. The server returns a content array (text, image, or resource items). The isError field distinguishes tool execution errors (isError: true) from protocol errors (JSON-RPC error codes).
When the LLM decides to use a tool, the MCP client sends tools/call with the name and arguments. The server executes and returns content items.
Content types: text (plain text or markdown), image (base64 + MIME type), resource (embedded URI + content).
Error handling is split: if the tool executes but encounters a domain error (API returned 404, file not found), return isError: true with a text description. JSON-RPC errors (-32602 etc.) are for protocol-level failures only. This lets the LLM handle domain errors gracefully.
// tools/call request
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_weather","arguments":{"location":"San Francisco","units":"celsius"}}}
// Success
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{"type":"text","text":"San Francisco: 18°C, Partly cloudy. Wind: 15 km/h SW."}],
"isError": false
}
}
// Tool execution error (not a protocol error)
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{"type":"text","text":"Error: Location 'Atlantis' not found."}],
"isError": true
}
}