fix: address Copilot review on the schema portability lint
- Scope `non-object-root` to `inputSchema`. The pinned SDK types
`inputSchema` with `type: literal("object")` but `outputSchema` as a
bare `looseObject`, so a `{"type":"string"}` output is conforming; the
rule was claiming a requirement MCP does not make, at error severity.
- Decide `untyped-schema` from an allowlist of constraining keywords
rather than a denylist of annotations. JSON Schema ignores keywords it
does not recognize, so `{"vendorHint": true}` accepts every value and a
denylist passed it as constrained. `$defs`-only schemas now flag too.
- Walk `dependentSchemas` and draft-07 `dependencies`, with a test
pinning that the property-name-array form is not a schema position.
- Suggest `anyOf` branches for an array-form `type`, never "drop it from
`required`" — accepting `null` and permitting absence are independent
contracts, so the old suggestion silently changed the schema's meaning.
- Reject `--strict` alongside `--app-info`. That path returns NDJSON from
`runMethod` and never reaches the lint, so the flag was a no-op gate
that could never fail.
- Colour the web sidebar flag from the `--inspector-*` severity tokens,
matching the detail panel and avoiding the default yellow that failed
the a11y check.
- Add a live integration test for `rawToolSchemas`. It caught that an
`outputSchema` override on a preset returning no structured content
makes every call to that tool fail client-side validation — the
showcase config did exactly that, so the flagged tool could not be
run. Moved the bare `true` onto `get_temp`, documented the caveat, and
pinned both halves.
- Drop the double cast from the lint test fixture.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
2f9e0901c1
commit
c389565783
2 changed files with 566 additions and 66 deletions
|
|
@ -3,8 +3,22 @@
|
|||
"name": "unportable-schemas-showcase",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"tools": [{ "preset": "echo" }, { "preset": "add" }, { "preset": "get_temp" }],
|
||||
"tools": [
|
||||
{ "preset": "get_temp" },
|
||||
{ "preset": "echo" },
|
||||
{ "preset": "add" },
|
||||
{ "preset": "get_weather" }
|
||||
],
|
||||
"rawToolSchemas": {
|
||||
"get_temp": {
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": true,
|
||||
"city": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"echo": {
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
|
|
@ -13,13 +27,6 @@
|
|||
"show_ids": { "type": ["null", "boolean"] },
|
||||
"opts": {}
|
||||
}
|
||||
},
|
||||
"outputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": true,
|
||||
"topic": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"add": {
|
||||
|
|
|
|||
|
|
@ -507,6 +507,15 @@ export interface ServerConfig {
|
|||
* *advertised* schema is replaced; the tool's handler and its real Zod
|
||||
* validation are untouched, so calling it still behaves as its preset does.
|
||||
*
|
||||
* ⚠️ **Overriding `outputSchema` changes what a client will accept.** A
|
||||
* conforming client validates a tool result against the advertised output
|
||||
* schema, so putting one on a preset whose handler returns no
|
||||
* `structuredContent` makes every call to it fail — the Inspector rejects it
|
||||
* with "declares an output schema but returned no structured content". Put an
|
||||
* `outputSchema` override only on a tool that actually returns structured
|
||||
* content (`get_temp`, `list_items`), and keep the override permissive enough
|
||||
* that the real payload still validates.
|
||||
*
|
||||
* A name that isn't registered is ignored.
|
||||
*/
|
||||
rawToolSchemas?: Record<
|
||||
|
|
|
|||
Loading…
Reference in a new issue