---
title: "WebMCP in Angular: How to Expose Tools to the Browser's AI Agent (and When to Wait)"
description: "How Angular exposes WebMCP tools to a browser AI agent (bootstrap, routes, services, and Signal Forms), plus the security surface that opens and where I would still wait before shipping."
deck: "WebMCP lets your Angular app hand typed tools to a browser AI agent instead of letting it click through the DOM. Angular ships experimental support behind `provideExperimentalWebMcpTools`. As of 2026-06-01 the entry point moved from `navigator` to `document.modelContext`, so the live guide sits on [next.angular.dev/ai/webmcp](https://next.angular.dev/ai/webmcp), not stable docs."
author: "André Ramos"
url: "https://andreramos.dev/angular/web-mcp-in-angular/"
lang: "en"
type: "article"
---

# WebMCP in Angular: How to Expose Tools to the Browser's AI Agent (and When to Wait)

> WebMCP lets your Angular app hand typed tools to a browser AI agent instead of letting it click through the DOM. Angular ships experimental support behind `provideExperimentalWebMcpTools`. As of 2026-06-01 the entry point moved from `navigator` to `document.modelContext`, so the live guide sits on [next.angular.dev/ai/webmcp](https://next.angular.dev/ai/webmcp), not stable docs.

## What WebMCP actually changes

An AI agent that automates your app usually drives the UI: it reads the DOM, finds a button, clicks it, fills a field, hopes the layout did not change. WebMCP flips that. The [spec](https://github.com/webmachinelearning/webmcp) describes it as letting developers expose web application functionality, either JavaScript functions or HTML `<form>` elements, as tools with natural language descriptions and structured schemas for an agent to ingest. Your app declares a `findOrder` tool with an input schema; the agent calls it by name and gets structured data back. No selector guessing, no synthetic clicks.

Read the status before you read the API. WebMCP is a [W3C Community Group draft](https://webmachinelearning.github.io/webmcp/) from the Web Machine Learning CG. That is a draft report, not a W3C Standard and not on the Standards Track. The shape can still move under you.

This is a different layer from the [Angular CLI MCP server](/angular/angular-cli-mcp-ai-generated-angular-code/), which feeds project context to an assistant while you write Angular at your desk. That one helps generate code. WebMCP is runtime: your shipped app exposing capabilities to whatever agent the end user is running. The blast radius is the production app, not the editor, which is exactly why the rest of this matters.

## How Angular wires it

There are four places to register a tool, and they map to how long the tool should live. Pick the narrowest scope that covers the capability.

At bootstrap, [`provideExperimentalWebMcpTools`](https://next.angular.dev/api/core/provideExperimentalWebMcpTools) registers tools for the whole app. Each tool carries a `name`, a `description`, an `inputSchema` in JSON Schema, and an `execute` callback that runs inside an injection context, so it can `inject` services directly.

At the route level you pass the same provider in a route's `providers`, and the tool only exists while that route is active. For that to be true you need [`withExperimentalAutoCleanupInjectors`](https://next.angular.dev/ai/webmcp) in `provideRouter`; without it the route's tools stay registered after you navigate away. One honest caveat: this exact recommended setup currently has an open bug. Route providers plus `withExperimentalAutoCleanupInjectors` can throw `InvalidStateError: Duplicate tool name` on repeated navigation back to the route ([issue #68899](https://github.com/angular/angular/issues/68899), open as of 2026-06-02). If you spike the route path, navigate in and out a few times and watch for it.

Inside a service, `declareExperimentalWebMcpTool` registers a tool from within an injection context and auto-unregisters when that context is destroyed. This is the natural home when the tool belongs to a feature service rather than a route.

For forms, `provideExperimentalWebMcpForms` plus an `experimentalWebMcpTool` option on `form()` turns a Signal Form into a tool. Angular infers the JSON schema from the form model's initial values and wires validation and submission, so the agent sees field errors and can self-correct instead of submitting garbage. Three constraints come with that inference: the model needs concrete initial values (`''`, `0`, `false`, never `null` or `undefined`), arrays need at least one element so the item shape is known, and async validators do not run during agent submission. I go deeper on forms-as-tools in [Turning Signal Forms into AI agent tools](/angular/signal-forms-as-ai-agent-tools/).

*Bootstrap: a tool for the whole app*

```ts
import { Service, inject, provideExperimentalWebMcpTools } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app-root';
import { Orders } from './orders';

bootstrapApplication(AppRoot, {
  providers: [
    provideExperimentalWebMcpTools([
      {
        name: 'findOrder',
        description: 'Looks up an order by its number.',
        inputSchema: {
          type: 'object',
          properties: { orderId: { type: 'string' } },
          required: ['orderId'],
        },
        execute: ({ orderId }) => {
          const orders = inject(Orders);
          return { content: [{ type: 'text', text: orders.summary(orderId) }] };
        },
      },
    ]),
  ],
});
```

*Route level: scoped to one route, with cleanup*

```ts
// routes.ts
export const routes: Routes = [{
  path: 'dashboard',
  loadComponent: () => import('./dashboard').then((m) => m.Dashboard),
  providers: [
    provideExperimentalWebMcpTools([{
      name: 'exportDashboardReports',
      description: 'Exports the current dashboard analytics.',
      inputSchema: { type: 'object', properties: {} },
      execute: () => ({ content: [{ type: 'text', text: 'Export triggered.' }] }),
    }]),
  ],
}];

// app.config.ts: without this, route tools stay live after navigation
provideRouter(routes, withExperimentalAutoCleanupInjectors());
```

*Signal Forms: schema inferred from the model*

```ts
// provideExperimentalWebMcpForms() must be in your providers
readonly model = signal({ firstName: '', lastName: '' });

readonly userForm = form(this.model,
  (f) => {
    required(f.firstName, { message: 'First name is mandatory.' });
    required(f.lastName, { message: 'Last name is mandatory.' });
  },
  {
    experimentalWebMcpTool: { name: 'registerUser', description: 'Registers a new user.' },
    submission: { action: async (formValue) => { /* ... */ } },
  },
);
```

## Can you even run this today?

Before you design tools, check what status you are building on. WebMCP support shipped with v22, but it is still an experimental API, which is why its guide lives on `next.angular.dev` and not the stable [angular.dev](https://angular.dev/reference/releases) docs yet.

The entry point also just moved. It used to hang off `navigator`; as of 2026-06-01 it is `document.modelContext`, after [issue #68947](https://github.com/angular/angular/issues/68947) was completed and [PR #68961](https://github.com/angular/angular/pull/68961) merged. Until that has settled across consumers, feature-detect both: `const modelContext = document.modelContext || navigator.modelContext;`.

On the consumer side, be skeptical of demos. WebMCP is a CG draft, and I cannot point you at a shipping browser or agent that consumes `document.modelContext` from a primary source I would cite. So you test the registration without waiting for that: the guide suggests the [`@mcp-b/webmcp-polyfill`](https://next.angular.dev/ai/webmcp) package as a mock for unit tests, which lets you assert that your tools register and that `execute` returns what you expect.

The Angular team is direct about all of this. Their words: "The WebMCP spec is very early in its lifecycle and is undergoing frequent changes. As such, WebMCP support in Angular is currently experimental. APIs are subject to change even outside of major versions." Read that as: a minor bump can rename what you shipped.

## The surface you're exposing

Every tool you register is a new thing an agent can trigger in your app without a human clicking. That sentence is the whole threat model. Treat the tool list the way you treat public API endpoints, because functionally that is what it is.

The current spec registers tools through `document.modelContext.registerTool(tool, { signal, exposedTo })`. The `exposedTo` option scopes which origins may call a tool, and an `AbortSignal` lets you tear a tool down. Default to the narrowest `exposedTo` you can justify, the same instinct you would bring to CORS.

Do not trust the input. The Angular docs are explicit: "Angular does not provide any implicit validation that the inputs provided by an agent actually match the defined JSON schema. Consider explicitly validating arguments to the execute function before using them to ensure reliability." The schema documents the tool; it does not enforce anything. An agent under [prompt injection](https://next.angular.dev/ai/webmcp) can hand your `execute` whatever a malicious page talked it into, so validate arguments at the top of `execute` and bail on anything you did not expect.

Tool names are a namespace, and a duplicate registration throws. That is also the mechanism behind the autocleanup bug above: a stale route tool that never unregistered collides with the fresh one on the next visit.

Where I land: I would refuse to register a tool that mutates real data behind no confirmation, and I would require every `execute` that touches money, identity, or destructive actions to validate its inputs and re-check authorization server-side, exactly as if the call came from an untrusted client. Because it does.

## Where I would spike it, and where I would wait

I would spike WebMCP on an internal tool or a low-stakes route, behind a flag, to learn the shape of tool design and input schemas. That investment survives even if the API renames.

I would wait on anything user-facing in production, anything in a critical or regulated flow, and anything where a mid-cycle breaking change is expensive to chase. With the entry point still moving from `navigator` to `document.modelContext` and the recommended route setup carrying an open duplicate-tool bug, the cost of treating this as stable is real, and it is separate from whether the idea is good. The idea is good. The surface is not settled.

| Scenario | Spike or wait | Why |
|---|---|---|
| Internal admin tool, flagged | Spike | Learn tool and schema design where breakage is cheap. |
| Read-only lookup on a minor route | Spike | Low blast radius, easy to remove if the API moves. |
| Route-scoped tools today | Spike, carefully | Watch for the duplicate-tool race in issue #68899 on repeated navigation. |
| User-facing action in production | Wait | Spec changes outside majors can break shipped flows. |
| Regulated or payment flow | Wait | Exposed tools widen the surface an agent can trigger. |

## Reusable artifact: WebMCP spike gate

- Scope the spike to an internal or low-stakes route, behind a flag.
- Feature-detect the entry point: `document.modelContext || navigator.modelContext`.
- If you scope tools to a route, expect the `withExperimentalAutoCleanupInjectors` duplicate-tool race (issue #68899) and test repeated navigation.
- Set `exposedTo` to the narrowest set of origins the tool needs.
- Validate every `execute` input at runtime; the JSON schema is documentation, not enforcement.
- Write down what each exposed tool lets the agent trigger, and re-check authorization server-side for anything that mutates.
- Re-check status and API names on every Angular minor, not just majors.

## FAQ

### Is WebMCP stable in Angular?

No. Angular's support is experimental and the team warns that APIs "are subject to change even outside of major versions." The underlying spec is a [W3C Community Group draft](https://webmachinelearning.github.io/webmcp/), not a standard.

### navigator.modelContext or document.modelContext?

As of 2026-06-01 the entry point moved to `document.modelContext` ([PR #68961](https://github.com/angular/angular/pull/68961)). Feature-detect both with `const modelContext = document.modelContext || navigator.modelContext;` until the change has settled across consumers.

### How is WebMCP different from the Angular CLI MCP server?

The [Angular CLI MCP server](/angular/angular-cli-mcp-ai-generated-angular-code/) is a development-time tool: it feeds project context to an assistant while you write code. WebMCP is runtime: your shipped app exposes tools to the end user's browser agent. Different layer, much larger surface. I compare the two head-on in [WebMCP vs the Angular CLI MCP server](/angular/webmcp-vs-angular-cli-mcp-server/).

### Do I have to validate agent inputs myself?

Yes. The docs state Angular does "not provide any implicit validation that the inputs provided by an agent actually match the defined JSON schema." Validate arguments at the start of every `execute`, and re-check authorization server-side for anything that mutates data.

### Which Angular version do I need?

WebMCP support shipped with v22, but it is still an experimental API. That is why the guide currently lives on [next.angular.dev/ai/webmcp](https://next.angular.dev/ai/webmcp).

### Can I test WebMCP tools without a browser that supports it?

Yes. The guide suggests the `@mcp-b/webmcp-polyfill` package as a mock for unit tests, so you can assert that tools register and that `execute` returns what you expect.

## Sources checked

- https://next.angular.dev/ai/webmcp
- https://next.angular.dev/api/core/provideExperimentalWebMcpTools
- https://webmachinelearning.github.io/webmcp/
- https://github.com/webmachinelearning/webmcp
- https://angular.dev/ai/mcp
- https://angular.dev/guide/forms/signals/overview
- https://angular.dev/reference/releases
- https://github.com/angular/angular/issues/68899
- https://github.com/angular/angular/issues/68947
- https://github.com/angular/angular/pull/68961

## Related

- [WebMCP vs the Angular CLI MCP Server: Runtime Tools vs Dev-Time Help](https://andreramos.dev/angular/webmcp-vs-angular-cli-mcp-server/)
- [WebMCP Security in Angular: The Agent Calling Your Tools Can Be Hijacked](https://andreramos.dev/angular/web-mcp-security-angular/)
- [Turning Signal Forms into AI Agent Tools](https://andreramos.dev/angular/signal-forms-as-ai-agent-tools/)
