Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,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)
Expand All @@ -357,6 +357,7 @@ 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(`Output schema:`, tool.outputSchema);
}

// Discover additional tools provided by a cross-origin frame (in addition to
Expand Down Expand Up @@ -480,8 +481,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.
Expand Down
89 changes: 68 additions & 21 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,21 @@ A <dfn>tool definition</dfn> is a [=struct=] with the following [=struct/items=]

Note: For tools registered by the imperative form of this API (i.e.,
{{ModelContext/registerTool()}}), this is the stringified representation of
{{ModelContextTool/inputSchema}}. For tools registered
{{ModelContextTool/inputSchema}}, created by the [=serialize a tool schema=]
algorithm. For tools registered
[declaratively](https://github.com/webmachinelearning/webmcp/pull/76), this will be a
stringified JSON Schema object created by the
[=synthesize a declarative JSON Schema object algorithm=].
[[!JSON-SCHEMA]]

: <dfn>output schema</dfn>
:: a [=string=].

Note: For tools registered by the imperative form of this API (i.e.,
{{ModelContext/registerTool()}}), this is the stringified representation of
{{ModelContextTool/outputSchema}}, created by the [=serialize a tool schema=]
algorithm.

: <dfn>execute steps</dfn>
:: an algorithm that takes a {{Document}} <var ignore>targetDocument</var>, a [=string=] <var
ignore>inputArguments</var>, an algorithm <var ignore>completionSteps</var> that takes a
Expand Down Expand Up @@ -561,6 +570,31 @@ To <dfn for="model context">unregister a tool</dfn> given a {{ModelContext}} |mo

</div>

<div algorithm>
To <dfn>serialize a tool schema</dfn> given a {{ModelContextTool}} |tool|'s
{{ModelContextTool/inputSchema}} or {{ModelContextTool/outputSchema}} |schema|:

1. If |tool|'s |schema| does not [=map/exist=], then return the empty string.

1. Return the result of [=serializing a JavaScript value to a JSON string=] given |tool|'s |schema|.

<div class="note">
<p>The [=serialize a JavaScript value to a JSON string=] algorithm throws exceptions in the
following cases:</p>

<ol>
<li><p><i>Throws a new {{TypeError}}</i> when the backing "<code>JSON.stringify()</code>"
yields undefined, e.g.,
"<code>inputSchema: { toJSON() {return HTMLDivElement;}}</code>", or
"<code>outputSchema: { toJSON() {return undefined;}}</code>".</p></li>

<li><p><i>Re-throws exceptions</i> thrown by "<code>JSON.stringify()</code>", e.g., when
|tool|'s |schema| is an object with a circular reference, etc.</p></li>
</ol>
</div>

</div>


<h2 id="api">API</h2>

Expand Down Expand Up @@ -620,7 +654,7 @@ is a [=model context=] [=struct=] created alongside the {{ModelContext}}.
<p>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.</p>
or {{ModelContextTool/outputSchema}} is invalid.</p>
</dd>

<dt><code><var ignore>document</var>.{{Document/modelContext}}.{{ModelContext/getTools(options)}}</code></dt>
Expand Down Expand Up @@ -674,26 +708,13 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
U+002D (-), or U+002E (.), then return [=a promise rejected with=] an {{InvalidStateError}}
{{DOMException}}.

1. Let |stringified input schema| be the empty string.
1. Let |stringified input schema| be the result of [=serializing a tool schema=]
given |tool|'s {{ModelContextTool/inputSchema}}. If this threw an exception, then return [=a
promise rejected with=] that exception.

1. If |tool|'s {{ModelContextTool/inputSchema}} [=map/exists=], then set |stringified input schema|
to the result of [=serializing a JavaScript value to a JSON string=], given |tool|'s
{{ModelContextTool/inputSchema}}. If this threw an exception, then return [=a promise rejected
with=] that exception.

<div class="note">
<p>The serialization algorithm above throws exceptions in the following cases:</p>

