Chrome 146 führt WebMCP (Web Model Context Protocol) ein, eine browsernative API, die es Websites ermöglicht, strukturierte Tools für KI-Agenten bereitzustellen. Anstatt auf Screen Scraping oder fragile Selektoren angewiesen zu sein, können Agenten nun Formulare entdecken, ihren Zweck verstehen, sie intelligent ausfüllen und sogar imperative JavaScript-Funktionen direkt aufrufen. Diese Schritt-für-Schritt-Anleitung führt durch die Implementierung aller drei WebMCP-Schichten in einem realen Next.js-Projekt, mit Codebeispielen und Best Practices aus der Produktion.
Live ausprobieren
Was ist WebMCP und warum ist es wichtig?
WebMCP ist für KI-Agenten das, was robots.txt für Suchmaschinen-Crawler ist: eine standardisierte Möglichkeit für Websites, mit automatisierten Systemen zu kommunizieren. Aber anstatt Crawlern mitzuteilen, was sie nicht indexieren sollen, teilt WebMCP KI-Agenten mit, was sie auf einer Seite tun können.
Stellen Sie es sich als ein strukturiertes Menü für KI vor. Wenn ein Agent eine Seite mit WebMCP-Unterstützung besucht, weiß er sofort: "Diese Seite hat ein Kontaktformular, das Name, E-Mail und Nachricht akzeptiert. Ich kann entweder das Formular visuell ausfüllen oder eine JavaScript-API aufrufen, um die Daten programmatisch zu übermitteln."
Drei Schichten arbeiten zusammen, um dies zu ermöglichen:
| Schicht | Funktionsweise | Wann KI sie nutzt |
|---|---|---|
| Deklaratives HTML | Attribute an Formularen und Eingaben beschreiben den Tool-Zweck | Agent füllt Formular visuell aus und klickt Absenden |
| Imperatives JavaScript | navigator.modelContext.registerTool() stellt eine API bereit | Agent ruft die Tool-Funktion direkt per Code auf |
| Manifest-Erkennung | .well-known/webmcp-Endpunkt und seitenbezogenes JSON | Agent entdeckt verfügbare Tools vor der Navigation |
TypeScript-Deklarationen für WebMCP einrichten
Bevor Sie WebMCP-Attribute hinzufügen, richten Sie TypeScript-Deklarationen ein. Ohne diese wird JSX benutzerdefinierte Attribute wie toolname und tooldescription mit Kompilierungsfehlern ablehnen.
Erstellen Sie eine types/webmcp.d.ts-Datei, die die globalen Interfaces deklariert, die Chrome 146 bereitstellt:
export {};
declare global {
interface WebMCPSubmitEvent extends Event {
agentInvoked?: boolean;
respondWith?: (response: string) => void;
}
interface WebMCPTool {
name: string;
description: string;
execute: (params: Record<string, unknown>) => unknown | Promise<unknown>;
inputSchema: {
type: string;
properties?: Record<string, {
type: string;
description?: string;
enum?: string[];
}>;
required?: string[];
};
}
interface ModelContext {
registerTool: (tool: WebMCPTool) => void;
unregisterTool: (name: string) => void;
}
interface Navigator {
modelContext?: ModelContext;
}
}
declare module "react" {
interface HTMLAttributes<T> {
toolname?: string;
tooldescription?: string;
toolparamdescription?: string;
}
}Best Practice: Warum globale Deklarationen?
Deklarative HTML-Attribute zu Formularen hinzufügen
Die deklarative Schicht ist am einfachsten zu implementieren. Fügen Sie drei Attribute zu Ihren bestehenden Formularen hinzu:
- 1toolname am Formularelement: ein eindeutiger Bezeichner, den der Agent verwendet, um dieses Tool zu referenzieren
- 2tooldescription am Formularelement: eine natürlichsprachliche Beschreibung, die dem Agenten sagt, wann und warum er dieses Formular verwenden soll
- 3toolparamdescription an jedem Input, Select und Textarea: Kontext für jedes Feld, der den Agenten leitet, welchen Wert er bereitstellen soll
<form
id="contactForm"
toolname="contact_form"
tooldescription="Submit a contact request with name, email, reason, and message."
noValidate
onSubmit={handleSubmit}
>
<input
type="text"
name="name"
required
toolparamdescription="Full name of the person submitting the request"
/>
<input
type="email"
name="email"
required
toolparamdescription="Email address for follow-up communication"
/>
<select
name="reason"
toolparamdescription="Reason for contact: 'support', 'sales', 'partnership', or 'other'"
>
<option value="support">Support</option>
<option value="sales">Sales</option>
</select>
<textarea
name="message"
required
toolparamdescription="Detailed message describing the request"
/>
<button type="submit">Send</button>
</form>Best Practice: Unterschiedliche Namen verwenden
Benutzerdefinierte UI-Komponenten behandeln
Wenn Ihr Formular benutzerdefinierte UI-Komponenten wie Button-Gruppen oder Radio-Karten anstelle nativer Select-Elemente verwendet, fügen Sie ein verstecktes <select>-Element hinzu. KI-Agenten können Optionen nur über Standard-HTML-Formularelemente entdecken.
Agent-Formularübermittlungen in React verarbeiten
Wenn ein KI-Agent ein deklaratives Formular ausfüllt und absendet, feuert Chrome ein normales submit-Event mit zwei zusätzlichen Eigenschaften am nativen Event:
- agentInvoked: boolean — wahr, wenn der KI-Agent das Absenden ausgelöst hat
- respondWith(response: string) — sendet eine Textantwort zurück an den Agenten
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const nativeEvent = e.nativeEvent as WebMCPSubmitEvent;
if (nativeEvent.agentInvoked) {
const fd = new FormData(e.currentTarget);
const data = {
name: fd.get("name") as string,
email: fd.get("email") as string,
reason: fd.get("reason") as string,
message: fd.get("message") as string,
};
const ref = "REF-" + Math.random().toString(36).substring(2, 8).toUpperCase();
// MUST be called synchronously, before any await!
nativeEvent.respondWith?.(
`Contact submitted successfully. Reference: ${ref}`
);
await submitToBackend(data);
setSubmitted(true);
return;
}
// Human path (unchanged)
setIsSubmitting(true);
};Kritisch: respondWith() muss synchron sein
Imperative Tools mit Best Practices registrieren
Die imperative Schicht gibt KI-Agenten einen zweiten Weg: Anstatt Formulare visuell auszufüllen, ruft der Agent eine JavaScript-Funktion direkt auf. Dies ist schneller, zuverlässiger und funktioniert auch bei komplexer oder dynamischer Formular-UI.
Best Practice: Das Ref-Guard-Registrierungsmuster
const toolRegisteredRef = useRef(false);
useEffect(() => {
const mc = navigator.modelContext;
if (!mc || toolRegisteredRef.current) return;
toolRegisteredRef.current = true;
mc.registerTool({
name: "submit_contact_request",
description: "Submit a contact request programmatically.",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "Full name" },
email: { type: "string", description: "Email address" },
reason: { type: "string", description: "Contact reason" },
message: { type: "string", description: "Message body" },
},
required: ["name", "email", "reason", "message"],
},
execute: async (params: Record<string, unknown>) => {
return dispatchAndWait("webmcp:submitContact", params);
},
});
}, []);Keine React Hooks für die Registrierung verwenden
Die dispatchAndWait-Brücke zwischen Tools und React
Die execute-Funktion des imperativen Tools läuft außerhalb von Reacts Komponentenbaum. Um React-State zu aktualisieren, verwenden Sie das dispatchAndWait-Muster:
export function dispatchAndWait(
eventName: string,
detail: Record<string, unknown>,
timeoutMs = 30000
): Promise<string> {
return new Promise((resolve, reject) => {
const requestId = Math.random().toString(36).substring(2, 15);
const completionEvent = `tool-completion-${requestId}`;
let timer: ReturnType<typeof setTimeout>;
const handleCompletion = (e: Event) => {
clearTimeout(timer);
window.removeEventListener(completionEvent, handleCompletion);
const customEvent = e as CustomEvent<{ result: string }>;
resolve(customEvent.detail?.result ?? "Action completed");
};
window.addEventListener(completionEvent, handleCompletion);
timer = setTimeout(() => {
window.removeEventListener(completionEvent, handleCompletion);
reject(new Error(`WebMCP tool timeout: ${eventName}`));
}, timeoutMs);
window.dispatchEvent(
new CustomEvent(eventName, { detail: { ...detail, requestId } })
);
});
}Manifest-basierte Erkennung implementieren
Die Manifest-Schicht ermöglicht Vor-Navigations-Erkennung. Bevor ein Agent überhaupt eine Seite öffnet, kann er das Site-Manifest abrufen.
Site-Level-Manifest in Next.js erstellen
import { NextResponse } from "next/server";
export const runtime = "edge";
export async function GET() {
const manifest = {
spec: "webmcp/0.1",
site: {
name: "My Website",
version: "2026.02",
description: "Website description for AI agents.",
pages: [
{
url: "/contact",
intents: ["contact_form", "submit_contact_request"],
},
],
flows: [
{
id: "contact_inquiry",
description: "Submit a contact request.",
steps: [{ intent: "contact_form", page: "/contact" }],
},
],
},
};
return NextResponse.json(manifest, {
headers: {
"Cache-Control": "public, max-age=86400, s-maxage=86400",
"Access-Control-Allow-Origin": "*",
},
});
}Best Practice: Aus Middleware ausschließen
Seitenbezogenes Manifest hinzufügen
Betten Sie ein <script type="application/json" id="webmcp">-Tag in jeder Seite ein:
{
"spec": "webmcp/0.1",
"page": { "url": "/contact", "title": "Contact Us" },
"context": {
"purpose": "Contact form for inquiries and support requests",
"entities": ["contact_request"],
"auth": { "required": false }
},
"intents": [
{
"id": "contact_form",
"description": "Submit a contact request",
"inputs": [
{ "name": "name", "type": "string", "required": true },
{ "name": "email", "type": "email", "required": true },
{ "name": "message", "type": "string", "required": true }
],
"policy": { "rateLimit": "5/min" }
}
]
}Visuelles Feedback mit WebMCP-CSS-Pseudoklassen
Chrome 146 fügt zwei neue CSS-Pseudoklassen hinzu:
- :tool-form-active — wird auf das Formularelement angewendet, während der Agent damit interagiert
- :tool-submit-active — wird auf den Absende-Button angewendet, während der Agent absendet
"use client";
import { useEffect } from "react";
export default function WebMCPStyles() {
useEffect(() => {
const style = document.createElement("style");
style.setAttribute("data-webmcp", "true");
style.textContent = [
"*:tool-form-active {",
" outline: 2px solid rgba(147, 51, 234, 0.5);",
" outline-offset: 2px;",
"}",
"*:tool-submit-active {",
" background: linear-gradient(110deg, #7c3aed 30%, #a78bfa 50%, #7c3aed 70%);",
" background-size: 200% 100%;",
" animation: webmcp-shimmer 2s infinite linear;",
"}",
"@keyframes webmcp-shimmer {",
" to { background-position: 200% center; }",
"}",
].join("\n");
document.head.appendChild(style);
return () => { style.remove(); };
}, []);
return null;
}Häufige Implementierungsfehler und wie man sie vermeidet
Best Practices: Fehler vermeiden
- 1Gleicher Name für deklarative und imperative Tools. Chrome wirft eine "Duplicate tool name"-DOMException. Verwenden Sie immer unterschiedliche Namen.
- 2respondWith() nach await aufrufen. Der Antwortkanal schließt sich, bevor die asynchrone Operation abgeschlossen ist.
- 3React Hooks für registerTool verwenden. Der Strict Mode mountet doppelt und ruft registerTool zweimal auf.
- 4Fehlende TypeScript-Deklarationen. Ohne die .d.ts-Datei verursachen die Attribute TSX-Kompilierungsfehler.
- 5Manifest-Routen nicht aus der i18n-Middleware ausschließen. Die Middleware leitet /.well-known/webmcp um und unterbricht die Erkennung.
- 6WebMCP zu sensiblen Formularen hinzufügen. Fügen Sie niemals toolname zu Formularen mit Passwörtern oder Kreditkarten hinzu.
Best Practices und wichtige Erkenntnisse
- WebMCP bietet ein standardisiertes Protokoll für die KI-Website-Interaktion und ersetzt fragiles Screen Scraping durch strukturierte Tool-Erkennung.
- Die Drei-Schichten-Architektur (deklarativ, imperativ, Manifest) gibt Agenten mehrere Wege zur Interaktion mit Ihrer Website.
- TypeScript-Deklarationen sind unverzichtbar und sollten der erste Schritt sein.
- Das Ref-Guard-Muster ist der korrekte Weg zur Registrierung imperativer Tools in React.
- respondWith() muss synchron sein. Dies ist die wichtigste Regel in der deklarativen Schicht.
- WebMCP-Manifeste fungieren als robots.txt für KI-Agenten.
Da KI-Agenten in Browser-Workflows immer häufiger werden, positioniert WebMCP Ihre Website als erstklassigen Teilnehmer im agentischen Web. Der Implementierungsaufwand ist überschaubar, aber der Nutzen ist erheblich: Ihre Formulare werden für jeden Chrome 146+ KI-Agenten erkennbar und nutzbar.
Quellenverzeichnis
- 1
- 2
- 3Chrome 146 Release Notes(Google Chrome Developers)