Skip to main content
Version: Latest
Technical ManualLooking for step-by-step instructions? In the User Manual: WebMCP: AI Agents in the Browser

WebMCP

ModuleCrestApps.OrchardCore.AI.WebMcp
FeatureWebMCP (CrestApps.OrchardCore.AI.WebMcp)
CategoryArtificial Intelligence - MCP

WebMCP is a proposed web standard of the W3C Web Machine Learning Community Group. It lets a web page give tools to an AI agent in the browser, such as the browser's own assistant, an agent extension, or a chat on the page. The page registers each tool with document.modelContext.registerTool(): a name, a description, a JSON schema, annotations and a JavaScript execute function. An agent lists the tools with getTools() and runs one with executeTool(). The tool runs in the page with the user's session, so no API key or OAuth setup is needed.

The module is a thin Orchard Core layer over CrestApps.Core's WebMCP (CrestApps.Core.AI.WebMcp and the @crestapps/webmcp scripts), and uses only the standard API. It is one feature, WebMCP, which adds:

PartWhat it does
Site toolsGives the AI tools and tool instances you select on the WebMCP settings card to every page a signed-in user opens (admin pages by default).
Storefront toolsOff by default. Gives visitors who are not signed in the selected tools that are marked safe for anyone, such as searching products and using their own cart.
Content item toolsThe WebMCP tools content part: attach it to a content type, and each content item picks the tools its own page exposes.
Page toolsTools that work on the page itself: page info, links, opening a page, and reading and filling forms. On by default; the Add page tools setting turns them off.
The AI chat as a WebMCP agentWhen AI Chat is enabled, the AI chat discovers and runs every WebMCP tool the page exposes, whoever registered it, for the AI profiles that allow it. It switches on by itself with AI Chat ([RequireFeatures]); there is nothing else to enable.

Using the settings screen and the profile switch is described in the User Manual under WebMCP.

Browser support

WebMCP is experimental. Chrome and Edge are trialling it natively. In the other browsers, the W3C reference polyfill (webmcp-polyfill.js, resource CrestAppsWebMcpPolyfill) installs document.modelContext, so the tools and the AI chat work everywhere. WebMCP needs a secure context: HTTPS, or localhost while developing.

How it compares with the MCP server​

MCP ServerWebMCP
Who calls the toolsA remote MCP clientAn agent in the user's browser
TransportStreamable HTTP at /mcpdocument.modelContext in the page, and two same-origin endpoints
AuthenticationAPI key, OpenID Connect or noneThe signed-in user's cookie, plus the antiforgery token on calls
Tool selectionMCP Server settings cardWebMCP settings card
Per-user tool permissionNoYes: every tool also needs Access AI tool for that user

Both features read the same tool catalog: tools registered with AddCoreAITool<T>() that are selectable (neither system tools nor hidden) and the configured tool instances. WebMCP adds no tools of its own to that catalog.

Site tools​

Who gets the scripts​

A full page (an MVC view or Razor page) gets the WebMCP scripts when all of these are true:

  1. The user is signed in.
  2. The page kind is turned on: admin pages by default, front-end pages only when Offer tools on front-end pages is on.
  3. The user has the Use WebMCP tools in the browser (UseWebMcpTools) permission. Administrators have it by default.

Everyone else gets nothing, unless storefront tools are on.

The page then gets, in order: the polyfill, CrestApps.Core's webmcp.js (resource CrestAppsWebMcp), the page tools (unless Add page tools is off), and the scripts other modules add. webmcp.js lists the tools the user may call and registers each with document.modelContext.registerTool(). A tool is listed when it is selectable, the settings allow it (by Expose all tools or the selection), and the user has Access AI tool for it. The server checks the same rules again on every call.

Endpoints​

The module maps CrestApps.Core's endpoints with MapWebMcpTools(), and replaces Core's access check with one that needs UseWebMcpTools (PermissionWebMcpAccessEvaluator).

Method and routeWhat it doesAnswers
GET /api/ai/webmcp/toolsLists the tools the user may call: { "tools": [{ "name", "title", "description", "inputSchema" }] }401 when not signed in, 403 without UseWebMcpTools
POST /api/ai/webmcp/tools/{name}/invokeCalls a tool with the JSON object in the body as its arguments, inside an AI invocation scope, and answers an MCP-style result: { "content": [{ "type": "text", "text" }], "isError" }401, 403, 400 without a valid antiforgery token in the RequestVerificationToken header or when the body is not a JSON object or is larger than 256 KB, 404 when the tool is not listed for the user

