Input schemas with JSON Schema
Tools take inputs. The inputSchema field describes what the tool expects using JSON Schema. Claude reads this to decide when and how to call your tool.
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query"
},
"limit": {
"type": "integer",
"description": "Max results",
"default": 10
}
},
"required": ["query"]
}
required fields must be provided by Claude. Optional fields have defaults.
Tool naming and descriptions
Claude reads your tool name and description to decide when to use it. Write them to be crystal clear:
Good: "search_google" — "Search Google for web results"
Better: "web_search" — "Search the web for current information. Use this when the user asks questions about recent events or needs up-to-date information."
Include context: when should Claude use this tool? What can it do well?
Returning results
Tools can return text, structured data, or images. Always return results as a list of Content objects:
from mcp.types import TextContent, ImageContent
# Text result
return [TextContent(type="text", text="Hello")]
# JSON data
import json
return [TextContent(
type="text",
text=json.dumps({"status": "ok", "count": 5})
)]
# Image
return [ImageContent(
type="image",
data="base64_encoded_image_data",
mimeType="image/png"
)]
Error handling
When a tool encounters an error, be explicit about it:
from mcp.types import TextContent
from mcp.server import McpError
@server.call_tool()
def call_tool(name: str, arguments: dict):
try:
# Your tool logic
result = do_something(arguments)
return [TextContent(type="text", text=result)]
except ValueError as e:
# Return error as content
return [TextContent(
type="text",
text=f"Error: Invalid input. {str(e)}"
)]
except Exception as e:
# Or raise McpError for critical failures
raise McpError(f"Tool failed: {str(e)}")
Return errors as text content when the user should see them. Raise McpError for system failures.
Best practices for tools
💡 Single responsibility
One tool = one task. "search_web" is better than "general_assistant_function".
💡 Clear inputs
Required fields should be essential. Optional fields need sensible defaults.
💡 Consistent output format
Always return the same structure. If you return JSON, keep the schema consistent.
💡 Document edge cases
What happens if the tool is called with invalid input? Include that in the description.
Quick summary
- Define inputSchema using JSON Schema — tell Claude what your tool expects
- Write tool names and descriptions for clarity — Claude relies on them
- Return results as Content objects (text, JSON, or images)
- Handle errors gracefully — return error messages or raise McpError
- Follow best practices: single responsibility, clear inputs, consistent output