<ol>
<li><p><i>Throws a new {{TypeError}}</i> when the backing "<code>JSON.stringify()</code>"
yields undefined, e.g.,
"<code>inputSchema: { toJSON() {return HTMLDivElement;}}</code>", or
"<code>inputSchema: { toJSON() {return undefined;}}</code>".</p></li>

<li><p><i>Re-throws exceptions</i> thrown by "<code>JSON.stringify()</code>", e.g., when
"<code>inputSchema</code>" is an object with a circular reference, etc.</p></li>
</ol>
</div>
1. Let |stringified output schema| be the result of [=serializing a tool schema=]
given |tool|'s {{ModelContextTool/outputSchema}}. If this threw an exception, then return [=a
promise rejected with=] that exception.

1. If |options|'s {{ModelContextRegisterToolOptions/signal}} [=map/exists=] and is
[=AbortSignal/aborted=], then return [=a promise rejected with=] |options|'s
Expand Down Expand Up @@ -742,6 +763,9 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
: [=tool definition/input schema=]
:: |stringified input schema|

: [=tool definition/output schema=]
:: |stringified output schema|

: [=tool definition/execute steps=]
:: An algorithm that takes a {{Document}} |targetDocument|, a [=string=] |inputArguments|, an
algorithm |completionSteps|, and a [=unique internal value=] |uuid|, and runs the [=imperative
Expand Down Expand Up @@ -865,6 +889,14 @@ The <dfn method for=ModelContext>getTools(<var>options</var>)</dfn> method steps
Note: This will never throw an exception, because the string stored in the tool
definition is always a valid JSON string.

: {{RegisteredTool/outputSchema}}
:: the result of [=parse a JSON string to a JavaScript value=] given |tool
definition|'s [=tool definition/output schema=], if |tool definition|'s [=tool
definition/output schema=] is not the empty string; otherwise undefined.

Note: This will never throw an exception, because the string stored in the tool
definition is always a valid JSON string.

: {{RegisteredTool/window}}
:: |targetDocument|'s [=relevant global object=]

Expand Down Expand Up @@ -1061,6 +1093,7 @@ dictionary ModelContextTool {
USVString title;
required DOMString description;
object inputSchema;
object outputSchema;
required ToolExecuteCallback execute;
ToolAnnotations annotations;
};
Expand Down Expand Up @@ -1102,6 +1135,13 @@ callback ToolExecuteCallback = Promise<any> (object inputObject, ToolExecuteCall
<p>A JSON Schema object describing the expected input parameters for the tool [[!JSON-SCHEMA]].
</dd>

<dt><code><var ignore>tool</var>["{{ModelContextTool/outputSchema}}"]</code></dt>
<dd>
<p>A JSON Schema object describing the expected output structure for the tool [[!JSON-SCHEMA]],
so that [=agents=] may use it to insert an [=implementation-defined=] message to guide the
language model’s behavior.
</dd>

<dt><code><var ignore>tool</var>["{{ModelContextTool/execute}}"]</code></dt>
<dd>
<p>A callback function that is invoked when an [=agent=] calls the tool. The function receives
Expand Down Expand Up @@ -1205,6 +1245,7 @@ dictionary RegisteredTool {
DOMString title;
required DOMString description;
object inputSchema;
object outputSchema;
required Window window;
required USVString origin;
ToolAnnotations annotations;
Expand All @@ -1229,6 +1270,12 @@ dictionary RegisteredTool {
[[!JSON-SCHEMA]]. It is a deep copy of the schema provided at tool registration, via
{{ModelContextTool/inputSchema}}.

: <code><var ignore>tool</var>["{{RegisteredTool/outputSchema}}"]</code>
:: A JSON Schema object describing the expected output structure for the tool [[!JSON-SCHEMA]], so
that [=agents=] may use it to insert an [=implementation-defined=] message to guide the
language model’s behavior. It is a deep copy of the schema provided at tool registration, via
{{ModelContextTool/outputSchema}}.

: <code><var ignore>tool</var>["{{RegisteredTool/window}}"]</code>
:: The {{Window}} of the document that registered the tool.

Expand Down
2 changes: 1 addition & 1 deletion security-privacy-questionnaire.md
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand Down
Loading