A tool that throws answers isError: true with a generic message. The exception goes to the site log only. A tool that is not listed for the user answers 404 whatever the reason, so the endpoint does not tell which tools exist.

Registering your own tools​

A theme or module registers its own tools with the standard API. Nothing CrestApps-specific is needed, and the AI chat finds them like any other tool:

const registration = new AbortController();

document.modelContext.registerTool({
name: 'contoso.find_store',
title: 'Find a store',
description: 'Finds the Contoso store nearest to a postal code.',
inputSchema: {
type: 'object',
properties: { postalCode: { type: 'string' } },
required: ['postalCode'],
},
annotations: { readOnlyHint: true },
execute: async ({ postalCode }) => findStore(postalCode),
}, { signal: registration.signal });

Make the resource that registers the tool depend on CrestAppsWebMcpPolyfill, so document.modelContext exists when it runs. A tool answers a JSON value and reports a failure by throwing. Use the readOnlyHint, consequentialHint and untrustedContentHint annotations to tell agents what the tool does.

Adding scripts and settings to the page​

Implement IWebMcpClientConfigurationHandler to add a script resource or a setting to every page that gets the WebMCP scripts. The handler runs after the user and the page have qualified:

internal sealed class ContosoWebMcpHandler : IWebMcpClientConfigurationHandler
{
public Task ConfigureAsync(WebMcpClientConfigurationContext context)
{
context.AddScript("ContosoWebMcpTools");
context.Settings["storesUrl"] = $"{context.HttpContext.Request.PathBase}/stores";

return Task.CompletedTask;
}
}

services.AddScoped<IWebMcpClientConfigurationHandler, ContosoWebMcpHandler>();

Scripts load after webmcp.js, in the order they were added. Settings are written to the <script type="application/json" id="crestapps-webmcp-config"> block in the page head, and scripts read them from window.crestAppsWebMcp.config. The serializer escapes HTML characters, so a setting cannot close the block.

Configuration​

The CrestApps:AI:WebMcp shell configuration section overrides the stored settings. Keys:

KeyWhat it does
ExposeAllTools, ToolsThe tools given to browser agents (tool and tool instance names).
EnableOnAdminPages, EnableOnFrontEndPagesThe page kinds that get the scripts.
EnablePageToolsWhether those pages also get the page tools. On by default.
EnableStorefrontToolsWhether front-end pages give everyone else the storefront tools. Off by default.
PageToolOriginsThe origins of cross-origin frames whose shared tools the AI chat may use. Empty by default. See Frames on other origins.
{
"OrchardCore": {
"CrestApps": {
"AI": {
"WebMcp": {
"EnableOnFrontEndPages": false,
"Tools": [ "listTimeZones" ]
}
}
}
}
}
OrchardCore__CrestApps__AI__WebMcp__EnableOnFrontEndPages=false
OrchardCore__CrestApps__AI__WebMcp__Tools__0=listTimeZones

Saving the WebMCP settings card releases the tenant, so the new selection takes effect on the next request. While Expose all tools is checked, the card hides the tool lists, because they are ignored.

Storefront tools​

A shop's visitors usually aren't signed in. Offer storefront tools to visitors (EnableStorefrontTools, off by default) gives their browser agents a small set of tools on the site's front-end pages. It gives them only the tools that are both:

  • marked safe for anyone by the module that registers them, and
  • selected on the WebMCP card (or offered by Expose all tools).

Tool instances, unmarked tools and the page tools are never given. Admin pages never get storefront tools.

Who gets them: visitors who are not signed in, and signed-in users who don't get the site tools (no UseWebMcpTools permission, or front-end pages off). The page gets the polyfill and webmcp.js, pointed at the storefront endpoints, and no other scripts.

Method and routeWhat it doesAnswers
GET /api/ai/webmcp/storefront/toolsLists the storefront tools.404 while the setting is off
POST /api/ai/webmcp/storefront/tools/{name}/invokeCalls one, with the antiforgery token.404 while the setting is off or when the tool isn't a storefront tool, 400 as for the site tools

The server checks the setting, the mark and the selection on every list and every call, so a direct call can't reach any other tool. Tools run as the caller: a guest, or the signed-in user. There is no per-tool permission check, because a marked tool is one anyone may run.

When Orchard Core's Rate Limits feature is on, each visitor (by IP address) may call the storefront endpoints 60 times a minute (WebMcpConstants.StorefrontRequestsPerMinute, rate-limit group webmcp-storefront). Turn it on for public sites.

