feat: Add SDK support for SEP-1034 default values in elicitation schemas (#1337)
Co-authored-by: Tapan Chugh <tapanc@cs.washington.edu> Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
This commit is contained in:
@@ -747,6 +747,8 @@ async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerS
|
||||
_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_
|
||||
<!-- /snippet-source -->
|
||||
|
||||
Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms.
|
||||
|
||||
The `elicit()` method returns an `ElicitationResult` with:
|
||||
|
||||
- `action`: "accept", "decline", or "cancel"
|
||||
|
||||
@@ -213,3 +213,58 @@ async def test_elicitation_with_optional_fields():
|
||||
{},
|
||||
text_contains=["Validation failed:", "optional_list"],
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_elicitation_with_default_values():
|
||||
"""Test that default values work correctly in elicitation schemas and are included in JSON."""
|
||||
mcp = FastMCP(name="DefaultValuesServer")
|
||||
|
||||
class DefaultsSchema(BaseModel):
|
||||
name: str = Field(default="Guest", description="User name")
|
||||
age: int = Field(default=18, description="User age")
|
||||
subscribe: bool = Field(default=True, description="Subscribe to newsletter")
|
||||
email: str = Field(description="Email address (required)")
|
||||
|
||||
@mcp.tool(description="Tool with default values")
|
||||
async def defaults_tool(ctx: Context[ServerSession, None]) -> str:
|
||||
result = await ctx.elicit(message="Please provide your information", schema=DefaultsSchema)
|
||||
|
||||
if result.action == "accept" and result.data:
|
||||
return (
|
||||
f"Name: {result.data.name}, Age: {result.data.age}, "
|
||||
f"Subscribe: {result.data.subscribe}, Email: {result.data.email}"
|
||||
)
|
||||
else:
|
||||
return f"User {result.action}"
|
||||
|
||||
# First verify that defaults are present in the JSON schema sent to clients
|
||||
async def callback_schema_verify(context: RequestContext[ClientSession, None], params: ElicitRequestParams):
|
||||
# Verify the schema includes defaults
|
||||
schema = params.requestedSchema
|
||||
props = schema["properties"]
|
||||
|
||||
assert props["name"]["default"] == "Guest"
|
||||
assert props["age"]["default"] == 18
|
||||
assert props["subscribe"]["default"] is True
|
||||
assert "default" not in props["email"] # Required field has no default
|
||||
|
||||
return ElicitResult(action="accept", content={"email": "test@example.com"})
|
||||
|
||||
await call_tool_and_assert(
|
||||
mcp,
|
||||
callback_schema_verify,
|
||||
"defaults_tool",
|
||||
{},
|
||||
"Name: Guest, Age: 18, Subscribe: True, Email: test@example.com",
|
||||
)
|
||||
|
||||
# Test overriding defaults
|
||||
async def callback_override(context: RequestContext[ClientSession, None], params: ElicitRequestParams):
|
||||
return ElicitResult(
|
||||
action="accept", content={"email": "john@example.com", "name": "John", "age": 25, "subscribe": False}
|
||||
)
|
||||
|
||||
await call_tool_and_assert(
|
||||
mcp, callback_override, "defaults_tool", {}, "Name: John, Age: 25, Subscribe: False, Email: john@example.com"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user