Skip to content

Commit e3ebab9

Browse files
committed
Merge branch 'main' into ihrpr/remote-snippets
2 parents 362b00e + 0b4ce00 commit e3ebab9

File tree

4 files changed

+57
-75
lines changed

4 files changed

+57
-75
lines changed

README.md

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,12 +1054,7 @@ For more control, you can use the low-level server implementation directly. This
10541054

10551055
<!-- snippet-source examples/snippets/servers/lowlevel/lifespan.py -->
10561056
```python
1057-
"""Low-level server example showing lifespan management.
1058-
1059-
This example demonstrates how to use the lifespan API to manage
1060-
server startup and shutdown, including resource initialization
1061-
and cleanup.
1062-
1057+
"""
10631058
Run from the repository root:
10641059
uv run examples/snippets/servers/lowlevel/lifespan.py
10651060
"""
@@ -1175,13 +1170,9 @@ The lifespan API provides:
11751170

11761171
<!-- snippet-source examples/snippets/servers/lowlevel/basic.py -->
11771172
```python
1178-
"""Basic low-level server example.
1179-
1180-
This example demonstrates the low-level server API with minimal setup,
1181-
showing how to implement basic prompts using the raw protocol handlers.
1182-
1173+
"""
11831174
Run from the repository root:
1184-
uv run examples/snippets/servers/lowlevel/basic.py
1175+
uv run examples/snippets/servers/lowlevel/basic.py
11851176
"""
11861177

11871178
import asyncio
@@ -1213,7 +1204,7 @@ async def handle_get_prompt(name: str, arguments: dict[str, str] | None) -> type
12131204
if name != "example-prompt":
12141205
raise ValueError(f"Unknown prompt: {name}")
12151206

1216-
arg1_value = arguments.get("arg1", "default") if arguments else "default"
1207+
arg1_value = (arguments or {}).get("arg1", "default")
12171208

12181209
return types.GetPromptResult(
12191210
description="Example prompt",
@@ -1258,11 +1249,7 @@ The low-level server supports structured output for tools, allowing you to retur
12581249

12591250
<!-- snippet-source examples/snippets/servers/lowlevel/structured_output.py -->
12601251
```python
1261-
"""Low-level server example showing structured output support.
1262-
1263-
This example demonstrates how to use the low-level server API to return
1264-
structured data from tools, with automatic validation against output schemas.
1265-
1252+
"""
12661253
Run from the repository root:
12671254
uv run examples/snippets/servers/lowlevel/structured_output.py
12681255
"""
@@ -1283,20 +1270,22 @@ async def list_tools() -> list[types.Tool]:
12831270
"""List available tools with structured output schemas."""
12841271
return [
12851272
types.Tool(
1286-
name="calculate",
1287-
description="Perform mathematical calculations",
1273+
name="get_weather",
1274+
description="Get current weather for a city",
12881275
inputSchema={
12891276
"type": "object",
1290-
"properties": {"expression": {"type": "string", "description": "Math expression"}},
1291-
"required": ["expression"],
1277+
"properties": {"city": {"type": "string", "description": "City name"}},
1278+
"required": ["city"],
12921279
},
12931280
outputSchema={
12941281
"type": "object",
12951282
"properties": {
1296-
"result": {"type": "number"},
1297-
"expression": {"type": "string"},
1283+
"temperature": {"type": "number", "description": "Temperature in Celsius"},
1284+
"condition": {"type": "string", "description": "Weather condition"},
1285+
"humidity": {"type": "number", "description": "Humidity percentage"},
1286+
"city": {"type": "string", "description": "City name"},
12981287
},
1299-
"required": ["result", "expression"],
1288+
"required": ["temperature", "condition", "humidity", "city"],
13001289
},
13011290
)
13021291
]
@@ -1305,19 +1294,21 @@ async def list_tools() -> list[types.Tool]:
13051294
@server.call_tool()
13061295
async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
13071296
"""Handle tool calls with structured output."""
1308-
if name == "calculate":
1309-
expression = arguments["expression"]
1310-
try:
1311-
# WARNING: eval() is dangerous! Use a safe math parser in production
1312-
result = eval(expression)
1313-
structured = {"result": result, "expression": expression}
1314-
1315-
# low-level server will validate structured output against the tool's
1316-
# output schema, and automatically serialize it into a TextContent block
1317-
# for backwards compatibility with pre-2025-06-18 clients.
1318-
return structured
1319-
except Exception as e:
1320-
raise ValueError(f"Calculation error: {str(e)}")
1297+
if name == "get_weather":
1298+
city = arguments["city"]
1299+
1300+
# Simulated weather data - in production, call a weather API
1301+
weather_data = {
1302+
"temperature": 22.5,
1303+
"condition": "partly cloudy",
1304+
"humidity": 65,
1305+
"city": city, # Include the requested city
1306+
}
1307+
1308+
# low-level server will validate structured output against the tool's
1309+
# output schema, and additionally serialize it into a TextContent block
1310+
# for backwards compatibility with pre-2025-06-18 clients.
1311+
return weather_data
13211312
else:
13221313
raise ValueError(f"Unknown tool: {name}")
13231314