Pages with storefront tools carry an antiforgery token, so browsers and proxies don't cache them.

Marking a tool safe for anyone​

Mark a tool when you register it, with MarkAIToolAnonymousSafe from CrestApps.OrchardCore.AI.Core.Extensions:

services.AddCoreAITool<SearchStoreProductsTool>(SearchStoreProductsTool.ToolName)
.WithTitle(S["Search store products"])
.Selectable();

services.MarkAIToolAnonymousSafe(SearchStoreProductsTool.ToolName);

The marks are kept in AnonymousAIToolOptions (CrestApps.OrchardCore.AI.Core.Models). Mark a tool only when anyone may run it: it reads public data or acts on the caller's own data (such as their own cart), never shows another person's data, and never pays, deletes or changes the site. The store's commerce tools are marked.

Content item tools​

WebMCP lets each page expose its own tools, not only the tools every page gets. The WebMCP tools content part (WebMcpPart) does that for content items. It is available when Orchard Core's Contents feature is enabled.

  1. Attach WebMCP tools to a content type (Content Definition → Content Types → Edit → Add Parts).
  2. When creating or editing a content item of that type, pick the tools its page exposes. The list shows only the selectable tools and tool instances the editor may use (Access AI tool); tools another editor picked that the current editor may not use stay selected.
  3. On the content item's page (its Detail display), signed-in users with Use WebMCP tools in the browser get those tools, registered with document.modelContext.registerTool() like the site tools. Each call goes to the item's own endpoints:
Method and routeWhat it does
GET /api/ai/webmcp/content-items/{contentItemId}/toolsLists the item's tools the user may call.
POST /api/ai/webmcp/content-items/{contentItemId}/tools/{name}/invokeCalls one of them, with the antiforgery token.

On every list and call, the server checks: the user is signed in and has Use WebMCP tools in the browser; the published content item has the part with that tool selected; the user may view the content item; and the user has Access AI tool for the tool. Anything else answers 404, except 401 when not signed in and 403 without the WebMCP permission.

The item's tools are added even when front-end pages are off on the settings card, because the editor chose them for that page. The site tools and page tools still follow the settings. The scripts are added through the resource manager, so they reach the page whatever zones the theme's template renders. The AI chat sees the item's tools among the page's tools, so on that page a profile with Allow page tools can run them; each run goes through the item's endpoint with the same checks.

Page tools​

When Add page tools is on (the default), the pages that get the WebMCP scripts also get CrestApps.Core's webmcp-page-tools.js (resource CrestAppsWebMcpPageTools). It registers these tools with document.modelContext, so any WebMCP agent can use them:

ToolRead-onlyWhat it does
page_get_infoYesThe page's title, address, description, first 20 h1 and h2 headings, and whether it is an admin page.
page_read_contentYesWhat the page shows in main (or [role="main"], else the body): its text, one line per block and cut to 8,000 characters, and up to 10 tables as caption, headers and the first 50 rows, such as the records an admin list shows. Menus, forms, scripts, hidden parts, the chat and anything marked data-webmcp-ignore are left out.
page_list_linksYesUp to 200 same-origin links in nav, header, aside and [role="navigation"], with their text. An optional filter keeps the links whose text contains it.
page_navigateNoOpens a page of this site: a path that starts with /, or a full address on the site. It first asks the site with a HEAD request whether the page exists, and refuses a bare relative path (usually a guess), a page that answers 404 or 410, other origins and script addresses with a message that tells the agent to call page_list_links. It answers before it opens the page, so in the AI chat the agent continues on the page it opened; see Runs that continue on the next page.
page_list_form_fieldsYesUp to 200 fields of the page's forms: name, id, label, type, value (cut to 2,000 characters), required and, for lists, the choices. Hidden, password, file, button and disabled fields and the antiforgery token are left out.
page_set_form_fieldNoPuts a value into one listed field, found by name, id or label, and raises input and change. For a list, the value is a choice's value or text. It never submits the form.

The AI chat as a WebMCP agent​

When the AI Chat feature is enabled, the module makes the AI chat a WebMCP agent for the tab the user has open. It uses every tool document.modelContext.getTools() lists, not only the CrestApps ones. It runs through the AI chat's own SignalR hub, so it opens no extra connection:

  1. Before it sends a message, the chat (ai-chat.js) reads the page's tools and sends them to the hub with SetPageTools, when they changed since the last message. It leaves out the site's AI tools, because the chat reaches those on the server. A tool registered after the page loaded is picked up with the next message.
  2. The hub checks each tool: at most 64 tools, WebMCP names (^[A-Za-z0-9_.-]{1,128}$), a description of at most 2,000 characters and a JSON object schema of at most 16 KB, and keeps them for the connection.
  3. When the chat session's profile has Allow page tools on, the tools are offered to the model.
  4. When the model calls one, the hub asks the tab to run it with SignalR client results (ExecutePageTool). The tab runs it with executeTool() and answers the result, up to ToolCallTimeout.

