@@ -371,54 +371,54 @@ def get_context(self) -> Context[ServerSession, LifespanResultT, Request]:
371
371
a Context parameter in your tool/resource functions. Use this method only
372
372
when you need context access from code that isn't directly called by FastMCP.
373
373
374
- ## When to use this method
374
+ You might call this method directly in:
375
375
376
- **Helper functions**: When context is needed in utility functions:
376
+ - **Helper functions**
377
377
378
- ```python
379
- mcp = FastMCP(name="example")
378
+ ```python
379
+ mcp = FastMCP(name="example")
380
380
381
- async def log_operation(operation: str):
382
- # Get context when it's not injected
383
- ctx = mcp.get_context()
384
- await ctx.info(f"Performing operation: {operation}")
381
+ async def log_operation(operation: str):
382
+ # Get context when it's not injected
383
+ ctx = mcp.get_context()
384
+ await ctx.info(f"Performing operation: {operation}")
385
385
386
- @mcp.tool()
387
- async def main_tool(data: str) -> str:
388
- await log_operation("data_processing") # Helper needs context
389
- return process_data(data)
390
- ```
386
+ @mcp.tool()
387
+ async def main_tool(data: str) -> str:
388
+ await log_operation("data_processing") # Helper needs context
389
+ return process_data(data)
390
+ ```
391
391
392
- **Callbacks and event handlers**: When context is needed in async callbacks:
392
+ - **Callbacks** and ** event handlers** when context is needed in async callbacks
393
393
394
- ```python
395
- async def progress_callback(current: int, total: int):
396
- ctx = mcp.get_context() # Access context in callback
397
- await ctx.report_progress(current, total)
394
+ ```python
395
+ async def progress_callback(current: int, total: int):
396
+ ctx = mcp.get_context() # Access context in callback
397
+ await ctx.report_progress(current, total)
398
398
399
- @mcp.tool()
400
- async def long_operation(data: str) -> str:
401
- return await process_with_callback(data, progress_callback)
402
- ```
399
+ @mcp.tool()
400
+ async def long_operation(data: str) -> str:
401
+ return await process_with_callback(data, progress_callback)
402
+ ```
403
403
404
- **Class methods**: When context is needed in class-based code:
404
+ - **Class methods** when context is needed in class-based code
405
405
406
- ```python
407
- class DataProcessor:
408
- def __init__(self, mcp_server: FastMCP):
409
- self.mcp = mcp_server
410
-
411
- async def process_chunk(self, chunk: str) -> str:
412
- ctx = self.mcp.get_context() # Get context in method
413
- await ctx.debug(f"Processing chunk of size {len(chunk)}")
414
- return processed_chunk
406
+ ```python
407
+ class DataProcessor:
408
+ def __init__(self, mcp_server: FastMCP):
409
+ self.mcp = mcp_server
415
410
416
- processor = DataProcessor(mcp)
411
+ async def process_chunk(self, chunk: str) -> str:
412
+ ctx = self.mcp.get_context() # Get context in method
413
+ await ctx.debug(f"Processing chunk of size {len(chunk)}")
414
+ return processed_chunk
417
415
418
- @mcp.tool()
419
- async def process_data(data: str) -> str:
420
- return await processor.process_chunk(data)
421
- ```
416
+ processor = DataProcessor(mcp)
417
+
418
+ @mcp.tool()
419
+ async def process_data(data: str) -> str:
420
+ return await processor.process_chunk(data)
421
+ ```
422
422
423
423
Returns:
424
424
[`Context`][mcp.server.fastmcp.Context] object for the current request
@@ -1247,7 +1247,7 @@ async def simple_tool(data: str) -> str:
1247
1247
# No context needed
1248
1248
return f"Processed: {data}"
1249
1249
1250
- @mcp.tool()
1250
+ @mcp.tool()
1251
1251
async def advanced_tool(data: str, ctx: Context) -> str:
1252
1252
# Context automatically injected
1253
1253
await ctx.info("Starting processing")
@@ -1271,7 +1271,7 @@ async def advanced_tool(data: str, ctx: Context) -> str:
1271
1271
```python
1272
1272
await ctx.debug("Detailed debug information")
1273
1273
await ctx.info("General status updates")
1274
- await ctx.warning("Important warnings")
1274
+ await ctx.warning("Important warnings")
1275
1275
await ctx.error("Error conditions")
1276
1276
```
1277
1277
@@ -1289,7 +1289,7 @@ async def advanced_tool(data: str, ctx: Context) -> str:
1289
1289
class UserPrefs(BaseModel):
1290
1290
format: str
1291
1291
detailed: bool
1292
-
1292
+
1293
1293
result = await ctx.elicit("How should I format the output?", UserPrefs)
1294
1294
if result.action == "accept":
1295
1295
format_data(data, result.data.format)
@@ -1325,12 +1325,12 @@ class ProcessingOptions(BaseModel):
1325
1325
1326
1326
@mcp.tool()
1327
1327
async def process_data(
1328
- data: str,
1328
+ data: str,
1329
1329
ctx: Context,
1330
1330
auto_format: bool = False
1331
1331
) -> str:
1332
1332
await ctx.info(f"Starting to process {len(data)} characters")
1333
-
1333
+
1334
1334
# Get user preferences if not auto-formatting
1335
1335
if not auto_format:
1336
1336
if ctx.session.check_client_capability(
@@ -1348,18 +1348,18 @@ async def process_data(
1348
1348
format_type = "standard"
1349
1349
include_meta = False
1350
1350
else:
1351
- format_type = "standard"
1351
+ format_type = "standard"
1352
1352
include_meta = False
1353
1353
else:
1354
1354
format_type = "auto"
1355
1355
include_meta = True
1356
-
1356
+
1357
1357
# Process with progress updates
1358
1358
for i in range(0, len(data), 100):
1359
1359
chunk = data[i:i+100]
1360
1360
await ctx.report_progress(i, len(data), f"Processing chunk {i//100 + 1}")
1361
1361
# ... process chunk
1362
-
1362
+
1363
1363
await ctx.info(f"Processing complete with format: {format_type}")
1364
1364
return processed_data
1365
1365
```
@@ -1418,10 +1418,10 @@ def request_context(
1418
1418
async def advanced_tool(data: str, ctx: Context) -> str:
1419
1419
# Access lifespan context directly
1420
1420
db = ctx.request_context.lifespan_context["database"]
1421
-
1421
+
1422
1422
# Access request metadata
1423
1423
progress_token = ctx.request_context.meta.progressToken if ctx.request_context.meta else None
1424
-
1424
+
1425
1425
return processed_data
1426
1426
```
1427
1427
"""
@@ -1470,19 +1470,19 @@ async def elicit(
1470
1470
1471
1471
This method enables interactive data collection from clients during tool processing.
1472
1472
The client may display the message to the user and collect a response according to
1473
- the provided Pydantic schema, or if the client is an agent, it may automatically
1473
+ the provided Pydantic schema, or if the client is an agent, it may automatically
1474
1474
generate an appropriate response. This is useful for gathering additional parameters,
1475
1475
user preferences, or confirmation before proceeding with operations.
1476
1476
1477
- You typically access this method through the [`Context`][mcp.server.fastmcp.Context]
1477
+ You typically access this method through the [`Context`][mcp.server.fastmcp.Context]
1478
1478
object injected into your FastMCP tool functions. Always check that the client
1479
1479
supports elicitation using [`check_client_capability`][mcp.server.session.ServerSession.check_client_capability]
1480
1480
before calling this method.
1481
1481
1482
1482
Args:
1483
1483
message: The prompt or question to present to the user. Should clearly explain
1484
1484
what information is being requested and why it's needed.
1485
- schema: A Pydantic model class defining the expected response structure.
1485
+ schema: A Pydantic model class defining the expected response structure.
1486
1486
According to the MCP specification, only primitive types (str, int, float, bool)
1487
1487
and simple containers (list, dict) are allowed - no complex nested objects.
1488
1488
@@ -1519,13 +1519,13 @@ async def process_data(data: str, ctx: Context) -> str:
1519
1519
):
1520
1520
# Fall back to default processing
1521
1521
return process_with_defaults(data)
1522
-
1522
+
1523
1523
# Ask user for processing preferences
1524
1524
result = await ctx.elicit(
1525
1525
"How would you like me to process this data?",
1526
1526
ProcessingOptions
1527
1527
)
1528
-
1528
+
1529
1529
if result.action == "accept":
1530
1530
options = result.data
1531
1531
await ctx.info(f"Processing with format: {options.format}")
@@ -1546,12 +1546,12 @@ class ConfirmDelete(BaseModel):
1546
1546
@mcp.tool()
1547
1547
async def delete_files(pattern: str, ctx: Context) -> str:
1548
1548
files = find_matching_files(pattern)
1549
-
1549
+
1550
1550
result = await ctx.elicit(
1551
1551
f"About to delete {len(files)} files matching '{pattern}'. Continue?",
1552
1552
ConfirmDelete
1553
1553
)
1554
-
1554
+
1555
1555
if result.action == "accept" and result.data.confirm:
1556
1556
await ctx.info(f"Deletion confirmed: {result.data.reason}")
1557
1557
return delete_files(files)
@@ -1572,7 +1572,7 @@ async def configure_system(ctx: Context) -> str:
1572
1572
"How should I configure the system?",
1573
1573
UserChoice
1574
1574
)
1575
-
1575
+
1576
1576
match result.action:
1577
1577
case "accept":
1578
1578
choice = result.data
@@ -1642,10 +1642,10 @@ def request_id(self) -> str:
1642
1642
async def traceable_tool(data: str, ctx: Context) -> str:
1643
1643
# Log with request ID for traceability
1644
1644
print(f"Processing request {ctx.request_id}")
1645
-
1645
+
1646
1646
# Request ID is automatically included in Context methods
1647
1647
await ctx.info("Starting processing") # Links to this request
1648
-
1648
+
1649
1649
return processed_data
1650
1650
```
1651
1651
"""
@@ -1664,7 +1664,7 @@ def session(self) -> ServerSession:
1664
1664
which internally use this session with appropriate request linking.
1665
1665
1666
1666
Returns:
1667
- [`ServerSession`][mcp.server.session.ServerSession]: The session for
1667
+ [`ServerSession`][mcp.server.session.ServerSession]: The session for
1668
1668
communicating with the client and accessing advanced MCP features.
1669
1669
1670
1670
Examples:
@@ -1693,7 +1693,7 @@ async def advanced_tool(data: str, ctx: Context) -> str:
1693
1693
@mcp.tool()
1694
1694
async def update_resource(uri: str, ctx: Context) -> str:
1695
1695
# ... update the resource ...
1696
-
1696
+
1697
1697
# Notify client of resource changes
1698
1698
await ctx.session.send_resource_updated(AnyUrl(uri))
1699
1699
return "Resource updated"
0 commit comments