diff --git a/README.md b/README.md
index bf2dfb3..44a6dba 100644
--- a/README.md
+++ b/README.md
@@ -353,7 +353,9 @@ 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`, `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.
+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, or use `{ fromOrigins: ["*"] }` to query all potentially trustworthy origins in that tree. The wildcard does not match opaque origins. Entries other than `"*"` must be valid, potentially trustworthy origins.
+
+The origin wildcard does not bypass Permissions Policy or the provider's explicit `exposedTo` origin list. Authors are encouraged to use explicit origin lists and treat discovered tool descriptions as untrusted data. Other entries are still validated even when `"*"` is present.
```js
// Discover tools exposed by same-origin frames in the tree (default)
@@ -371,6 +373,11 @@ for (const tool of tools) {
const crossOriginTools = await document.modelContext.getTools({
fromOrigins: ["https://trusted-partner.example"]
});
+
+// Discover tools from all eligible origins:
+const allOriginTools = await document.modelContext.getTools({
+ fromOrigins: ["*"]
+});
```
An agent executes a discovered `RegisteredTool` by passing the tool dictionary and input arguments along to `document.modelContext.executeTool()`. The browser securely mediates the execution, ensuring the [`exposedTo`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextregistertooloptions-exposedto) and [`fromOrigins`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextgettooloptions-fromorigins) agree, and the tool runs in the tool owner's execution context:
diff --git a/index.bs b/index.bs
index 847677e..ec28f25 100644
--- a/index.bs
+++ b/index.bs
@@ -173,6 +173,9 @@ An AI platform is a provider of agentic assistants such as OpenAI’s
Supporting concepts
+An origin wildcard is the [=string=] "`*`", used in
+{{ModelContextGetToolOptions/fromOrigins}} to request discovery from all eligible origins.
+
A model context is a [=struct=] with the following [=struct/items=]:
@@ -940,10 +943,18 @@ The getTools(options) method steps
1. Let |from origins| be an empty [=list=] of [=origins=].
+1. Let |includeAllOrigins| be false.
+
1. If |options|'s {{ModelContextGetToolOptions/fromOrigins}} [=map/exists=], then:
1. [=list/For each=] |origin| of |options|'s {{ModelContextGetToolOptions/fromOrigins}}:
+ 1. If |origin| is the [=origin wildcard=], then:
+
+ 1. Set |includeAllOrigins| to true.
+
+ 1. [=iteration/continue=].
+
1. Let |parsedURL| be the result of running the [=URL parser=] on |origin|.
1. If |parsedURL| is failure or its [=url/origin=] is not [$is origin potentially
@@ -973,7 +984,15 @@ The getTools(options) method steps
1. Let |callerOrigin| be |toolRequestor|'s [=Document/origin=].
1. Let |toolOwnerIsRequested| be true if |targetOrigin| is [=same origin=] with
- |callerOrigin|, or if |from origins| [=list/contains=] |targetOrigin|; otherwise, false.
+ |callerOrigin|; otherwise, false.
+
+ 1. If |includeAllOrigins| is true and |targetOrigin| is [$is origin potentially
+ trustworthy?|potentially trustworthy$], then set |toolOwnerIsRequested| to true.
+
+ 1. [=list/For each=] |requestedOrigin| of |from origins|:
+
+ 1. If |targetOrigin| is [=same origin=] with |requestedOrigin|, then set
+ |toolOwnerIsRequested| to true and [=iteration/break=].
1. If |toolOwnerIsRequested| is false, then [=iteration/continue=].
@@ -1343,6 +1362,10 @@ dictionary ModelContextRegisterToolOptions {
:: An {{AbortSignal}} that unregisters the tool when aborted.
+Issue(#317): Wildcard support in {{ModelContextRegisterToolOptions/exposedTo}} requires separate
+consideration of its security implications. More selective matching using {{URLPattern}} is also
+under consideration.
+
ModelContextGetToolOptions Dictionary
The {{ModelContextGetToolOptions}} dictionary allows web applications to filter the tools returned
@@ -1356,11 +1379,26 @@ dictionary ModelContextGetToolOptions {
: options["{{ModelContextGetToolOptions/fromOrigins}}"]
- :: An array of origins from which to query tools. Documents whose origin appears in this list, or
- are same-origin with the caller, have their tools queried. An empty list only includes
- same-origin documents.
+ :: An array of origin strings or the [=origin wildcard=] from which to query tools in the current
+ document's tree. Documents whose origin appears in the array, or are same-origin with the
+ caller, have their tools queried. The [=origin wildcard=] also includes documents with
+ [$is origin potentially trustworthy?|potentially trustworthy$] origins. An omitted or empty
+ array only includes same-origin documents.
+Note: Entries other than the [=origin wildcard=] are validated even when it is present. An invalid
+or non-potentially-trustworthy entry causes {{ModelContext/getTools()}} to reject with a
+"{{SecurityError}}" {{DOMException}}.
+
+
+ Use the [=origin wildcard=] to discover tools from all eligible origins:
+
+ ```js
+ const tools = await document.modelContext.getTools({ fromOrigins: ["*"] });
+ ```
+
+
+
ModelContextExecuteToolOptions Dictionary
The {{ModelContextExecuteToolOptions}} dictionary allows web applications to pass options to
@@ -2051,7 +2089,8 @@ gates are satisfied:
a tool to its parent [=origin=] via {{ModelContextRegisterToolOptions/exposedTo}},
{{ModelContext/getTools()}} only returns tools from [=same origin=] {{Document}}s by default. To
discover tools from a cross-origin descendant [=navigable=], the calling {{Document}} must also
- explicitly list the target [=origin=] in {{ModelContextGetToolOptions/fromOrigins}}.
+ explicitly list the target [=origin=] or the [=origin wildcard=] in
+ {{ModelContextGetToolOptions/fromOrigins}}.
@@ -2089,6 +2128,11 @@ await document.modelContext.registerTool(
);
```
+Note: The [=origin wildcard=] does not restrict discovery to origins trusted by the author.
+Authors are encouraged to use explicit origin lists and treat discovered tool descriptions as
+untrusted data. The provider's {{ModelContextRegisterToolOptions/exposedTo}} origin list and the
+"{{tools}}" Permissions Policy still apply.
+
Residual Risks
Even when cross-origin access is governed by the mechanisms above, two categories of residual risk
diff --git a/security-privacy-questionnaire.md b/security-privacy-questionnaire.md
index db482b4..9078a97 100644
--- a/security-privacy-questionnaire.md
+++ b/security-privacy-questionnaire.md
@@ -74,6 +74,8 @@ The feature is gated by the [`"tools"`](https://webmachinelearning.github.io/web
Additionally, tools can specify [`exposedTo`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextregistertooloptions-exposedto) to control which origins (or `native-agents`, name to be bikeshed per [#179](https://github.com/webmachinelearning/webmcp/pull/179)) can discover them.
+Consumers can use the origin wildcard `"*"` in [`fromOrigins`](https://webmachinelearning.github.io/webmcp/#dom-modelcontextgettooloptions-fromorigins) to query all potentially trustworthy origins in the document's tree. The origin wildcard does not bypass Permissions Policy or the provider's `exposedTo` origin list. Authors are encouraged to use explicit origin lists and treat discovered tool descriptions as untrusted data.
+
> 15. How do the features in this specification work in the context of a browser's Private Browsing or Incognito mode?
We do not anticipate any differences, but implementers should be aware of how to safely handle private browsing modes. See [Interaction with Private Browsing Modes](https://webmachinelearning.github.io/webmcp/#interaction-with-private-browsing).
@@ -103,6 +105,8 @@ Note: this behavior is not yet spec'd but is the intended direction.
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.
+The origin wildcard `"*"` in `fromOrigins` is exempt from origin validation. Other entries are validated even when it is present; invalid or non-potentially-trustworthy entries cause `getTools()` to reject with `SecurityError`.
+
> 21. Does your feature allow sites to learn about the user's use of assistive technology?
No.