refactor: replace lowlevel Server decorators with on_* constructor kwargs (#1985)

This commit is contained in:
Max Isbey 2026-02-12 15:55:54 +00:00 • committed by GitHub
commit 0a22a9dc33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -3,62 +3,67 @@ uv run examples/snippets/servers/lowlevel/structured_output.py
"""
import asyncio
from typing import Any
import json
import mcp.server.stdio
from mcp import types
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
server = Server("example-server")
from mcp.server import Server, ServerRequestContext
@server.list_tools()
async def list_tools() -> list[types.Tool]:
async def handle_list_tools(
ctx: ServerRequestContext, params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
"""List available tools with structured output schemas."""
return [
types.Tool(
name="get_weather",
description="Get current weather for a city",
input_schema={
"type": "object",
"properties": {"city": {"type": "string", "description": "City name"}},
"required": ["city"],
},
output_schema={
"type": "object",
"properties": {
"temperature": {"type": "number", "description": "Temperature in Celsius"},
"condition": {"type": "string", "description": "Weather condition"},
"humidity": {"type": "number", "description": "Humidity percentage"},
"city": {"type": "string", "description": "City name"},
return types.ListToolsResult(
tools=[
types.Tool(
name="get_weather",
description="Get current weather for a city",
input_schema={
"type": "object",
"properties": {"city": {"type": "string", "description": "City name"}},
"required": ["city"],
},
"required": ["temperature", "condition", "humidity", "city"],
},
)
]
output_schema={
"type": "object",
"properties": {
"temperature": {"type": "number", "description": "Temperature in Celsius"},
"condition": {"type": "string", "description": "Weather condition"},
"humidity": {"type": "number", "description": "Humidity percentage"},
"city": {"type": "string", "description": "City name"},
},
"required": ["temperature", "condition", "humidity", "city"],
},
)
]
)
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequestParams) -> types.CallToolResult:
"""Handle tool calls with structured output."""
if name == "get_weather":
city = arguments["city"]
if params.name == "get_weather":
city = (params.arguments or {})["city"]
# Simulated weather data - in production, call a weather API
weather_data = {
"temperature": 22.5,
"condition": "partly cloudy",
"humidity": 65,
"city": city, # Include the requested city
"city": city,
}
# low-level server will validate structured output against the tool's
# output schema, and additionally serialize it into a TextContent block
# for backwards compatibility with pre-2025-06-18 clients.
return weather_data
else:
raise ValueError(f"Unknown tool: {name}")
return types.CallToolResult(
content=[types.TextContent(type="text", text=json.dumps(weather_data, indent=2))],
structured_content=weather_data,
)
raise ValueError(f"Unknown tool: {params.name}")
server = Server(
"example-server",
on_list_tools=handle_list_tools,
on_call_tool=handle_call_tool,
)
async def run():
@ -67,14 +72,7 @@ async def run():
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="structured-output-example",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
server.create_initialization_options(),
)