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
1 changed files with 566 additions and 66 deletions
35
README.md
35
README.md
|
|
@ -290,15 +290,22 @@ The **TUI** had the same gap and is worth checking against the same server (`--t
|
|||
|
||||
#### Unportable tool schemas
|
||||
|
||||
`unportable-schemas-http.json` serves three tools, two of whose advertised
|
||||
`unportable-schemas-http.json` serves four tools, three of whose advertised
|
||||
schemas carry constructs that are legal JSON Schema and are refused or
|
||||
mishandled by real MCP clients: `echo` declares `outputSchema.properties.data`
|
||||
as a bare `true` (what Go's `jsonschema` package emits for `interface{}` —
|
||||
the case reported in [#1005](https://github.com/modelcontextprotocol/inspector/issues/1005)),
|
||||
an array-form `"type": ["null","boolean"]`, and an `opts` property that
|
||||
constrains nothing; `add` points a property at a remote `$ref`. `get_temp` is
|
||||
left clean, so a flagged tool sits next to an unflagged one. Plain
|
||||
streamable-HTTP — connect with the **default (legacy)** protocol era.
|
||||
mishandled by real MCP clients:
|
||||
|
||||
| Tool | What it carries |
|
||||
| --- | --- |
|
||||
| `get_temp` | `outputSchema.properties.data` as a bare `true` — what Go's `jsonschema` package emits for `interface{}`, the case reported in [#1005](https://github.com/modelcontextprotocol/inspector/issues/1005) |
|
||||
| `echo` | an array-form `"type": ["null","boolean"]`, and an `opts` property that constrains nothing |
|
||||
| `add` | a property pointing at a remote `$ref` |
|
||||
| `get_weather` | nothing — left clean, so a flagged tool sits beside an unflagged one |
|
||||
|
||||
Plain streamable-HTTP — connect with the **default (legacy)** protocol era.
|
||||
Every tool here is still **runnable**: the override replaces only the
|
||||
*advertised* schema, and the flagship bare-`true` rides `get_temp` (which
|
||||
returns structured content) rather than `echo` — see the caveat under
|
||||
[Try it](#unportable-tool-schemas) below.
|
||||
|
||||
The Inspector is where a server author looks first, so a construct that will
|
||||
fail downstream is named here rather than passed through silently. All three
|
||||
|
|
@ -313,8 +320,9 @@ mcp-inspector --cli http://127.0.0.1:6603/mcp --method tools/list --strict # e
|
|||
- **CLI** — `--strict` prints the full report (path, issue, suggested fix) on
|
||||
stderr and exits `6` on an error-severity finding; without it, one summary
|
||||
line. See [Schema portability](./clients/cli/README.md#schema-portability---strict).
|
||||
- **TUI** — the tools list marks `echo` with a red `!` and `add` with a yellow
|
||||
`?`; the detail pane lists each finding under **Schema Portability**.
|
||||
- **TUI** — the tools list marks `get_temp` with a red `!` and `echo`/`add`
|
||||
with a yellow `?`; the detail pane lists each finding under **Schema
|
||||
Portability**.
|
||||
- **Web** — the Tools sidebar row carries the same flag as a hover-labelled
|
||||
icon, and selecting the tool shows a **Schema portability** section above the
|
||||
argument form.
|
||||
|
|
@ -329,6 +337,13 @@ test server's `rawToolSchemas` override, because the Zod-built presets cannot
|
|||
express any of them — which is the same reason a real server hits this only
|
||||
when its schemas come from another generator.
|
||||
|
||||
⚠️ **If you add an `outputSchema` override of your own, put it on a tool that
|
||||
returns structured content.** A conforming client validates a tool result
|
||||
against the advertised output schema, so an override on a preset that returns
|
||||
none makes every call to it fail with "declares an output schema but returned
|
||||
no structured content" — a confusing thing to hit from a fixture. That is why
|
||||
the bare `true` rides `get_temp` here and not `echo`.
|
||||
|
||||
#### RFC 6570 resource templates
|
||||
|
||||
`rfc6570-templates-http.json` serves two resource templates straight out of [#1919](https://github.com/modelcontextprotocol/inspector/issues/1919) — `events_by_topic` (`foobar://events/{topic}`) and `events_by_query` (`foobar://events{?topic}`) — each echoing the URI it was matched against, plus a plain `foobar://events` resource (see below). Plain streamable-HTTP; connect with the **default (legacy)** protocol era.
|
||||
|
|
|
|||
Loading…
Reference in a new issue