examples/snippets/servers/lowlevel/basic.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
"""Basic low-level server example.
2-
3-
This example demonstrates the low-level server API with minimal setup,
4-
showing how to implement basic prompts using the raw protocol handlers.
5-
1+
"""
62
Run from the repository root:
7-
uv run examples/snippets/servers/lowlevel/basic.py
3+
uv run examples/snippets/servers/lowlevel/basic.py
84
"""
95

106
import asyncio
@@ -36,7 +32,7 @@ async def handle_get_prompt(name: str, arguments: dict[str, str] | None) -> type
3632
if name != "example-prompt":
3733
raise ValueError(f"Unknown prompt: {name}")
3834

39-
arg1_value = arguments.get("arg1", "default") if arguments else "default"
35+
arg1_value = (arguments or {}).get("arg1", "default")
4036

4137
return types.GetPromptResult(
4238
description="Example prompt",

examples/snippets/servers/lowlevel/lifespan.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
"""Low-level server example showing lifespan management.
2-
3-
This example demonstrates how to use the lifespan API to manage
4-
server startup and shutdown, including resource initialization
5-
and cleanup.
6-
1+
"""
72
Run from the repository root:
83
uv run examples/snippets/servers/lowlevel/lifespan.py
94
"""

examples/snippets/servers/lowlevel/structured_output.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
"""Low-level server example showing structured output support.
2-
3-
This example demonstrates how to use the low-level server API to return
4-
structured data from tools, with automatic validation against output schemas.
5-
1+
"""
62
Run from the repository root:
73
uv run examples/snippets/servers/lowlevel/structured_output.py
84
"""
@@ -23,20 +19,22 @@ async def list_tools() -> list[types.Tool]:
2319
"""List available tools with structured output schemas."""
2420
return [
2521
types.Tool(
26-
name="calculate",
27-
description="Perform mathematical calculations",
22+
name="get_weather",
23+
description="Get current weather for a city",
2824
inputSchema={
2925
"type": "object",
30-
"properties": {"expression": {"type": "string", "description": "Math expression"}},
31-
"required": ["expression"],
26+
"properties": {"city": {"type": "string", "description": "City name"}},
27+
"required": ["city"],
3228
},
3329
outputSchema={
3430
"type": "object",
3531
"properties": {
36-
"result": {"type": "number"},
37-
"expression": {"type": "string"},
32+
"temperature": {"type": "number", "description": "Temperature in Celsius"},
33+
"condition": {"type": "string", "description": "Weather condition"},
34+
"humidity": {"type": "number", "description": "Humidity percentage"},
35+
"city": {"type": "string", "description": "City name"},
3836
},
39-
"required": ["result", "expression"],
37+
"required": ["temperature", "condition", "humidity", "city"],
4038
},
4139
)
4240
]
@@ -45,19 +43,21 @@ async def list_tools() -> list[types.Tool]:
4543
@server.call_tool()
4644
async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
4745
"""Handle tool calls with structured output."""
48-
if name == "calculate":
49-
expression = arguments["expression"]
50-
try:
51-
# WARNING: eval() is dangerous! Use a safe math parser in production
52-
result = eval(expression)
53-
structured = {"result": result, "expression": expression}
46+
if name == "get_weather":
47+
city = arguments["city"]
48+
49+
# Simulated weather data - in production, call a weather API
50+
weather_data = {
51+
"temperature": 22.5,
52+
"condition": "partly cloudy",
53+
"humidity": 65,
54+
"city": city, # Include the requested city
55+
}
5456

55-
# low-level server will validate structured output against the tool's
56-
# output schema, and automatically serialize it into a TextContent block
57-
# for backwards compatibility with pre-2025-06-18 clients.
58-
return structured
59-
except Exception as e:
60-
raise ValueError(f"Calculation error: {str(e)}")
57+
# low-level server will validate structured output against the tool's
58+
# output schema, and additionally serialize it into a TextContent block
59+
# for backwards compatibility with pre-2025-06-18 clients.
60+
return weather_data
6161
else:
6262
raise ValueError(f"Unknown tool: {name}")
6363

0 commit comments

Comments
 (0)