@@ -322,6 +322,7 @@ The {{ModelContext}} interface provides methods for web applications to register
322322[Exposed=Window, SecureContext]
323323interface ModelContext : EventTarget {
324324 Promise<undefined> registerTool(ModelContextTool tool, optional ModelContextRegisterToolOptions options = {});
325+ Promise<sequence<RegisteredTool> > getTools(optional ModelContextGetToolOptions options = {});
325326
326327 attribute EventHandler ontoolchange;
327328};
@@ -339,6 +340,14 @@ is a [=model context=] [=struct=] created alongside the {{ModelContext}}.
339340 {{ModelContextTool/description}} are empty strings, or if the {{ModelContextTool/inputSchema}}
340341 is invalid.</p>
341342 </dd>
343+
344+ <dt><code><var ignore> document</var> .{{Document/modelContext}} .{{ModelContext/getTools(options)}} </code></dt>
345+ <dd>
346+ <p> Returns a promise that resolves to a list of registered tools from this document and its
347+ descendants that are exposed to this document. This API is designed for so-called "in-page"
348+ agents written in JavaScript, and possibly living in <{iframe}> s. The [=user agent=] 's [=browser
349+ agent=] uses a different internal mechanism to retrieve the tools exposed to it.</p>
350+ </dd>
342351</dl>
343352
344353
@@ -470,6 +479,117 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
470479
471480</div>
472481
482+ <div algorithm>
483+ The <dfn method for=ModelContext>getTools(<var>options</var>)</dfn> method steps are:
484+
485+ 1. Let |global| be [=this=] 's [=relevant global object=] .
486+
487+ 1. Let |toolRequestor| be |global|'s [=associated Document|associated <code>Document</code>=] .
488+
489+ 1. If |toolRequestor| is not [=Document/fully active=] , then return [=a promise rejected with=] an
490+ "{{InvalidStateError}} " {{DOMException}} .
491+
492+ 1. If this's [=surrounding agent=] 's [=agent cluster=]' s [=is origin-keyed=] is false and this's
493+ [=relevant settings object=] 's [=environment settings object/origin=]' s [=origin/scheme=] is not
494+ <code> "file"</code> , then return [=a promise rejected with=] a "{{SecurityError}} "
495+ {{DOMException}} .
496+
497+ 1. If |toolRequestor| is not [=allowed to use=] the "{{tools}} " feature, then return [=a promise
498+ rejected with=] a "{{NotAllowedError}} " {{DOMException}} .
499+
500+ 1. Let |from origins| be an empty [=list=] of [=origins=] .
501+
502+ 1. If |options|'s {{ModelContextGetToolOptions/fromOrigins}} [=map/exists=] , then:
503+
504+ 1. [=list/For each=] |origin| of |options|'s {{ModelContextGetToolOptions/fromOrigins}} :
505+
506+ 1. Let |parsedURL| be the result of running the [=URL parser=] on |origin|.
507+
508+ 1. If |parsedURL| is failure or its [=url/origin=] is not [$is origin potentially
509+ trustworthy?|potentially trustworthy$], then return [=a promise rejected with=] a
510+ "{{SecurityError}} " {{DOMException}} .
511+
512+ 1. [=list/Append=] |parsedURL|'s [=url/origin=] to |from origins|.
513+
514+ 1. Let |promise| be [=a new promise=] created in [=this=] 's [=relevant realm=] .
515+
516+ 1. Run the following steps [=in parallel=] :
517+
518+ 1. Let |tools| be an empty [=list=] of {{RegisteredTool}} dictionaries.
519+
520+ 1. Let |navigables| be |toolRequestor|'s [=node navigable=]' s [=navigable/traversable
521+ navigable=] 's [=Document/inclusive descendant navigables=] .
522+
523+ 1. [=list/For each=] |navigable| of |navigables|:
524+
525+ 1. Let |targetDocument| be |navigable|'s [=navigable/active document=] .
526+
527+ 1. If |targetDocument| is not [=allowed to use=] the "{{tools}} " feature, then
528+ [=iteration/continue=] .
529+
530+ 1. Let |targetOrigin| be |targetDocument|'s [=Document/origin=] .
531+
532+ 1. Let |callerOrigin| be |toolRequestor|'s [=Document/origin=] .
533+
534+ 1. If |toolOwnerIsRequested| be true if |targetOrigin| is [=same origin=] with |callerOrigin|,
535+ or if |from origins| [=list/contains=] |targetOrigin|; otherwise, false.
536+
537+ 1. If |toolOwnerIsRequested| is false, then [=iteration/continue=] .
538+
539+ 1. Let |targetToolMap| be |targetDocument|'s [=Document/associated ModelContext|associated
540+ <code>ModelContext</code>=] 's [=ModelContext/internal context=]' s [=model context/tool
541+ map=] .
542+
543+ 1. [=map/For each=] <var ignore> tool name</var> → |tool definition| of |targetToolMap|:
544+
545+ 1. If [=tool is exposed to an origin=] given |targetOrigin|, |tool definition|'s [=tool
546+ definition/exposed origins=] , and |callerOrigin| returns false, then
547+ [=iteration/continue=] .
548+
549+ 1. Let |registeredTool| be a new {{RegisteredTool}} dictionary, with the following fields:
550+
551+ : {{RegisteredTool/name}}
552+ :: |tool definition|'s [=tool definition/name=]
553+
554+ : {{RegisteredTool/title}}
555+ :: |tool definition|'s [=tool definition/title=] if it is non-null; otherwise the empty
556+ string.
557+
558+ Issue(#224): Consider not defaulting to the empty string, and just excluding this
559+ member, which will result in {{undefined}} .
560+
561+ : {{RegisteredTool/description}}
562+ :: |tool definition|'s [=tool definition/description=]
563+
564+ : {{RegisteredTool/inputSchema}}
565+ :: |tool definition|'s [=tool definition/input schema=] if it is not the empty string;
566+ otherwise undefined.
567+
568+ : {{RegisteredTool/window}}
569+ :: |targetDocument|'s [=relevant global object=]
570+
571+ : {{RegisteredTool/origin}}
572+ :: |targetOrigin|, [=serialization of an origin|serialized=] .
573+
574+ : {{RegisteredTool/annotations}}
575+ :: if |tool definition|'s [=tool definition/annotations=] is not null, a
576+ {{ToolAnnotations}} dictionary whose {{ToolAnnotations/readOnlyHint}} is |tool
577+ definition|'s [=tool definition/annotations=]' s [=annotations/read-only hint=] and
578+ {{ToolAnnotations/untrustedContentHint}} is |tool definition|'s [=tool
579+ definition/annotations=] 's [=annotations/untrusted content hint=] .
580+
581+ 1. [=list/Append=] |registeredTool| to |tools|.
582+
583+ 1. [=list/Sort in ascending order=] |tools|, with |a| being less than |b| if
584+ |a|["{{RegisteredTool/name}}"] is [=code unit less than=] |b|["{{RegisteredTool/name}}"] .
585+
586+ 1. [=Queue a global task=] on the [=webmcp task source=] given |global| to [=resolve=] |promise|
587+ with |tools|.
588+
589+ 1. Return |promise|.
590+
591+ </div>
592+
473593<h4 id="model-context-tool">ModelContextTool Dictionary</h4>
474594
475595The {{ModelContextTool}} dictionary describes a tool that can be invoked by [=agents=] .
@@ -514,7 +634,7 @@ callback ToolExecuteCallback = Promise<any> (object input);
514634
515635 <dt><code><var ignore> tool</var> ["{{ModelContextTool/inputSchema}}"] </code></dt>
516636 <dd>
517- <p> A JSON Schema [[!JSON-SCHEMA]] object describing the expected input parameters for the tool.
637+ <p> A JSON Schema object describing the expected input parameters for the tool [[!JSON-SCHEMA]] .
518638 </dd>
519639
520640 <dt><code><var ignore> tool</var> ["{{ModelContextTool/execute}}"] </code></dt>
@@ -562,6 +682,77 @@ dictionary ModelContextRegisterToolOptions {
562682 :: <p> An array of origins that control which documents this tool is exposed to, in the current document's tree.
563683</dl>
564684
685+ <h4 id="model-context-get-tool-options">ModelContextGetToolOptions Dictionary</h4>
686+
687+ The {{ModelContextGetToolOptions}} dictionary allows web applications to filter the tools returned
688+ by {{ModelContext/getTools()}} .
689+
690+ <xmp class="idl">
691+ dictionary ModelContextGetToolOptions {
692+ sequence<USVString> fromOrigins;
693+ };
694+ </xmp>
695+
696+ <dl class="domintro">
697+ : <code><var ignore> options</var> ["{{ModelContextGetToolOptions/fromOrigins}}"] </code>
698+ :: An array of origins from which to query tools. Documents whose origin appears in this list, or
699+ are same-origin with the caller, have their tools queried. An empty list only includes
700+ same-origin documents.
701+ </dl>
702+
703+ <h4 id="registered-tool">RegisteredTool Dictionary</h4>
704+
705+ The {{RegisteredTool}} dictionary represents a tool that has been registered and is available for
706+ execution.
707+
708+ <xmp class="idl">
709+ dictionary RegisteredTool {
710+ required DOMString name;
711+ // `title` can be exposed as a `DOMString` since it was taken in by a
712+ // `USVString`, meaning all unmatched surrogate processing has already been
713+ // done, and there's no need to do it again on tool exposure.
714+ DOMString title;
715+ required DOMString description;
716+ DOMString inputSchema;
717+ required Window window;
718+ required USVString origin;
719+ ToolAnnotations annotations;
720+ };
721+ </xmp>
722+
723+ <dl class="domintro">
724+ : <code><var ignore> tool</var> ["{{RegisteredTool/name}}"] </code>
725+ :: A unique identifier for the tool. It is the same value provided at tool registration, via
726+ {{ModelContextTool/name}} .
727+
728+ : <code><var ignore> tool</var> ["{{RegisteredTool/title}}"] </code>
729+ :: A human-readable label for the tool. It is the same value provided at tool registration, via
730+ {{ModelContextTool/title}} .
731+
732+ : <code><var ignore> tool</var> ["{{RegisteredTool/description}}"] </code>
733+ :: A natural language description of the tool's functionality. It is the same value provided at
734+ tool registration, via {{ModelContextTool/description}} .
735+
736+ : <code><var ignore> tool</var> ["{{RegisteredTool/inputSchema}}"] </code>
737+ :: A stringified JSON Schema object describing the expected input parameters for the tool
738+ [[!JSON-SCHEMA]] . It is the string derived from {{ModelContextTool/inputSchema}} during
739+ registration.
740+
741+ : <code><var ignore> tool</var> ["{{RegisteredTool/window}}"] </code>
742+ :: The {{Window}} of the document that registered the tool.
743+
744+ : <code><var ignore> tool</var> ["{{RegisteredTool/origin}}"] </code>
745+ :: The origin of the document that registered the tool. This member is only meaningful when the
746+ tool is cross-origin, and the consumer of a tool cannot otherwise get the tool's origin from
747+ its {{RegisteredTool/window}} . For same-origin tools, this is the same as the tool's
748+ {{RegisteredTool/window}} 's {{WindowOrWorkerGlobalScope/origin}}, and the caller' s own
749+ {{Window}} .{{WindowOrWorkerGlobalScope/origin}} .
750+
751+ : <code><var ignore> tool</var> ["{{RegisteredTool/annotations}}"] </code>
752+ :: Optional annotations providing metadata about the tool. It matches
753+ {{ModelContextTool/annotations}} .
754+ </dl>
755+
565756
566757<h3 id="declarative-api">Declarative WebMCP</h3>
567758
0 commit comments