Documentation Index
Fetch the complete documentation index at: https://docs.mcp-use.com/llms.txt
Use this file to discover all available pages before exploring further.
Elicitation allows MCP tools to request additional information from users during their execution.
Configuration
To enable elicitation, provide an elicitation_callback function when initializing the MCPClient:
from mcp_use.client import MCPClient
from mcp.client.session import RequestContext
from mcp.types import ElicitRequestParams, ElicitResult
async def elicitation_callback(
context: RequestContext,
params: ElicitRequestParams
) -> ElicitResult:
"""
Your elicitation callback implementation.
This function receives a request for user input and returns the user's response.
"""
# Display the message to the user and collect their input
print(f"Server requests: {params.message}")
# Example: Get user input (replace with your UI logic)
if hasattr(params, 'requestedSchema'):
# Handle structured input based on the schema
user_input = await collect_structured_input(params.requestedSchema)
else:
# Handle simple text input
user_input = input("Please provide your response: ")
# Return the result
return ElicitResult(
action="accept", # or "decline" or "cancel"
content=user_input
)
# Initialize client with elicitation support
client = MCPClient(
config="config.json",
elicitation_callback=elicitation_callback
)
Handler Parameters
The elicitation handler receives two parameters:
Elicitation Handler Parameters
| Parameter | Type | Description |
|---|
| context | RequestContext | Request context containing metadata about the elicitation request |
| params | ElicitRequestParams | The MCP elicitation request parameters containing the message and optional schema |
ElicitRequestParams Structure
| Field | Type | Description |
|---|
| message | str | The prompt message to display to the user |
| requestedSchema | dict | None | Optional JSON schema defining the expected response structure |
Response Structure
The handler must return an ElicitResult object that specifies how the user responded:
ElicitResult Structure
| Field | Type | Description |
|---|
| action | Literal['accept', 'decline', 'cancel'] | How the user responded to the elicitation request |
| content | dict | str | None | The user’s input data (required for “accept”, omitted for “decline”/“cancel”) |
Action Types:
- accept: User provided valid input - include their data in the
content field
- decline: User chose not to provide the requested information - omit
content
- cancel: User cancelled the entire operation - omit
content
Example Parameter Usage
async def detailed_elicitation_callback(
context: RequestContext,
params: ElicitRequestParams
) -> ElicitResult:
"""Example showing how to use all parameters."""
# Access the user message
user_message = params.message
print(f"Request: {user_message}")
# Check if schema is provided for structured data
schema = getattr(params, 'requestedSchema', None)
if schema:
# Handle structured input
schema_type = schema.get('type')
properties = schema.get('properties', {})
required_fields = schema.get('required', [])
print(f"Expecting {schema_type} with fields: {list(properties.keys())}")
print(f"Required fields: {required_fields}")
# Collect structured data
user_data = {}
for field_name, field_def in properties.items():
field_type = field_def.get('type', 'string')
description = field_def.get('description', '')
prompt = f"Enter {field_name}"
if description:
prompt += f" ({description})"
prompt += ": "
value = input(prompt)
# Basic type conversion
if field_type == 'number':
value = float(value) if value else None
elif field_type == 'integer':
value = int(value) if value else None
elif field_type == 'boolean':
value = value.lower() in ('true', '1', 'yes') if value else None
user_data[field_name] = value
# Validate required fields
missing = [f for f in required_fields if not user_data.get(f)]
if missing:
print(f"Missing required fields: {missing}")
return ElicitResult(action="cancel")
return ElicitResult(action="accept", content=user_data)
else:
# Handle simple text input
response = input(f"{user_message}: ")
if not response:
return ElicitResult(action="cancel")
return ElicitResult(action="accept", content=response)
Response Actions
Elicitation responses use a three-action model to clearly distinguish between different user intentions:
Accept
User explicitly approved and submitted data:
return ElicitResult(
action="accept",
content={"name": "John Doe", "email": "[email protected]"}
)
Decline
User explicitly declined the request:
return ElicitResult(
action="decline"
# content field is typically omitted
)
Cancel
User dismissed without making an explicit choice:
return ElicitResult(
action="cancel"
# content field is typically omitted
)
Structured Data Requests
MCP tools can request structured data using JSON schemas. The schema defines the expected format and validation rules:
async def advanced_elicitation_callback(
context: RequestContext,
params: ElicitRequestParams
) -> ElicitResult:
"""Handle structured data requests with validation."""
# Check if a schema is provided
if hasattr(params, 'requestedSchema') and params.requestedSchema:
schema = params.requestedSchema
# Example: Handle different schema types
if schema.get('type') == 'object':
properties = schema.get('properties', {})
required_fields = schema.get('required', [])
# Collect data for each property
user_data = {}
for field_name, field_schema in properties.items():
field_type = field_schema.get('type', 'string')
field_description = field_schema.get('description', '')
print(f"{field_name} ({field_type}): {field_description}")
# Collect input based on field type
if field_type == 'string':
value = input(f"Enter {field_name}: ")
elif field_type == 'number':
value = float(input(f"Enter {field_name}: "))
elif field_type == 'boolean':
value = input(f"Enter {field_name} (true/false): ").lower() == 'true'
elif field_type == 'integer':
value = int(input(f"Enter {field_name}: "))
else:
value = input(f"Enter {field_name}: ")
user_data[field_name] = value
# Basic validation for required fields
missing_fields = [field for field in required_fields if field not in user_data or not user_data[field]]
if missing_fields:
print(f"Missing required fields: {missing_fields}")
return ElicitResult(action="cancel")
return ElicitResult(action="accept", content=user_data)
# Fallback to simple text input
response = input(f"{params.message}: ")
return ElicitResult(action="accept", content=response)
When building MCP servers, tools can request user input using the context parameter:
from fastmcp import Context, FastMCP
mcp = FastMCP(name="MyServer")
@mcp.tool
async def purchase_item(ctx: Context) -> str:
"""Purchase an item with user-provided details."""
# Define the schema for purchase information
purchase_schema = {
"type": "object",
"properties": {
"quantity": {
"type": "number",
"minimum": 1,
"description": "Number of items to purchase"
},
"unit": {
"type": "string",
"enum": ["kg", "lbs", "pieces"],
"description": "Unit of measurement"
},
"item_name": {
"type": "string",
"description": "Name of the item to purchase"
}
},
"required": ["quantity", "unit", "item_name"]
}
# Request purchase details from the user
result = await ctx.elicit(
message="Please provide purchase details",
response_type=purchase_schema
)
# Handle different response actions
if result.action == "accept":
data = result.data
return f"Purchasing {data['quantity']} {data['unit']} of {data['item_name']}"
elif result.action == "decline":
return "Purchase declined by user"
else:
return "Purchase cancelled"
@mcp.tool
async def collect_feedback(ctx: Context) -> str:
"""Collect user feedback with a simple text request."""
result = await ctx.elicit(
message="Please provide your feedback about our service"
)
if result.action == "accept":
return f"Thank you for your feedback: {result.data}"
else:
return "No feedback provided"
Integration with MCPAgent
When using elicitation with MCPAgent, the elicitation callback is automatically used during tool execution:
import asyncio
from mcp_use import MCPAgent, MCPClient
from langchain_openai import ChatOpenAI
async def main():
# Define elicitation callback
async def handle_user_input(ctx, params):
# Your UI logic here - this example uses simple input
print(f"\n🤖 Server Request: {params.message}")
if hasattr(params, 'requestedSchema') and params.requestedSchema:
# Handle structured input
schema = params.requestedSchema
if schema.get('type') == 'object':
data = {}
for field, field_schema in schema.get('properties', {}).items():
value = input(f"Enter {field}: ")
data[field] = value
return ElicitResult(action="accept", content=data)
# Simple text input
response = input("Your response: ")
return ElicitResult(action="accept", content=response)
# Create client with elicitation support
client = MCPClient.from_config_file(
"config.json",
elicitation_callback=handle_user_input
)
# Create agent
llm = ChatOpenAI(model="gpt-4")
agent = MCPAgent(llm=llm, client=client)
# Run agent - tools can now request user input
result = await agent.run("Help me purchase some items from the store")
print(result)
if __name__ == "__main__":
asyncio.run(main())
Error Handling
If no elicitation callback is provided but a tool requests user input:
# Without elicitation callback
client = MCPClient(config="config.json") # No elicitation_callback
# Tool that requires elicitation will return an error
session = client.get_session("server_name")
result = await session.call_tool("purchase_item", {})
# This will fail because no elicitation callback is configured