49b9bb6724
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Has been cancelled
53 lines
2.2 KiB
Markdown
53 lines
2.2 KiB
Markdown
# schema-validators
|
|
|
|
Four ways to type a tool parameter so `MCPServer` derives the JSON-Schema
|
|
`inputSchema` and validates arguments before your handler runs: a pydantic
|
|
`BaseModel`, a `TypedDict`, a `@dataclass`, and a bare `dict[str, Any]`. The
|
|
client lists the tools, resolves each `who` schema, and round-trips a call.
|
|
|
|
## Run it
|
|
|
|
```bash
|
|
# stdio (default — the client spawns the server as a subprocess)
|
|
uv run python -m stories.schema_validators.client
|
|
|
|
# HTTP — the client self-hosts the server on a free port, runs, then tears it down
|
|
uv run python -m stories.schema_validators.client --http
|
|
# same, against the lowlevel-API server variant
|
|
uv run python -m stories.schema_validators.client --http --server server_lowlevel
|
|
```
|
|
|
|
## What to look at
|
|
|
|
- `client.py` `main` — the body opens with `async with Client(target, mode=mode)
|
|
as client:`. `target` is anything `Client` accepts (an in-process server, a
|
|
transport, or an HTTP URL); the entry point picks it, the story constructs it.
|
|
- `server.py` — `who.name` vs `who["name"]`: pydantic and dataclass parameters
|
|
arrive as **instances** (attribute access); TypedDict and `dict[str, Any]`
|
|
arrive as plain dicts.
|
|
- `client.py` — the listed `inputSchema` for the three typed variants nests a
|
|
`$defs`/`$ref` object with a `name` property; `greet_dict` publishes only
|
|
`{"type": "object", "additionalProperties": true}` — no field validation.
|
|
- `server_lowlevel.py` — the same schemas written by hand. There is no
|
|
reflection layer at this tier; you author JSON Schema and unpack
|
|
`params.arguments` yourself.
|
|
|
|
## Caveats
|
|
|
|
- Pydantic emits local `#/$defs/` references for nested models. The SDK does
|
|
not dereference network `$ref`s (SEP-2106 MUST NOT); only same-document refs
|
|
are resolved during validation.
|
|
- `PersonTD` is `total=True`, so its nested schema requires both `name` and
|
|
`title`; the `BaseModel` and `@dataclass` variants default `title="friend"`,
|
|
so only `name` is required there. Use `typing.NotRequired[...]` to mark
|
|
optional TypedDict fields.
|
|
|
|
## Spec
|
|
|
|
[Tools — input schema](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#input-schema)
|
|
|
|
## See also
|
|
|
|
`tools/` (output schema → `structuredContent`), `error_handling/` (what
|
|
happens when validation fails).
|