Angular 22

WebMCP Tools Support

Angular 22 introduces experimental WebMCP support, enabling AI agents to invoke tools registered in your Angular app via the WebMCP protocol.

Experimental API โ€” These APIs are prefixed with Experimental and may change in future versions.

1. ToolDescriptor Interface

Every WebMCP tool is defined by a ToolDescriptor with a name, description, a JSON Schema inputSchema, and an execute callback. The Client provides an AbortSignal for cancellation.

nameUnique identifier the agent uses to call this tool
descriptionHelps the agent decide when to use the tool
inputSchemaJSON Schema โ€” TypeScript infers arg types from it
executeCallback that runs in an injection context
client.signalAbortSignal for cancelling long operations
// The ToolDescriptor interface:
interface ToolDescriptor<InputSchema> {
  /** Unique name the agent uses to invoke this tool */
  name: string;

  /** Description helping the agent decide when to use this tool */
  description: string;

  /** JSON Schema defining the expected arguments */
  inputSchema: InputSchema;

  /** The function that runs when the agent calls this tool */
  execute: (
    args: InferArgsFromInputSchema<InputSchema>,
    client: Client
  ) => unknown;
}

// The Client interface:
interface Client {
  /** AbortSignal โ€” cancel long-running operations */
  signal: AbortSignal;
}

2. provideExperimentalWebMcpTools()

Register tools at the application level in app.config.ts. Tools are available for the entire lifetime of the app. The execute callback runs in the application's injection context, so you can use inject().

1Define tools with provideExperimentalWebMcpTools()
2An MCP-compatible agent connects to the app
3Agent discovers and invokes tools via the WebMCP protocol
4Angular runs the execute function and returns the result
// app.config.ts โ€” register tools at the application level
import { provideExperimentalWebMcpTools } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    provideExperimentalWebMcpTools([
      {
        name: 'get_user_profile',
        description: 'Fetches the current user profile data',
        inputSchema: {
          type: 'object',
          properties: {
            includeAvatar: {
              type: 'boolean',
              description: 'Whether to include the avatar URL',
            },
          },
        },
        execute: async (args, client) => {
          const userService = inject(UserService);
          const user = await userService.getCurrentUser();
          return JSON.stringify({
            name: user.name,
            email: user.email,
            avatar: args.includeAvatar ? user.avatarUrl : undefined,
          });
        },
      },
    ]),
  ],
};

3. declareExperimentalWebMcpTool()

Register a tool dynamically inside a component or service. The tool is tied to the injection context โ€” it's automatically unregistered when the component is destroyed. This is ideal for context-specific tools that should only be available while a certain view is active.

Component Createdโ†’Tool registered & available to agents
Component Destroyedโ†’Tool automatically unregistered
// product-list.component.ts โ€” register a tool dynamically
import { declareExperimentalWebMcpTool, inject } from '@angular/core';

@Component({ ... })
export class ProductListComponent {
  private readonly productService = inject(ProductService);
  private readonly cart = inject(CartService);

  constructor() {
    // Tool is registered when component is created,
    // and automatically unregistered when destroyed.
    declareExperimentalWebMcpTool({
      name: 'add_to_cart',
      description: 'Adds a product to the shopping cart by product ID',
      inputSchema: {
        type: 'object',
        properties: {
          productId: {
            type: 'string',
            description: 'The unique product identifier',
          },
          quantity: {
            type: 'number',
            description: 'Number of items to add (default: 1)',
          },
        },
        required: ['productId'],
      },
      execute: async (args, client) => {
        // Runs in the component's injection context
        const product = await this.productService.getById(args.productId);
        if (!product) return 'Product not found';

        // Respect the abort signal for cancellation
        if (client.signal.aborted) return 'Operation cancelled';

        this.cart.add(product, args.quantity ?? 1);
        return `Added ${args.quantity ?? 1}x "${product.name}" to cart`;
      },
    });
  }
}

4. Route-Level Tools

Since provideExperimentalWebMcpTools() returns EnvironmentProviders, you can scope tools to specific routes. The tools are only available when the route is active โ€” perfect for admin panels, dashboards, or feature-specific AI capabilities.

// Register tools for specific routes only
const routes: Routes = [
  {
    path: 'admin',
    loadComponent: () => import('./admin.component'),
    providers: [
      provideExperimentalWebMcpTools([
        {
          name: 'list_users',
          description: 'Lists all registered users (admin only)',
          inputSchema: {
            type: 'object',
            properties: {
              role: { type: 'string', description: 'Filter by role' },
              limit: { type: 'number', description: 'Max results' },
            },
          },
          execute: async (args) => {
            const userService = inject(UserService);
            const users = await userService.list({
              role: args.role,
              limit: args.limit ?? 50,
            });
            return JSON.stringify(users);
          },
        },
      ]),
    ],
  },
];
// Tool is available only when the /admin route is active!

Key Points

  • Experimental โ€” APIs are prefixed with Experimental and may change.
  • Type-safe โ€” TypeScript infers execute argument types from the inputSchema JSON Schema via InferArgsFromInputSchema.
  • Injection context โ€” execute runs in the associated injector's context, so inject() works inside it.
  • Automatic cleanup โ€” declareExperimentalWebMcpTool unregisters the tool when the injection context is destroyed.
  • Cancellation โ€” The Client provides an AbortSignal to cancel long-running operations.
  • Scoped registration โ€” Use at the app level, route level, or component level depending on when the tool should be available.