Hand TypedDict tool results to pydantic natively (#3331)
This commit is contained in:
parent
0d92192765
commit
0cee6249ba
1 changed files with 230 additions and 85 deletions
|
|
@ -44,6 +44,7 @@ from mcp_types import (
|
|||
from pydantic import BaseModel
|
||||
from starlette.applications import Starlette
|
||||
from starlette.routing import Mount, Route
|
||||
from typing_extensions import NotRequired, TypedDict
|
||||
|
||||
from mcp.client import Client
|
||||
from mcp.server.context import ServerRequestContext
|
||||
|
|
@ -715,6 +716,32 @@ class TestServerTools:
|
|||
assert "Unknown tool" in content.text
|
||||
|
||||
|
||||
async def test_typeddict_tool_omitting_optional_keys_passes_client_validation():
|
||||
"""The client validates structured content against the tool's output schema, so a `NotRequired`
|
||||
key the tool leaves out must be absent from `structured_content` rather than null."""
|
||||
|
||||
class Person(TypedDict):
|
||||
name: str
|
||||
age: NotRequired[int]
|
||||
|
||||
mcp = MCPServer()
|
||||
|
||||
@mcp.tool()
|
||||
def get_person() -> Person:
|
||||
return {"name": "Dave"}
|
||||
|
||||
async with Client(mcp) as client:
|
||||
(tool,) = (await client.list_tools()).tools
|
||||
assert tool.output_schema == {
|
||||
"type": "object",
|
||||
"title": "Person",
|
||||
"properties": {"name": {"title": "Name", "type": "string"}, "age": {"title": "Age", "type": "integer"}},
|
||||
"required": ["name"],
|
||||
}
|
||||
result = await client.call_tool("get_person", {})
|
||||
assert result.structured_content == {"name": "Dave"}
|
||||
|
||||
|
||||
class TestServerResources:
|
||||
async def test_init_with_resources(self):
|
||||
def get_text() -> str:
|
||||
|
|
|
|||
Loading…
Reference in a new issue