@@ -314,6 +314,7 @@ The {{ModelContext}} interface provides methods for web applications to register
314314[Exposed=Window, SecureContext]
315315interface ModelContext : EventTarget {
316316 Promise<undefined> registerTool(ModelContextTool tool, optional ModelContextRegisterToolOptions options = {});
317+ Promise<sequence<RegisteredTool> > getTools(optional ModelContextGetToolOptions options = {});
317318
318319 attribute EventHandler ontoolchange;
319320};
@@ -331,6 +332,12 @@ is a [=model context=] [=struct=] created alongside the {{ModelContext}}.
331332 {{ModelContextTool/description}} are empty strings, or if the {{ModelContextTool/inputSchema}}
332333 is invalid.</p>
333334 </dd>
335+
336+ <dt><code><var ignore> document</var> .{{Document/modelContext}} .{{ModelContext/getTools(options)}} </code></dt>
337+ <dd>
338+ <p> Returns a promise that resolves to a list of registered tools from this document and its
339+ descendants that are exposed to this document.</p>
340+ </dd>
334341</dl>
335342
336343
@@ -464,6 +471,112 @@ The <dfn method for=ModelContext>registerTool(<var>tool</var>, <var>options</var
464471
465472</div>
466473
474+ <div algorithm>
475+ The <dfn method for=ModelContext>getTools(<var>options</var>)</dfn> method steps are:
476+
477+ 1. Let |global| be [=this=] 's [=relevant global object=] .
478+
479+ 1. Let |tool owner| be |global|'s [=associated Document|associated <code>Document</code>=] .
480+
481+ 1. If |tool owner| is not [=Document/fully active=] , then return [=a promise rejected with=] an
482+ "{{InvalidStateError}} " {{DOMException}} .
483+
484+ 1. If this's [=surrounding agent=] 's [=agent cluster=]' s [=is origin-keyed=] is false and this's
485+ [=relevant settings object=] 's [=environment settings object/origin=]' s [=origin/scheme=] is not
486+ <code> "file"</code> , then return [=a promise rejected with=] a "{{SecurityError}} "
487+ {{DOMException}} .
488+
489+ 1. If |tool owner| is not [=allowed to use=] the "{{tools}} " feature, then return [=a promise
490+ rejected with=] a "{{NotAllowedError}} " {{DOMException}} .
491+
492+ 1. Let |from origins| be an empty [=list=] of [=origins=] .
493+
494+ 1. If |options|'s {{ModelContextGetToolOptions/fromOrigins}} [=map/exists=] , then:
495+
496+ 1. [=list/For each=] |origin| of |options|'s {{ModelContextGetToolOptions/fromOrigins}} :
497+
498+ 1. Let |parsedURL| be the result of running the [=URL parser=] on |origin|.
499+
500+ 1. If |parsedURL| is failure or its [=url/origin=] is not [$is origin potentially
501+ trustworthy?|potentially trustworthy$], then return [=a promise rejected with=] a
502+ "{{SecurityError}} " {{DOMException}} .
503+
504+ 1. [=list/Append=] |parsedURL|'s [=url/origin=] to |from origins|.
505+
506+ 1. Let |promise| be [=a new promise=] created in [=this=] 's [=relevant realm=] .
507+
508+ 1. Run the following steps [=in parallel=] :
509+
510+ 1. Let |tools| be an empty [=list=] of {{RegisteredTool}} dictionaries.
511+
512+ 1. Let |navigables| be |tool owner|'s [=node navigable=]' s [=navigable/traversable navigable=] 's
513+ [=Document/inclusive descendant navigables=] .
514+
515+ 1. [=list/For each=] |navigable| of |navigables|:
516+
517+ 1. Let |targetDocument| be |navigable|'s [=navigable/active document=] .
518+
519+ 1. If |targetDocument| is not [=allowed to use=] the "{{tools}} " feature, then
520+ [=iteration/continue=] .
521+
522+ 1. Let |targetOrigin| be |targetDocument|'s [=Document/origin=] .
523+
524+ 1. Let |callerOrigin| be |tool owner|'s [=Document/origin=] .
525+
526+ 1. Let |is visible to caller| be true if |targetOrigin| is [=same origin=] with
527+ |callerOrigin|, or if |from origins| [=list/contains=] |targetOrigin|. Otherwise, let it be
528+ false.
529+
530+ 1. If |is visible to caller| is false, then [=iteration/continue=] .
531+
532+ 1. Let |targetToolMap| be |targetDocument|'s [=Document/associated ModelContext|associated
533+ <code>ModelContext</code>=] 's [=ModelContext/internal context=]' s [=model context/tool
534+ map=] .
535+
536+ 1. [=map/For each=] <var ignore> tool name</var> → |tool definition| of |targetToolMap|:
537+
538+ 1. If [=tool is visible to an origin=] given |targetOrigin|, |tool definition|'s [=tool
539+ definition/exposed origins=] , and |callerOrigin| is false, then [=iteration/continue=] .
540+
541+ 1. Let |registeredTool| be a new {{RegisteredTool}} dictionary, with the following fields:
542+
543+ : {{RegisteredTool/name}}
544+ :: |tool definition|'s [=tool definition/name=]
545+
546+ : {{RegisteredTool/title}}
547+ :: |tool definition|'s [=tool definition/title=]
548+
549+ : {{RegisteredTool/description}}
550+ :: |tool definition|'s [=tool definition/description=]
551+
552+ : {{RegisteredTool/inputSchema}}
553+ :: |tool definition|'s [=tool definition/input schema=] if it is not the empty string;
554+ otherwise undefined.
555+
556+ : {{RegisteredTool/window}}
557+ :: |targetDocument|'s [=relevant global object=]
558+
559+ : {{RegisteredTool/origin}}
560+ :: |targetOrigin|, [=serialization of an origin|serialized=] .
561+
562+ : {{RegisteredTool/annotations}}
563+ :: A new {{ToolAnnotations}} dictionary whose {{ToolAnnotations/readOnlyHint}} is |tool
564+ definition|'s [=tool definition/read-only hint=] and
565+ {{ToolAnnotations/untrustedContentHint}} is |tool definition|'s [=tool
566+ definition/untrusted content hint=] .
567+
568+ 1. [=list/Append=] |registeredTool| to |tools|.
569+
570+ 1. [=list/Sort in ascending order=] |tools|, with |a| being less than |b| if
571+ |a|["{{RegisteredTool/name}}"] is [=code unit less than=] |b|["{{RegisteredTool/name}}"] .
572+
573+ 1. [=Queue a global task=] on the [=webmcp task source=] given |global| to [=resolve=] |promise|
574+ with |tools|.
575+
576+ 1. Return |promise|.
577+
578+ </div>
579+
467580<h4 id="model-context-tool">ModelContextTool Dictionary</h4>
468581
469582The {{ModelContextTool}} dictionary describes a tool that can be invoked by [=agents=] .
@@ -508,7 +621,8 @@ callback ToolExecuteCallback = Promise<any> (object input);
508621
509622 <dt><code><var ignore> tool</var> ["{{ModelContextTool/inputSchema}}"] </code></dt>
510623 <dd>
511- <p> A JSON Schema [[!JSON-SCHEMA]] object describing the expected input parameters for the tool.
624+ <p> A stringified JSON Schema object describing the expected input parameters for the tool
625+ [[!JSON-SCHEMA]] .
512626 </dd>
513627
514628 <dt><code><var ignore> tool</var> ["{{ModelContextTool/execute}}"] </code></dt>
@@ -556,6 +670,68 @@ dictionary ModelContextRegisterToolOptions {
556670 :: <p> An array of origins that control which documents this tool is exposed to, in the current document's tree.
557671</dl>
558672
673+ <h4 id="model-context-get-tool-options">ModelContextGetToolOptions Dictionary</h4>
674+
675+ The {{ModelContextGetToolOptions}} dictionary allows web applications to filter the tools returned
676+ by {{ModelContext/getTools()}} .
677+
678+ <xmp class="idl">
679+ dictionary ModelContextGetToolOptions {
680+ sequence<USVString> fromOrigins;
681+ };
682+ </xmp>
683+
684+ <dl class="domintro">
685+ : <code><var ignore> options</var> ["{{ModelContextGetToolOptions/fromOrigins}}"] </code>
686+ :: An array of origins from which to list tools. When this array is empty or omitted, only tools
687+ exposed to documents that are same-origin with the caller of {{ModelContext/getTools()}} are
688+ included in the result.
689+ </dl>
690+
691+ <h4 id="registered-tool">RegisteredTool Dictionary</h4>
692+
693+ The {{RegisteredTool}} dictionary represents a tool that has been registered and is available for
694+ invocation.
695+
696+ <xmp class="idl">
697+ dictionary RegisteredTool {
698+ required DOMString name;
699+ required DOMString description;
700+ DOMString inputSchema;
701+ // `title` can be exposed as a `DOMString` since it was taken in by a
702+ // `USVString`, meaning all unmatched surrogate processing has already been
703+ // done, and there's no need to do it again on tool exposure.
704+ DOMString title;
705+ required Window window;
706+ required USVString origin;
707+ ToolAnnotations annotations;
708+ };
709+ </xmp>
710+
711+ <dl class="domintro">
712+ : <code><var ignore> tool</var> ["{{RegisteredTool/name}}"] </code>
713+ :: A unique identifier for the tool.
714+
715+ : <code><var ignore> tool</var> ["{{RegisteredTool/description}}"] </code>
716+ :: A natural language description of the tool's functionality.
717+
718+ : <code><var ignore> tool</var> ["{{RegisteredTool/inputSchema}}"] </code>
719+ :: A stringified JSON Schema object describing the expected input parameters for the tool
720+ [[!JSON-SCHEMA]] .
721+
722+ : <code><var ignore> tool</var> ["{{RegisteredTool/title}}"] </code>
723+ :: A human-readable label for the tool.
724+
725+ : <code><var ignore> tool</var> ["{{RegisteredTool/window}}"] </code>
726+ :: The {{Window}} of the document that registered the tool.
727+
728+ : <code><var ignore> tool</var> ["{{RegisteredTool/origin}}"] </code>
729+ :: The origin of the document that registered the tool.
730+
731+ : <code><var ignore> tool</var> ["{{RegisteredTool/annotations}}"] </code>
732+ :: Optional annotations providing metadata about the tool.
733+ </dl>
734+
559735
560736<h3 id="declarative-api">Declarative WebMCP</h3>
561737
0 commit comments