The connection and the completion of a message it sends are always on the same server, so this needs no sticky sessions or shared store in a web farm.

Profiles​

The AI profile editor has two options, stored as CrestApps.Core's WebMcpProfileSettings:

OptionWhat it does
Allow page tools (AllowPageTools)Offers the page's WebMCP tools to the model. Off by default.
Allow consequential page tools (AllowConsequentialPageTools)The tools the page marks with consequentialHint, such as placing an order, ask the user to Allow or Deny each call in the chat UI and the admin widget (see Tool approvals). With this option on they run without asking. Needs Allow page tools. Off by default.

Tool names and annotations​

WebMCP names may contain ., which AI providers do not accept in function names, so the model sees each tool under a function name: store.add_to_cart is offered as store_add_to_cart, and the tab still runs store.add_to_cart. Results of tools marked untrustedContentHint reach the model after a notice to treat them as data, not as instructions.

Frames on other origins​

A frame on another origin can share its tools with the page by registering them with exposedTo, and the page must allow it with the tools permissions policy: <iframe src="https://partner.example" allow="tools">. List the frame's origin under PageToolOrigins for the AI chat to use those tools.

Configuration​

KeyDefaultWhat it does
CrestApps:AI:WebMcp:Chat:ToolCallTimeout00:01:00How long the chat waits for the browser to answer a page tool call.
{
"OrchardCore": {
"CrestApps": {
"AI": {
"WebMcp": {
"Chat": {
"ToolCallTimeout": "00:00:30"
}
}
}
}
}
}
OrchardCore__CrestApps__AI__WebMcp__Chat__ToolCallTimeout=00:00:30

Recipes​

The WebMCP settings are a site settings section, so the Settings step sets them:

{
"steps": [
{
"name": "Settings",
"WebMcpSettings": {
"EnableOnAdminPages": true,
"EnableOnFrontEndPages": false,
"EnablePageTools": true,
"EnableStorefrontTools": false,
"ExposeAllTools": false,
"Tools": [ "listAIProfiles" ]
}
}
]
}

Attach the WebMCP tools part to a content type with the ContentDefinition step, and set an item's tools in the Content step under WebMcpPart.Tools:

{
"steps": [
{
"name": "ContentDefinition",
"ContentTypes": [
{
"Name": "Product",
"ContentTypePartDefinitionRecords": [
{ "PartName": "WebMcpPart", "Name": "WebMcpPart", "Settings": {} }
]
}
]
},
{
"name": "Content",
"data": [
{
"ContentItemId": "4product0000000000000000001",
"ContentType": "Product",
"Published": true,
"Latest": true,
"WebMcpPart": { "Tools": [ "checkStock" ] }
}
]
}
]
}

The step adds the part to the type. The tools a recipe sets are not limited to what an editor may use: the server still checks Access AI tool for the user on every call.

Set the profile options in the AIProfile step, under the profile's Settings:

{
"steps": [
{
"name": "AIProfile",
"Profiles": [
{
"Name": "admin-assistant",
"Settings": {
"WebMcpProfileSettings": {
"AllowPageTools": true,
"AllowConsequentialPageTools": false
}
}
}
]
}
]
}

Security​

  • Nothing is given by default. You select the tools, and front-end pages and storefront tools are off.
  • Anonymous visitors only ever reach tools marked safe for anyone that you also selected, and only while storefront tools are on.
  • The server checks the user, UseWebMcpTools, the selection and Access AI tool on every list and every call. The script's list only decides what is registered in the browser.
  • Calls need the antiforgery token, so another site cannot make the user's browser call a tool.
  • A browser agent acts as the signed-in user. Give agents only the tools you would let the user run, and prefer read-only tools.
  • Page tools never submit forms and never leave the site, so the user reviews and saves what an agent changes.
  • A profile with Allow page tools lets the model run any tool the page exposes, including a third-party script's. Allow it only on profiles used on pages whose scripts you trust. Tools marked consequentialHint ask the user before each call unless the second option is on, and results marked untrustedContentHint reach the model as data.
  • Page tools only reach the completions of messages sent from the same chat connection.