Repository navigation
Add outputSchema to ModelContextTool and RegisteredTool - #254
Conversation
Codify WebMCP JSON Schema subset (Draft 2020-12) per 2026-03-05 CG resolution.
Meta-validation in registerTool() (TypeError on invalid schema) and input
validation in executeTool() parallel block before tool execute steps
(DataError with {path,reason,schemaPath} for agent self-correction).
Spec-only per review; WPT split to web-platform-tests/wpt (tentative).
Coordinates with webmachinelearning#254 (outputSchema, same dictionaries).
|
Is this still planned on being added? |
a7e008f to
a988ee0
Compare
I hope so :) 🤞 @domfarolino I've started experimenting with |
a988ee0 to
ec56f58
Compare
markafoltz
left a comment
There was a problem hiding this comment.
A few questions/comments about how the serialization result is passed around (might be missing some key idea)
markafoltz
left a comment
There was a problem hiding this comment.
Looks good % a few optional suggested edits
|
Thanks for working on this. One thing I'd like to see said explicitly is that leaving out Related, and a question more than a request: since results are serialized as JSON, a tool that returns a string comes back as a JSON string with quotes and escaped newlines. Is that the intended shape for text results, or is a plain text result something to look at separately (maybe together with the typed results work in #41 and #282)? On sjdallst2's question about validation, I'd say a result that doesn't match should reach the host as a tool error, so the host can tell it from a normal result and decide what to do. Also, a schema is written by the page, so the description fields inside it are model-visible text from the page and should get the same treatment as tool descriptions. |
|
@domfarolino I think we're good now. |
SHA: 6cd745a Reason: push, by domfarolino Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This adds an optional outputSchema dictionary member to ModelContextTool and RegisteredTool to define the expected structure of tool execution return values. Upon registration, outputSchema is serialized with the tool schema serialization algorithm, throwing a TypeError on serialization failure before checking abort signals. getTools() exposes outputSchema as a parsed JSON Schema object, or undefined when omitted. Spec PR: webmachinelearning/webmcp#254 Bug: 489045948 Bug: 565876481 Change-Id: I5e333c74c834cd6bc29253609e4e3d74edb09d08
This adds an optional outputSchema dictionary member to ModelContextTool and RegisteredTool to define the expected structure of tool execution return values. Upon registration, outputSchema is serialized with the tool schema serialization algorithm, throwing a TypeError on serialization failure before checking abort signals. getTools() exposes outputSchema as a parsed JSON Schema object, or undefined when omitted. Spec PR: webmachinelearning/webmcp#254 Bug: 489045948 Bug: 565876481 Change-Id: I5e333c74c834cd6bc29253609e4e3d74edb09d08 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8398367 Reviewed-by: Khushal Sagar <khushalsagar@chromium.org> Reviewed-by: Dominic Farolino <dom@chromium.org> Commit-Queue: Fr <beaufort.francois@gmail.com> Cr-Commit-Position: refs/heads/main@{#1732837}
This adds an optional outputSchema dictionary member to ModelContextTool and RegisteredTool to define the expected structure of tool execution return values. Upon registration, outputSchema is serialized with the tool schema serialization algorithm, throwing a TypeError on serialization failure before checking abort signals. getTools() exposes outputSchema as a parsed JSON Schema object, or undefined when omitted. Spec PR: webmachinelearning/webmcp#254 Bug: 489045948 Bug: 565876481 Change-Id: I5e333c74c834cd6bc29253609e4e3d74edb09d08 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8398367 Reviewed-by: Khushal Sagar <khushalsagar@chromium.org> Reviewed-by: Dominic Farolino <dom@chromium.org> Commit-Queue: Fr <beaufort.francois@gmail.com> Cr-Commit-Position: refs/heads/main@{#1732837}
This adds an optional outputSchema dictionary member to ModelContextTool and RegisteredTool to define the expected structure of tool execution return values. Upon registration, outputSchema is serialized with the tool schema serialization algorithm, throwing a TypeError on serialization failure before checking abort signals. getTools() exposes outputSchema as a parsed JSON Schema object, or undefined when omitted. Spec PR: webmachinelearning/webmcp#254 Bug: 489045948 Bug: 565876481 Change-Id: I5e333c74c834cd6bc29253609e4e3d74edb09d08 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8398367 Reviewed-by: Khushal Sagar <khushalsagar@chromium.org> Reviewed-by: Dominic Farolino <dom@chromium.org> Commit-Queue: Fr <beaufort.francois@gmail.com> Cr-Commit-Position: refs/heads/main@{#1732837}
Follows webmachinelearning/webmcp#254, which adds an optional outputSchema to ModelContextTool and RegisteredTool. The content script forwards RegisteredTool.outputSchema to the side panel, which sends it as its own field of each tool declaration. Only Gemini gives it to the model, as responseJsonSchema on the function declaration. The AI SDK's Google provider only sends name, description and parametersJsonSchema, and the SDK's own tool outputSchema never reaches any provider, so the Google provider's fetch adds the field to the request body. The model is opened for each turn with that turn's output schemas, so concurrent chats never see each other's tools. OpenAI, Anthropic, Ollama and the on-device Prompt API have no such field, and the schema is not mixed into the tool description either. webmcp-types does not declare outputSchema yet, so the WebMCP types are augmented locally until it does.
Follows webmachinelearning/webmcp#254, which adds an optional outputSchema to ModelContextTool and RegisteredTool. The content script forwards RegisteredTool.outputSchema to the side panel, which sends it as its own field of each tool declaration. Only Gemini gives it to the model, as responseJsonSchema on the function declaration. The AI SDK's Google provider only sends name, description and parametersJsonSchema, and the SDK's own tool outputSchema never reaches any provider, so the Google provider's fetch adds the field to the request body. The model is opened for each turn with that turn's output schemas, so concurrent chats never see each other's tools. OpenAI, Anthropic, Ollama and the on-device Prompt API have no such field, and the schema is not mixed into the tool description either. webmcp-types does not declare outputSchema yet, so the WebMCP types are augmented locally until it does.
Follows webmachinelearning/webmcp#254, which adds an optional outputSchema to ModelContextTool and RegisteredTool. The content script forwards RegisteredTool.outputSchema to the side panel, which checks every result of that tool against it, before the result is truncated or spotlighted. A result that does not match goes back to the model as a tool error saying where it differs, as MCP clients do with structured content. A schema that cannot be used is the page's mistake, so the result is then passed on unchecked. The check is done in the side panel, so it holds for the backend server and the on-device Prompt API alike. The schema is not sent to any model: only Gemini has a field for it, and the model is better served by results known to match than by a description of what they should look like. Results are validated with @cfworker/json-schema, which never evaluates code, as the extension's content security policy requires. webmcp-types does not declare outputSchema yet (webmachinelearning/webmcp-types#16), so RegisteredTool is augmented locally until it does.
The spec added outputSchema to ModelContextTool and RegisteredTool (webmachinelearning/webmcp#254, merged 2026-11-02; Chrome 159): a JSON Schema for the tool's result, which agents may use to reject a result that does not validate. It is reactive and compared by content like inputSchema, so a change re-registers the tool and a rebuilt identical object does not. useWebMCPTools and defineWebMCPTool take it through the shared options type, the stub stores it and returns it from getTools(), and the descriptor and RegisteredTool types declare it until webmcp-types does (its PR #16 is open). Normalization is unchanged, as in use-webmcp-tool's open PR #18: the spec defines no structured result field, and a { content } value already passes through untouched for tools that want to add structuredContent.
This PR adds an optional
outputSchemamember to theModelContextToolandRegisteredTooldictionaries to enable browser agents and in-page agents to help LLMs reliably reason about the return values of tools.While
responseConstraintwas previously discussed, that name is too specific to the Built-in AI / Prompt API. TheoutputSchemaname aligns directly with the MCP Tools specificationoutputSchemaused to define expected structured outputs with JSON Schema.FIX #9
Preview | Diff