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.