diff --git a/README.md b/README.md
index e28d86f..bf2dfb3 100644
--- a/README.md
+++ b/README.md
@@ -353,7 +353,7 @@ Any document in the tree matching these origins (and allowed to use `tools` perm
Once tools are registered, in-page agents can discover and invoke them using `getTools()` and `executeTool()`.
-Calling `document.modelContext.getTools()` returns a promise that resolves with an array of `RegisteredTool` dictionary objects. Each object contains the tool's `name`, `description`, `inputSchema`, `origin`, and owner `window`. By default, `getTools()` only returns tools registered by documents same-origin with the caller in the frame tree. To retrieve cross-origin tools, you must explicitly list their origins in the `fromOrigins` option. This array only supports secure origins.
+Calling `document.modelContext.getTools()` returns a promise that resolves with an array of `RegisteredTool` dictionary objects. Each object contains the tool's `name`, `description`, `inputSchema`, `outputSchema`, `origin`, and owner `window`. By default, `getTools()` only returns tools registered by documents same-origin with the caller in the frame tree. To retrieve cross-origin tools, you must explicitly list their origins in the `fromOrigins` option. This array only supports secure origins.
```js
// Discover tools exposed by same-origin frames in the tree (default)
@@ -362,7 +362,8 @@ const tools = await document.modelContext.getTools();
for (const tool of tools) {
console.log(`Tool: ${tool.name} (from ${tool.origin})`);
console.log(`Description: ${tool.description}`);
- console.log(`Parameters schema:`, tool.inputSchema);
+ console.log(`Input schema:`, tool.inputSchema);
+ console.log(`Output schema:`, tool.outputSchema);
}
// Discover additional tools provided by a cross-origin frame (in addition to
@@ -524,8 +525,6 @@ As the WebMCP proposal continues to evolve with community and stakeholder feedba
- **Skills Integration**: Determining if the author should expose a higher-level "skill" to help the agent coordinate multiple related tools to fulfill a user journey. See [Issue #161](https://github.com/webmachinelearning/webmcp/issues/161).
-- **Output schema**: Supporting structured `outputSchema` contracts (complementing `inputSchema`) to help LLMs reliably reason about the return values of tools. See [Issue #9](https://github.com/webmachinelearning/webmcp/issues/9).
-
- **User prompting and elicitation**: Exploring a way for a tool to prompt the user for confirmation when tools require explicit user authorization. This could be done by delegating to the agent and its harness, or by invoking native browser permission dialogue outside of the agent loop. See [Issue #165](https://github.com/webmachinelearning/webmcp/issues/165) and [Issue #50](https://github.com/webmachinelearning/webmcp/issues/50) for discussion about the `ModelContextClient` interface.
- **Tool progress reporting**: For long-running tasks (e.g., batch processing or generating content), the agent may want a way to track a tool's progress. We are exploring how this intersects with the established [MCP Progress](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress) specification.
diff --git a/index.bs b/index.bs
index 8cd4180..669d4d1 100644
--- a/index.bs
+++ b/index.bs
@@ -165,10 +165,21 @@ A tool definition is a [=struct=] with the following [=struct/items=]
:: a [=string=].
: input schema
- :: a [=string=].
-
- Note: This is the stringified representation of the {{ModelContextTool/inputSchema}} passed to
- {{ModelContext/registerTool()}}. [[!JSON-SCHEMA]]
+ :: a [=string=] that is either the empty string, indicating that no input schema was provided, or
+ a JSON string representing a JSON Schema object [[!JSON-SCHEMA]], as returned by the
+ [=serialize a tool schema=] algorithm.
+
+ : output schema
+ :: a [=string=] that is either the empty string, indicating that no output schema was provided,
+ or a JSON string representing a JSON Schema object [[!JSON-SCHEMA]], as returned by the
+ [=serialize a tool schema=] algorithm.
+
+ Note: The [=tool definition/input schema=] and [=tool definition/output schema=] are only the
+ empty string when the corresponding {{ModelContextTool/inputSchema}} or
+ {{ModelContextTool/outputSchema}} member is omitted or explicitly set to undefined. Because
+ these members are of type {{object}}, a non-object value such as
+ " Throws a new {{TypeError}} when the backing " Re-throws exceptions thrown by " Registers a tool that [=agents=] can invoke. Returns a rejected promise if a tool with the
same name is already registered, if the given {{ModelContextTool/name}} or
{{ModelContextTool/description}} are empty strings, or if the {{ModelContextTool/inputSchema}}
- is invalid.inputSchema: """ does not produce the empty string; instead it causes
+ {{ModelContext/registerTool()}} to throw a {{TypeError}} during dictionary conversion.
: execute steps
:: an algorithm that takes a {{Document}} targetDocument, a [=string=] unregister a tool given a {{ModelContext}} |mo
+
+
+JSON.stringify()"
+ yields undefined, e.g.,
+ "inputSchema: { toJSON() {return HTMLDivElement;}}", or
+ "outputSchema: { toJSON() {return undefined;}}".JSON.stringify()", e.g., when
+ the object value has a circular reference.API
@@ -657,7 +692,7 @@ is a [=model context=] [=struct=] created alongside the {{ModelContext}}.
document.{{Document/modelContext}}.{{ModelContext/getTools(options)}}The serialization algorithm above throws exceptions in the following cases:
- -Throws a new {{TypeError}} when the backing "JSON.stringify()"
- yields undefined, e.g.,
- "inputSchema: { toJSON() {return HTMLDivElement;}}", or
- "inputSchema: { toJSON() {return undefined;}}".
Re-throws exceptions thrown by "JSON.stringify()", e.g., when
- "inputSchema" is an object with a circular reference, etc.
A JSON Schema object describing the expected input parameters for the tool [[!JSON-SCHEMA]]. +
tool["{{ModelContextTool/outputSchema}}"]A JSON Schema object describing the expected output structure for the tool [[!JSON-SCHEMA]]. + Tool output is expected to conform to the provided schema, and [=agents=] may reject outputs + that do not validate. +
tool["{{ModelContextTool/execute}}"]A callback function that is invoked when an [=agent=] calls the tool. The function receives
@@ -1270,6 +1313,7 @@ dictionary RegisteredTool {
DOMString title;
required DOMString description;
object inputSchema;
+ object outputSchema;
required Window window;
required USVString origin;
ToolAnnotations annotations;
@@ -1294,6 +1338,12 @@ dictionary RegisteredTool {
[[!JSON-SCHEMA]]. It is a deep copy of the schema provided at tool registration, via
{{ModelContextTool/inputSchema}}.
+ : tool["{{RegisteredTool/outputSchema}}"]
+ :: A JSON Schema object describing the expected output structure for the tool [[!JSON-SCHEMA]].
+ Tool output is expected to conform to the provided schema, and [=agents=] may reject outputs
+ that do not validate. It is a deep copy of the schema provided at tool registration, via
+ {{ModelContextTool/outputSchema}}.
+
: tool["{{RegisteredTool/window}}"]
:: The {{Window}} of the document that registered the tool.
diff --git a/security-privacy-questionnaire.md b/security-privacy-questionnaire.md
index dc0e7df..6e2d7d0 100644
--- a/security-privacy-questionnaire.md
+++ b/security-privacy-questionnaire.md
@@ -101,7 +101,7 @@ Note: this behavior is not yet spec'd but is the intended direction.
> 20. Does your spec define when and how new kinds of errors should be raised?
-Yes. `registerTool()` throws `InvalidStateError` for inactive documents, duplicate names, or invalid name/description; `NotAllowedError` when the `"tools"` Permissions Policy is disallowed; `SecurityError` for non-trustworthy [`exposedTo`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextregistertooloptions-exposedto) origins; and `TypeError` when `inputSchema` serialization fails. These errors only reflect the page's own state and inputs, so they do not leak new information.
+Yes. `registerTool()` throws `InvalidStateError` for inactive documents, duplicate names, or invalid name/description; `NotAllowedError` when the `"tools"` Permissions Policy is disallowed; `SecurityError` for non-trustworthy [`exposedTo`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextregistertooloptions-exposedto) origins; and `TypeError` when `inputSchema` or `outputSchema` serialization fails. These errors only reflect the page's own state and inputs, so they do not leak new information.
> 21. Does your feature allow sites to learn about the user's use of assistive technology?