You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/mcp/client.md
+141-1Lines changed: 141 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -280,7 +280,7 @@ async def main():
280
280
```
281
281
282
282
1. When you supply `http_client`, Pydantic AI re-uses this client for every
283
-
request. Anything supported by **httpx** (`verify`, `cert`, custom
283
+
request. Anything supported by **httpx** (`verify`, `cert`, custom
284
284
proxies, timeouts, etc.) therefore applies to all MCP traffic.
285
285
286
286
## MCP Sampling
@@ -391,3 +391,143 @@ server = MCPServerStdio(
391
391
allow_sampling=False,
392
392
)
393
393
```
394
+
395
+
## Elicitation
396
+
397
+
In MCP, [elicitation](https://modelcontextprotocol.io/docs/concepts/elicitation) allows a server to request for [structured input](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#supported-schema-types) from the client for missing or additional context during a session.
398
+
399
+
Elicitation let models essentially say "Hold on - I need to know X before i can continue" rather than requiring everything upfront or taking a shot in the dark.
400
+
401
+
### How Elicitation works
402
+
403
+
Elicitation introduces a new protocol message type called [`ElicitRequest`](https://modelcontextprotocol.io/specification/2025-06-18/schema#elicitrequest), which is sent from the server to the client when it needs additional information. The client can then respond with an [`ElicitResult`](https://modelcontextprotocol.io/specification/2025-06-18/schema#elicitresult) or an `ErrorData` message.
404
+
405
+
Here's a typical interaction:
406
+
407
+
- User makes a request to the MCP server (e.g. "Book a table at that Italian place")
408
+
- The server identifies that it needs more information (e.g. "Which Italian place?", "What date and time?")
409
+
- The server sends an `ElicitRequest` to the client asking for the missing information.
410
+
- The client receives the request, presents it to the user (e.g. via a terminal prompt, GUI dialog, or web interface).
411
+
- User provides the requested information, `decline` or `cancel` the request.
412
+
- The client sends an `ElicitResult` back to the server with the user's response.
413
+
- With the structured data, the server can continue processing the original request.
414
+
415
+
This allows for a more interactive and user-friendly experience, especially for multi-staged workflows. Instead of requiring all information upfront, the server can ask for it as needed, making the interaction feel more natural.
416
+
417
+
### Setting up Elicitation
418
+
419
+
To enable elicitation, provide an [`elicitation_callback`][pydantic_ai.mcp.MCPServer.elicitation_callback] function when creating your MCP server instance:
restaurant: str= Field(description='Choose a restaurant')
432
+
party_size: int= Field(description='Number of people', ge=1, le=8)
433
+
date: str= Field(description='Reservation date (DD-MM-YYYY)')
434
+
435
+
436
+
@mcp.tool()
437
+
asyncdefbook_table(ctx: Context) -> str:
438
+
"""Book a restaurant table with user input."""
439
+
# Ask user for booking details using Pydantic schema
440
+
result =await ctx.elicit(message='Please provide your booking details:', schema=BookingDetails)
441
+
442
+
if result.action =='accept'and result.data:
443
+
booking = result.data
444
+
returnf'✅ Booked table for {booking.party_size} at {booking.restaurant} on {booking.date}'
445
+
elif result.action =='decline':
446
+
return'No problem! Maybe another time.'
447
+
else: # cancel
448
+
return'Booking cancelled.'
449
+
450
+
451
+
if__name__=='__main__':
452
+
mcp.run(transport='stdio')
453
+
```
454
+
455
+
This server demonstrates elicitation by requesting structured booking details from the client when the `book_table` tool is called. Here's how to create a client that handles these elicitation requests:
MCP elicitation supports string, number, boolean, and enum types with flat object structures only. These limitations ensure reliable cross-client compatibility. See [supported schema types](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#supported-schema-types) for details.
530
+
531
+
### Security
532
+
533
+
MCP Elicitation requires careful handling - servers must not request sensitive information, and clients must implement user approval controls with clear explanations. See [security considerations](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#security-considerations) for details.
"""The maximum number of times to retry a tool call."""
447
450
451
+
elicitation_callback: ElicitationFnT|None=None
452
+
"""Callback function to handle elicitation requests from the server."""
453
+
448
454
def__init__(
449
455
self,
450
456
command: str,
@@ -460,6 +466,7 @@ def __init__(
460
466
allow_sampling: bool=True,
461
467
sampling_model: models.Model|None=None,
462
468
max_retries: int=1,
469
+
elicitation_callback: ElicitationFnT|None=None,
463
470
*,
464
471
id: str|None=None,
465
472
):
@@ -479,6 +486,7 @@ def __init__(
479
486
allow_sampling: Whether to allow MCP sampling through this client.
480
487
sampling_model: The model to use for sampling.
481
488
max_retries: The maximum number of times to retry a tool call.
489
+
elicitation_callback: Callback function to handle elicitation requests from the server.
482
490
id: An optional unique ID for the MCP server. An MCP server needs to have an ID in order to be used in a durable execution environment like Temporal, in which case the ID will be used to identify the server's activities within the workflow.
483
491
"""
484
492
self.command=command
@@ -496,6 +504,7 @@ def __init__(
496
504
allow_sampling,
497
505
sampling_model,
498
506
max_retries,
507
+
elicitation_callback,
499
508
id=id,
500
509
)
501
510
@@ -605,6 +614,9 @@ class _MCPServerHTTP(MCPServer):
605
614
max_retries: int
606
615
"""The maximum number of times to retry a tool call."""
607
616
617
+
elicitation_callback: ElicitationFnT|None=None
618
+
"""Callback function to handle elicitation requests from the server."""
619
+
608
620
def__init__(
609
621
self,
610
622
*,
@@ -621,6 +633,7 @@ def __init__(
621
633
allow_sampling: bool=True,
622
634
sampling_model: models.Model|None=None,
623
635
max_retries: int=1,
636
+
elicitation_callback: ElicitationFnT|None=None,
624
637
**_deprecated_kwargs: Any,
625
638
):
626
639
"""Build a new MCP server.
@@ -639,6 +652,7 @@ def __init__(
639
652
allow_sampling: Whether to allow MCP sampling through this client.
640
653
sampling_model: The model to use for sampling.
641
654
max_retries: The maximum number of times to retry a tool call.
655
+
elicitation_callback: Callback function to handle elicitation requests from the server.
0 commit comments