forked from mcp-use/mcp-use
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext_example.py
More file actions
301 lines (230 loc) · 9.16 KB
/
context_example.py
File metadata and controls
301 lines (230 loc) · 9.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
"""
MCP Server Context Example
This example demonstrates all Context features available in mcp-use servers:
- Progress reporting
- Logging
- Request metadata access
- Resource reading from within tools
- Client roots listing
"""
import asyncio
from datetime import datetime
from mcp.types import ToolAnnotations
from mcp_use.server import Context, MCPServer
server = MCPServer(
name="Context Demo Server",
version="1.0.0",
instructions="A server demonstrating all Context features",
debug=True,
pretty_print_jsonrpc=True,
)
# =============================================================================
# TOOLS WITH CONTEXT
# =============================================================================
@server.tool()
async def process_items(items: list[str], context: Context) -> str:
"""Process a list of items with progress reporting.
Demonstrates: context.report_progress()
"""
results = []
total = len(items)
for i, item in enumerate(items):
# Report progress to the client
await context.report_progress(i, total)
# Simulate processing time
await asyncio.sleep(0.1)
results.append(f"Processed: {item.upper()}")
# Report completion
await context.report_progress(total, total)
return "\n".join(results)
@server.tool()
async def log_demo(message: str, context: Context) -> str:
"""Demonstrate different logging levels.
Demonstrates: context.debug(), context.info(), context.warning(), context.error()
"""
# Different log levels available through context
await context.debug(f"Debug: Processing message '{message}'")
await context.info(f"Info: Message received with {len(message)} characters")
await context.warning("Warning: This is a demo warning")
# context.error() is also available for error logging
return f"Logged message: {message}"
@server.tool()
async def get_request_info(context: Context) -> dict:
"""Get information about the current request.
Demonstrates: context.request_id, context.client_id, context.session
"""
info = {
"request_id": str(context.request_id) if context.request_id else "N/A",
"client_id": context.client_id if hasattr(context, "client_id") else "N/A",
"timestamp": datetime.now().isoformat(),
}
await context.info(f"Request info retrieved: {info}")
return info
@server.tool()
async def read_resource_from_tool(resource_uri: str, context: Context) -> str:
"""Read a resource from within a tool.
Demonstrates: context.read_resource()
Try with: "config://database" or "status://health"
"""
try:
# Read a resource using the context
contents = await context.read_resource(resource_uri)
await context.info(f"Successfully read resource: {resource_uri}")
return f"Resource content:\n{contents}"
except Exception as e:
await context.warning(f"Failed to read resource {resource_uri}: {e}")
return f"Error reading resource: {e}"
@server.tool()
async def get_client_roots(context: Context) -> str:
"""Get the list of roots exposed by the client.
Demonstrates: context.list_roots()
Roots represent directories or files that the client has made available
to the server. This is useful for file-based operations where the server
needs to know which paths are accessible.
"""
try:
roots = await context.list_roots()
if not roots:
await context.info("Client has no roots configured")
return "No roots available from client"
await context.info(f"Client exposed {len(roots)} root(s)")
# Format roots for display
lines = [f"Client roots ({len(roots)}):"]
for root in roots:
name = root.name or "(unnamed)"
lines.append(f" - {name}: {root.uri}")
return "\n".join(lines)
except Exception as e:
await context.warning(f"Failed to get client roots: {e}")
return f"Error getting roots: {e}"
@server.tool(
name="long_running_task",
title="Long Running Task",
description="Simulates a long-running task with detailed progress",
annotations=ToolAnnotations(
readOnlyHint=False,
idempotentHint=True,
),
)
async def long_running_task(steps: int, delay_ms: int, context: Context) -> str:
"""Run a multi-step task with progress and logging.
Demonstrates: Combined use of progress + logging
Args:
steps: Number of steps to perform (1-20)
delay_ms: Delay between steps in milliseconds (10-1000)
"""
# Validate inputs
steps = max(1, min(20, steps))
delay_ms = max(10, min(1000, delay_ms))
delay_sec = delay_ms / 1000
await context.info(f"Starting task with {steps} steps, {delay_ms}ms delay each")
for i in range(steps):
step_num = i + 1
# Report progress
await context.report_progress(i, steps)
# Log each step
await context.debug(f"Executing step {step_num}/{steps}")
# Simulate work
await asyncio.sleep(delay_sec)
# Log milestone steps
if step_num == steps // 2:
await context.info("Reached halfway point")
elif step_num == steps:
await context.info("Task completed successfully")
# Final progress report
await context.report_progress(steps, steps)
return f"Completed {steps} steps in {steps * delay_ms}ms"
# =============================================================================
# RESOURCES (can be read from tools via context.read_resource)
# =============================================================================
@server.resource(
uri="config://database", name="database_config", title="Database Configuration", mime_type="application/json"
)
def database_config() -> str:
"""Database connection configuration."""
return """{
"host": "localhost",
"port": 5432,
"database": "myapp",
"pool_size": 10
}"""
@server.resource(uri="config://cache", name="cache_config", title="Cache Configuration", mime_type="application/json")
def cache_config() -> str:
"""Cache configuration settings."""
return """{
"enabled": true,
"ttl_seconds": 3600,
"max_size_mb": 256
}"""
@server.resource(uri="status://health", name="health_status", title="Health Status", mime_type="application/json")
def health_status() -> str:
"""Current server health status."""
return f"""{{
"status": "healthy",
"timestamp": "{datetime.now().isoformat()}",
"uptime": "99.9%"
}}"""
@server.resource(
uri="data://{data_type}",
name="dynamic_data",
title="Dynamic Data",
description="Get data by type (users, products, orders)",
mime_type="application/json",
)
def get_data(data_type: str) -> str:
"""Dynamic data resource with URI template."""
data = {
"users": '[{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]',
"products": '[{"id": 1, "name": "Widget", "price": 9.99}]',
"orders": '[{"id": 1, "user_id": 1, "total": 29.97}]',
}
return data.get(data_type, '{"error": "Unknown data type"}')
# =============================================================================
# PROMPTS
# =============================================================================
@server.prompt(name="help", title="Help", description="Show available context features")
def help_prompt() -> str:
"""Help prompt showing available features."""
return """# Context Demo Server
This server demonstrates MCP Context features:
## Tools with Context
- **process_items**: Progress reporting with `context.report_progress()`
- **log_demo**: Logging with `context.debug/info/warning/error()`
- **get_request_info**: Access request metadata
- **read_resource_from_tool**: Read resources with `context.read_resource()`
- **get_client_roots**: Get client roots with `context.list_roots()`
- **long_running_task**: Combined progress + logging
## Resources (readable via context)
- `config://database` - Database configuration
- `config://cache` - Cache configuration
- `status://health` - Health status
- `data://{type}` - Dynamic data (users, products, orders)
Try: "Process these items: apple, banana, cherry with progress reporting"
"""
@server.prompt(name="task_prompt")
def task_prompt(task_name: str) -> str:
"""Generate a task-specific prompt."""
return f"""Please help me with the following task: {task_name}
Use the available tools to:
1. Track progress with process_items or long_running_task
2. Check logs with log_demo
3. Read configuration with read_resource_from_tool
Available resources:
- config://database
- config://cache
- status://health
- data://users, data://products, data://orders
"""
# =============================================================================
# RUN SERVER
# =============================================================================
if __name__ == "__main__":
print("Starting Context Demo Server...")
print("Features demonstrated:")
print(" - context.report_progress(current, total)")
print(" - context.debug/info/warning/error(message)")
print(" - context.request_id")
print(" - context.read_resource(uri)")
print(" - context.list_roots()")
print()
server.run(transport="streamable-http", port=8000)