Build
What Claude actually sees
Claude never sees your code. It sees a name, a description and a schema, then the result. With the Python SDK, each one comes straight from your code.
server.pypython
from mcp.server import MCPServerfrom mcp.server.mcpserver.exceptions import ToolError mcp = MCPServer("weather") @mcp.tool()async def get_weather( city: str, units: str = "metric") -> str: """Current weather for a city, today only.""" data = await fetch_weather(city, units) if data is None: raise ToolError(f"Unknown city: {city}") return f"{data.temp}° and {data.summary}" if __name__ == "__main__": mcp.run() # stdio by defaultwhat Claude sees (tools/list)json
{ "name": "get_weather", "description": "Current weather for a city, today only.", "inputSchema": { "type": "object", "properties": { "city": { "type": "string" }, "units": { "type": "string", "default": "metric" } }, "required": ["city"] }}- Function namename
- Docstringdescription, read like a prompt
- Type hints + defaultsinputSchema
- Return valuethe tool result
- ToolErroran error Claude can read and fix
On stdio, stdout is the protocol channel
A stray
print() corrupts the message stream. Log to stderr instead.