# /// script # requires-python = ">=3.13" # dependencies = ["mcp==2.3.0", "uvicorn>=0.32"] # /// """Unit Converter: the MCP server the guide's first agent starts from (EuKollab guide, Your first agent). One read-only tool with an output schema, served over HTTP at http://localhost:9000/mcp. Run it with: uv run unit_converter.py It refuses units it doesn't know, so `ekl agent init` finds no example for it by itself: the guide shows the fix. Hosted, where the connector reaches it by a private name (unit-converter.railway.internal on Railway, say), set HOST_NAMES to that name, HOST to :: and PORT to its port: the MCP SDK refuses a request whose Host header it doesn't know (421 Misdirected Request), and admits only this machine's names unless told others. """ import os from typing import TypedDict import uvicorn from mcp.server.mcpserver import MCPServer from mcp.server.transport_security import TransportSecuritySettings from mcp.types import ToolAnnotations server = MCPServer("Unit Converter", instructions="Converts lengths between metres, feet and inches.") FACTORS = {"m": 1.0, "ft": 0.3048, "in": 0.0254} class Length(TypedDict): """The tool's typed return value, which the SDK publishes as its output schema.""" value: float unit: str @server.tool(title="Convert a length", annotations=ToolAnnotations(readOnlyHint=True)) def convert_length(value: float, from_unit: str, to_unit: str) -> Length: """Convert a length between metres (m), feet (ft) and inches (in).""" if from_unit not in FACTORS or to_unit not in FACTORS: raise ValueError("units are m, ft or in") return {"value": round(value * FACTORS[from_unit] / FACTORS[to_unit], 6), "unit": to_unit} # The SDK's DNS-rebinding protection, with any names the host gives this server added to this machine's own. NAMES = [ "127.0.0.1", "localhost", "[::1]", *(n.strip() for n in os.environ.get("HOST_NAMES", "").split(",") if n.strip()), ] security = TransportSecuritySettings( allowed_hosts=[h for n in NAMES for h in (n, f"{n}:*")], allowed_origins=["http://127.0.0.1:*", "http://localhost:*", "http://[::1]:*"], ) app = server.streamable_http_app(transport_security=security) if __name__ == "__main__": uvicorn.run(app, host=os.environ.get("HOST", "127.0.0.1"), port=int(os.environ.get("PORT", "9000")))