Appearance
WebMCP dans Angular 22 : préparer vos applications aux agents IA
Angular 22 introduit un support expérimental de WebMCP. L'idée est simple à formuler, mais importante : au lieu de laisser un agent IA deviner quoi faire en lisant le DOM, une application peut lui exposer des actions structurées, décrites et typées.
Imaginez une application de gestion de commandes. Sans WebMCP, un agent doit lire l'écran, trouver le bon bouton, remplir les bons champs, puis espérer que l'interface n'a pas changé. Avec WebMCP, l'application peut déclarer un outil comme searchOrders ou createCustomer. L'agent n'a plus seulement une page à observer : il dispose d'une capacité explicite que l'application accepte de rendre disponible.

Fonctionnalité expérimentale
WebMCP est encore une proposition de standard jeune, et Angular marque volontairement ses APIs avec le préfixe Experimental. Les noms, les options et le comportement peuvent changer, même hors version majeure.
C'est quoi WebMCP ?
WebMCP, pour Web Model Context Protocol, propose une API JavaScript permettant à une page web d'exposer des "tools" à des agents IA ou à des technologies d'assistance. On peut voir cela comme une version côté navigateur de ce que MCP apporte déjà côté serveur : une liste de capacités que l'agent peut découvrir et invoquer.
La différence avec une API backend classique est importante. Le tool vit dans la page, avec le contexte de l'utilisateur connecté, l'état courant de l'interface, les services front-end déjà chargés et les règles métier déjà présentes côté client.
Concrètement, un tool WebMCP contient généralement :
- un nom unique ;
- une description compréhensible par l'agent ;
- un schéma d'entrée, souvent en JSON Schema ;
- une fonction
executeappelée quand l'agent invoque le tool.
Le but n'est pas de remplacer vos écrans. Le but est d'offrir aux agents un chemin plus fiable que "cliquer au bon endroit" quand l'application connaît déjà l'action métier à effectuer.
Ce qu'Angular ajoute
Angular ne définit pas WebMCP à lui seul. Le framework ajoute une couche d'intégration avec ses mécanismes existants :
- l'injection de dépendances ;
- le cycle de vie des injecteurs ;
- les providers d'application ou de route ;
- les Signal Forms.
C'est là que l'intégration devient intéressante. Un tool peut être enregistré quand l'application démarre, quand une route est active, ou depuis un service. Quand le contexte Angular associé est détruit, Angular peut aussi désenregistrer le tool.
Déclarer un tool au niveau de l'application
L'API principale documentée est provideExperimentalWebMcpTools. Elle s'utilise dans les providers de l'application.
ts
import { inject, provideExperimentalWebMcpTools } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { CatalogService } from './catalog.service';
bootstrapApplication(AppComponent, {
providers: [
provideExperimentalWebMcpTools([
{
name: 'searchCatalog',
description: 'Recherche des produits dans le catalogue.',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Texte recherché par l'utilisateur.',
},
maxResults: {
type: 'number',
description: 'Nombre maximal de résultats à retourner.',
},
},
required: ['query'],
additionalProperties: false,
},
execute: async ({ query, maxResults }) => {
if (typeof query !== 'string') {
throw new Error('Le paramètre query doit être une chaîne.');
}
if (maxResults !== undefined && typeof maxResults !== 'number') {
throw new Error('Le paramètre maxResults doit être un nombre.');
}
const catalog = inject(CatalogService);
const products = await catalog.search(query, maxResults ?? 5);
return {
content: [
{
type: 'text',
text: JSON.stringify(products),
},
],
};
},
},
]),
],
});Deux points méritent attention.
D'abord, execute est appelée dans le contexte d'injection de l'injecteur associé. Vous pouvez donc utiliser inject() pour appeler un service Angular au moment où le tool s'exécute.
Ensuite, le schéma sert à décrire l'entrée attendue, mais il ne faut pas le confondre avec une validation de sécurité automatique. La documentation Angular recommande de valider explicitement les paramètres reçus dans execute.
Limiter un tool à une route
Tous les tools ne devraient pas être disponibles partout. Un tool d'export de tableau de bord n'a pas forcément de sens sur une page de profil.
Angular permet donc de déclarer des tools dans les providers d'une route :
ts
import { provideExperimentalWebMcpTools } from '@angular/core';
import { provideRouter, withExperimentalAutoCleanupInjectors } from '@angular/router';
export const appConfig = {
providers: [
provideRouter(
[
{
path: 'dashboard',
loadComponent: () =>
import('./dashboard.component').then((m) => m.DashboardComponent),
providers: [
provideExperimentalWebMcpTools([
{
name: 'exportDashboard',
description: 'Exporte les indicateurs visibles du tableau de bord.',
inputSchema: { type: 'object', properties: {} },
execute: () => ({
content: [
{
type: 'text',
text: 'Export du tableau de bord déclenché.',
},
],
}),
},
]),
],
},
],
withExperimentalAutoCleanupInjectors(),
),
],
};Le détail important est withExperimentalAutoCleanupInjectors(). Sans cette option, les tools déclarés sur une route peuvent rester accessibles après navigation. Dans une application réelle, ce serait une mauvaise surprise : l'agent pourrait voir une capacité qui n'a plus de rapport avec l'écran courant.
Déclarer un tool depuis un service
Pour les cas plus dynamiques, Angular documente aussi declareExperimentalWebMcpTool. Cette fonction déclare un tool depuis un contexte d'injection.
ts
import { Injectable, declareExperimentalWebMcpTool, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class CounterService {
readonly count = signal(0);
constructor() {
declareExperimentalWebMcpTool({
name: 'incrementCounter',
description: 'Incrémente le compteur global.',
inputSchema: {
type: 'object',
properties: {
amount: {
type: 'number',
description: 'Valeur à ajouter au compteur.',
},
},
required: ['amount'],
additionalProperties: false,
},
execute: ({ amount }) => {
if (typeof amount !== 'number') {
throw new Error('Le paramètre amount doit être un nombre.');
}
this.count.update((value) => value + amount);
return {
content: [
{
type: 'text',
text: `Le compteur vaut maintenant ${this.count()}.`,
},
],
};
},
});
}
}Ce style est pratique quand le tool est naturellement lié à un service racine. Il faut en revanche éviter de déclarer le même tool plusieurs fois. WebMCP impose des noms uniques : un composant affiché plusieurs fois qui déclarerait le même tool provoquerait des collisions.
Signal Forms : transformer un formulaire en tool
L'autre piste intéressante concerne les Signal Forms. Angular 22 prévoit provideExperimentalWebMcpForms, qui permet d'activer l'intégration WebMCP côté formulaires.
ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideExperimentalWebMcpForms } from '@angular/forms/signals';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent, {
providers: [provideExperimentalWebMcpForms()],
});Ensuite, un Signal Form peut opter pour experimentalWebMcpTool :
ts
import { Component, signal } from '@angular/core';
import { form, required } from '@angular/forms/signals';
@Component({
selector: 'app-register-user',
template: `
<form>
<!-- Champs liés au Signal Form -->
</form>
`,
})
export class RegisterUserComponent {
private readonly model = signal({
firstName: '',
lastName: '',
age: 0,
});
readonly userForm = form(
this.model,
(path) => {
required(path.firstName, { message: 'Le prénom est obligatoire.' });
required(path.lastName, { message: 'Le nom est obligatoire.' });
},
{
experimentalWebMcpTool: {
name: 'registerUser',
description: 'Inscrit un nouvel utilisateur.',
},
submission: {
action: async (value) => {
console.log('Utilisateur à inscrire', value);
},
},
},
);
}Angular peut alors inférer un schéma d'entrée à partir du modèle initial du formulaire. Les validateurs synchrones comme required peuvent enrichir ce schéma, et l'action de soumission devient le point d'entrée appelé quand l'agent utilise le tool.
Cette approche montre bien la direction prise par Angular : utiliser la connaissance que le framework possède déjà sur vos formulaires pour exposer des outils plus riches, sans vous obliger à réécrire tout le JSON Schema à la main.
Valeurs initiales concrètes
L'inférence du schéma repose sur le modèle initial. Préférez des valeurs concrètes comme '', 0, false ou un tableau non vide. Avec null, undefined ou un tableau vide, Angular ne peut pas toujours déduire le type attendu.
Ce qu'il faut surveiller avant de l'utiliser
WebMCP est prometteur, mais ce n'est pas encore une API à traiter comme une fondation stable.
Le standard bouge encore
Le dépôt GitHub de WebMCP présente le projet comme une proposition de nouvelle interface JavaScript. L'équipe Angular a explicitement renommé les APIs pour ajouter Experimental, justement parce que le standard et l'implémentation navigateur sont encore en mouvement.
Le navigateur doit suivre
Même si Angular fournit les helpers, un agent ne pourra utiliser ces tools que dans un environnement navigateur compatible avec WebMCP ou avec un polyfill adapté. Pour les tests, la documentation Angular cite @mcp-b/webmcp-polyfill.
Les entrées doivent être validées
Un schéma décrit ce que l'agent devrait envoyer. Il ne dispense pas de contrôler les données à l'exécution. Pour une application réelle, traitez les arguments reçus comme n'importe quelle entrée externe.
Les noms doivent être stables et uniques
Un tool est découvert par son nom. Évitez les noms trop vagues comme submit ou save. Préférez des noms métier explicites : registerUser, exportDashboard, searchCatalog.
Les droits utilisateur restent essentiels
WebMCP ne doit pas contourner votre modèle d'autorisation. Si un utilisateur ne peut pas exporter une donnée via l'interface, le tool correspondant ne devrait pas pouvoir le faire non plus.
Faut-il l'adopter maintenant ?
Pour une application en production, la réponse raisonnable est : pas comme dépendance critique. WebMCP et les APIs Angular associées sont encore expérimentaux.
En revanche, c'est le bon moment pour comprendre le modèle et prototyper. Les cas les plus intéressants sont les applications métier où une action est pénible à réaliser par clics successifs, mais facile à décrire sous forme de capacité structurée :
- chercher une information dans un catalogue ;
- remplir un formulaire complexe ;
- exporter un rapport ;
- créer une ressource à partir de champs validés ;
- déclencher une action contextualisée sur une route.
La direction est claire : Angular prépare ses applications à un web où les humains et les agents peuvent collaborer dans la même interface. L'enjeu n'est pas de rendre le DOM plus lisible pour l'IA, mais d'exposer les vraies intentions métier de l'application.