@@ -17,6 +17,7 @@ Default Biblio Status: current
1717Boilerplate : omit conformance
1818Indent : 2
1919Die On : warning
20+ Test Suite : https://wpt.fyi/results/webmcp
2021</pre>
2122
2223<style>
@@ -171,6 +172,16 @@ A <dfn>tool definition</dfn> is a [=struct=] with the following [=struct/items=]
171172 "internal" steps that have not been defined yet, that describe how to fill out a <{form}> and
172173 its [=form-associated elements=] .
173174
175+ : <dfn>annotations</dfn>
176+ :: an [=annotations=] -or-null.
177+
178+ : <dfn>exposed origins</dfn>
179+ :: a [=list=] or [=origins=] , initially [=list/empty=] .
180+ </dl>
181+
182+ An <dfn>annotations</dfn> is a [=struct=] with the following [=struct/items=] :
183+
184+ <dl dfn-for="annotations">
174185 : <dfn>read-only hint</dfn>
175186 :: a [=boolean=] , initially false.
176187
@@ -179,11 +190,9 @@ A <dfn>tool definition</dfn> is a [=struct=] with the following [=struct/items=]
179190
180191 : <dfn>consequential hint</dfn>
181192 :: a [=boolean=] , initially false.
182-
183- : <dfn>exposed origins</dfn>
184- :: a [=list=] or [=origins=] , initially [=list/empty=] .
185193</dl>
186194
195+
187196<hr>
188197
189198<div algorithm>
@@ -202,7 +211,7 @@ To <dfn>notify documents of a tool change</dfn> given a {{Document}} |tool owner
202211 1. If |targetDocument| is not [=allowed to use=] the "{{tools}} " feature, then
203212 [=iteration/continue=] .
204213
205- 1. If [=tool is visible to an origin=] given |tool owner|'s [=Document/origin=] , |exposed
214+ 1. If [=tool is exposed to an origin=] given |tool owner|'s [=Document/origin=] , |exposed
206215 origins|, and |targetDocument|'s [=Document/origin=] , then [=queue a global task=] on the
207216 [=webmcp task source=] given |targetDocument|'s [=relevant global object=] to [=fire an
208217 event=] named {{ModelContext/toolchange}} at |targetDocument|'s [=Document/associated
@@ -238,14 +247,14 @@ To <dfn>notify documents of a tool change</dfn> given a {{Document}} |tool owner
238247</div>
239248
240249<div algorithm>
241- To determine if a <dfn>tool is visible to an origin</dfn> given an [=origin=] |tool owner origin|,
242- a [=list=] of [=origins=] |exposed origins|, and an [=origin=] |target origin|, run these steps:
250+ To determine if a <dfn>tool is exposed to an origin</dfn> given an [=origin=] |tool owner origin|,
251+ a [=list=] of [=origins=] |exposed origins|, and an [=origin=] |accessing origin|, run these steps:
243252
244- 1. If |tool owner origin| is [=same origin=] with |target origin|, then return true.
253+ 1. If |tool owner origin| is [=same origin=] with |accessing origin|, then return true.
245254
246- 1. [=list/For each=] |origin| of |exposed origins|:
255+ 1. [=list/For each=] |allowed origin| of |exposed origins|:
247256
248- 1. If |target origin| is [=same origin=] with |origin|, then return true.
257+ 1. If |accessing origin| is [=same origin=] with |allowed origin|, then return true.
249258
2502591. Return false.
251260
@@ -316,6 +325,7 @@ The {{ModelContext}} interface provides methods for web applications to register
316325[Exposed=Window, SecureContext]
317326interface ModelContext : EventTarget {
318327 Promise<undefined> registerTool(ModelContextTool tool, optional ModelContextRegisterToolOptions options = {});
328+ Promise<sequence<RegisteredTool> > getTools(optional ModelContextGetToolOptions options = {});
319329
320330 attribute EventHandler ontoolchange;
321331};
@@ -333,6 +343,14 @@ is a [=model context=] [=struct=] created alongside the {{ModelContext}}.
333343 {{ModelContextTool/description}} are empty strings, or if the {{ModelContextTool/inputSchema}}
334344 is invalid.</p>
335345 </dd>
346+
347+ <dt><code><var ignore> document</var> .{{Document/modelContext}} .{{ModelContext/getTools(options)}} </code></dt>
348+ <dd>
349+ <p> Returns a promise that resolves to a list of registered tools from this document and its
350+ descendants that are exposed to this document. This API is designed for so-called "in-page"
351+ agents written in JavaScript, and possibly living in <{iframe}> s. The [=user agent=] 's [=browser
352+ agent=] uses a different internal mechanism to retrieve the tools exposed to it.</p>
353+ </dd>
336354</dl>
337355
338356
@@ -392,15 +410,6 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
392410 </ol>
393411 </div>
394412
395- 1. Let |read-only hint| be true if |tool|'s {{ModelContextTool/annotations}} [=map/exists=] and
396- its {{ToolAnnotations/readOnlyHint}} is true. Otherwise, let it be false.
397-
398- 1. Let |untrusted content hint| be true if |tool|'s {{ModelContextTool/annotations}} [=map/exists=] and
399- its {{ToolAnnotations/untrustedContentHint}} is true. Otherwise, let it be false.
400-
401- 1. Let |consequential hint| be true if |tool|'s {{ModelContextTool/annotations}} [=map/exists=] and
402- its {{ToolAnnotations/consequentialHint}} is true. Otherwise, let it be false.
403-
4044131. Let |promise| be [=a new promise=] created in [=this=] 's [=relevant realm=] .
405414
4064151. Let |signal| be |options|'s {{ModelContextRegisterToolOptions/signal}} .
@@ -447,14 +456,18 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
447456 : [=tool definition/execute steps=]
448457 :: steps that invoke |tool|'s {{ModelContextTool/execute}}
449458
450- : [=tool definition/read-only hint=]
451- :: |read-only hint|
459+ : [=tool definition/annotations=]
460+ :: null if |tool|'s {{ModelContextTool/annotations}} does not [=map/exist=] . Otherwise, an
461+ [=annotations=] with the following [=struct/items=] :
462+
463+ : [=annotations/read-only hint=]
464+ :: |tool|'s {{ModelContextTool/annotations}}' s {{ToolAnnotations/readOnlyHint}}
452465
453- : [=tool definition /untrusted content hint=]
454- :: |untrusted content hint|
466+ : [=annotations /untrusted content hint=]
467+ :: |tool| 's {{ModelContextTool/annotations}}' s {{ToolAnnotations/untrustedContentHint}}
455468
456- : [=tool definition /consequential hint=]
457- :: |consequential hint|
469+ : [=annotations /consequential hint=]
470+ :: |tool| 's {{ModelContextTool/annotations}}' s {{ToolAnnotations/consequentialHint}}
458471
459472 : [=tool definition/exposed origins=]
460473 :: |exposed origins|
@@ -472,6 +485,119 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
472485
473486</div>
474487
488+ <div algorithm>
489+ The <dfn method for=ModelContext>getTools(<var>options</var>)</dfn> method steps are:
490+
491+ 1. Let |global| be [=this=] 's [=relevant global object=] .
492+
493+ 1. Let |toolRequestor| be |global|'s [=associated Document|associated <code>Document</code>=] .
494+
495+ 1. If |toolRequestor| is not [=Document/fully active=] , then return [=a promise rejected with=] an
496+ "{{InvalidStateError}} " {{DOMException}} .
497+
498+ 1. If this's [=surrounding agent=] 's [=agent cluster=]' s [=is origin-keyed=] is false and this's
499+ [=relevant settings object=] 's [=environment settings object/origin=]' s [=origin/scheme=] is not
500+ <code> "file"</code> , then return [=a promise rejected with=] a "{{SecurityError}} "
501+ {{DOMException}} .
502+
503+ 1. If |toolRequestor| is not [=allowed to use=] the "{{tools}} " feature, then return [=a promise
504+ rejected with=] a "{{NotAllowedError}} " {{DOMException}} .
505+
506+ 1. Let |from origins| be an empty [=list=] of [=origins=] .
507+
508+ 1. If |options|'s {{ModelContextGetToolOptions/fromOrigins}} [=map/exists=] , then:
509+
510+ 1. [=list/For each=] |origin| of |options|'s {{ModelContextGetToolOptions/fromOrigins}} :
511+
512+ 1. Let |parsedURL| be the result of running the [=URL parser=] on |origin|.
513+
514+ 1. If |parsedURL| is failure or its [=url/origin=] is not [$is origin potentially
515+ trustworthy?|potentially trustworthy$], then return [=a promise rejected with=] a
516+ "{{SecurityError}} " {{DOMException}} .
517+
518+ 1. [=list/Append=] |parsedURL|'s [=url/origin=] to |from origins|.
519+
520+ 1. Let |promise| be [=a new promise=] created in [=this=] 's [=relevant realm=] .
521+
522+ 1. Run the following steps [=in parallel=] :
523+
524+ 1. Let |tools| be an empty [=list=] of {{RegisteredTool}} dictionaries.
525+
526+ 1. Let |navigables| be |toolRequestor|'s [=node navigable=]' s [=navigable/traversable
527+ navigable=] 's [=Document/inclusive descendant navigables=] .
528+
529+ 1. [=list/For each=] |navigable| of |navigables|:
530+
531+ 1. Let |targetDocument| be |navigable|'s [=navigable/active document=] .
532+
533+ 1. If |targetDocument| is not [=allowed to use=] the "{{tools}} " feature, then
534+ [=iteration/continue=] .
535+
536+ 1. Let |targetOrigin| be |targetDocument|'s [=Document/origin=] .
537+
538+ 1. Let |callerOrigin| be |toolRequestor|'s [=Document/origin=] .
539+
540+ 1. If |toolOwnerIsRequested| be true if |targetOrigin| is [=same origin=] with |callerOrigin|,
541+ or if |from origins| [=list/contains=] |targetOrigin|; otherwise, false.
542+
543+ 1. If |toolOwnerIsRequested| is false, then [=iteration/continue=] .
544+
545+ 1. Let |targetToolMap| be |targetDocument|'s [=Document/associated ModelContext|associated
546+ <code>ModelContext</code>=] 's [=ModelContext/internal context=]' s [=model context/tool
547+ map=] .
548+
549+ 1. [=map/For each=] <var ignore> tool name</var> → |tool definition| of |targetToolMap|:
550+
551+ 1. If [=tool is exposed to an origin=] given |targetOrigin|, |tool definition|'s [=tool
552+ definition/exposed origins=] , and |callerOrigin| returns false, then
553+ [=iteration/continue=] .
554+
555+ 1. Let |registeredTool| be a new {{RegisteredTool}} dictionary, with the following fields:
556+
557+ : {{RegisteredTool/name}}
558+ :: |tool definition|'s [=tool definition/name=]
559+
560+ : {{RegisteredTool/title}}
561+ :: |tool definition|'s [=tool definition/title=] if it is non-null; otherwise the empty
562+ string.
563+
564+ Issue(#224): Consider not defaulting to the empty string, and just excluding this
565+ member, which will result in {{undefined}} .
566+
567+ : {{RegisteredTool/description}}
568+ :: |tool definition|'s [=tool definition/description=]
569+
570+ : {{RegisteredTool/inputSchema}}
571+ :: |tool definition|'s [=tool definition/input schema=] if it is not the empty string;
572+ otherwise undefined.
573+
574+ : {{RegisteredTool/window}}
575+ :: |targetDocument|'s [=relevant global object=]
576+
577+ : {{RegisteredTool/origin}}
578+ :: |targetOrigin|, [=serialization of an origin|serialized=] .
579+
580+ : {{RegisteredTool/annotations}}
581+ :: if |tool definition|'s [=tool definition/annotations=] is not null, a
582+ {{ToolAnnotations}} dictionary whose {{ToolAnnotations/readOnlyHint}} is |tool
583+ definition|'s [=tool definition/annotations=]' s [=annotations/read-only hint=] ,
584+ {{ToolAnnotations/untrustedContentHint}} is |tool definition|'s [=tool
585+ definition/annotations=] 's [=annotations/untrusted content hint=] . and
586+ {{ToolAnnotations/consequentialHint}} is |tool definition|'s [=tool
587+ definition/annotations=] 's [=annotations/consequential hint=] .
588+
589+ 1. [=list/Append=] |registeredTool| to |tools|.
590+
591+ 1. [=list/Sort in ascending order=] |tools|, with |a| being less than |b| if
592+ |a|["{{RegisteredTool/name}}"] is [=code unit less than=] |b|["{{RegisteredTool/name}}"] .
593+
594+ 1. [=Queue a global task=] on the [=webmcp task source=] given |global| to [=resolve=] |promise|
595+ with |tools|.
596+
597+ 1. Return |promise|.
598+
599+ </div>
600+
475601<h4 id="model-context-tool">ModelContextTool Dictionary</h4>
476602
477603The {{ModelContextTool}} dictionary describes a tool that can be invoked by [=agents=] .
@@ -517,7 +643,7 @@ callback ToolExecuteCallback = Promise<any> (object input);
517643
518644 <dt><code><var ignore> tool</var> ["{{ModelContextTool/inputSchema}}"] </code></dt>
519645 <dd>
520- <p> A JSON Schema [[!JSON-SCHEMA]] object describing the expected input parameters for the tool.
646+ <p> A JSON Schema object describing the expected input parameters for the tool [[!JSON-SCHEMA]] .
521647 </dd>
522648
523649 <dt><code><var ignore> tool</var> ["{{ModelContextTool/execute}}"] </code></dt>
@@ -568,6 +694,77 @@ dictionary ModelContextRegisterToolOptions {
568694 :: <p> An array of origins that control which documents this tool is exposed to, in the current document's tree.
569695</dl>
570696
697+ <h4 id="model-context-get-tool-options">ModelContextGetToolOptions Dictionary</h4>
698+
699+ The {{ModelContextGetToolOptions}} dictionary allows web applications to filter the tools returned
700+ by {{ModelContext/getTools()}} .
701+
702+ <xmp class="idl">
703+ dictionary ModelContextGetToolOptions {
704+ sequence<USVString> fromOrigins;
705+ };
706+ </xmp>
707+
708+ <dl class="domintro">
709+ : <code><var ignore> options</var> ["{{ModelContextGetToolOptions/fromOrigins}}"] </code>
710+ :: An array of origins from which to query tools. Documents whose origin appears in this list, or
711+ are same-origin with the caller, have their tools queried. An empty list only includes
712+ same-origin documents.
713+ </dl>
714+
715+ <h4 id="registered-tool">RegisteredTool Dictionary</h4>
716+
717+ The {{RegisteredTool}} dictionary represents a tool that has been registered and is available for
718+ execution.
719+
720+ <xmp class="idl">
721+ dictionary RegisteredTool {
722+ required DOMString name;
723+ // `title` can be exposed as a `DOMString` since it was taken in by a
724+ // `USVString`, meaning all unmatched surrogate processing has already been
725+ // done, and there's no need to do it again on tool exposure.
726+ DOMString title;
727+ required DOMString description;
728+ DOMString inputSchema;
729+ required Window window;
730+ required USVString origin;
731+ ToolAnnotations annotations;
732+ };
733+ </xmp>
734+
735+ <dl class="domintro">
736+ : <code><var ignore> tool</var> ["{{RegisteredTool/name}}"] </code>
737+ :: A unique identifier for the tool. It is the same value provided at tool registration, via
738+ {{ModelContextTool/name}} .
739+
740+ : <code><var ignore> tool</var> ["{{RegisteredTool/title}}"] </code>
741+ :: A human-readable label for the tool. It is the same value provided at tool registration, via
742+ {{ModelContextTool/title}} .
743+
744+ : <code><var ignore> tool</var> ["{{RegisteredTool/description}}"] </code>
745+ :: A natural language description of the tool's functionality. It is the same value provided at
746+ tool registration, via {{ModelContextTool/description}} .
747+
748+ : <code><var ignore> tool</var> ["{{RegisteredTool/inputSchema}}"] </code>
749+ :: A stringified JSON Schema object describing the expected input parameters for the tool
750+ [[!JSON-SCHEMA]] . It is the string derived from {{ModelContextTool/inputSchema}} during
751+ registration.
752+
753+ : <code><var ignore> tool</var> ["{{RegisteredTool/window}}"] </code>
754+ :: The {{Window}} of the document that registered the tool.
755+
756+ : <code><var ignore> tool</var> ["{{RegisteredTool/origin}}"] </code>
757+ :: The origin of the document that registered the tool. This member is only meaningful when the
758+ tool is cross-origin, and the consumer of a tool cannot otherwise get the tool's origin from
759+ its {{RegisteredTool/window}} . For same-origin tools, this is the same as the tool's
760+ {{RegisteredTool/window}} 's {{WindowOrWorkerGlobalScope/origin}}, and the caller' s own
761+ {{Window}} .{{WindowOrWorkerGlobalScope/origin}} .
762+
763+ : <code><var ignore> tool</var> ["{{RegisteredTool/annotations}}"] </code>
764+ :: Optional annotations providing metadata about the tool. It matches
765+ {{ModelContextTool/annotations}} .
766+ </dl>
767+
571768
572769<h3 id="declarative-api">Declarative WebMCP</h3>
573770
0 commit comments