Zum Hauptinhalt springen

MCP Apps: Interaktive UIs innerhalb eines Tool-Calls

Experte

Sein gesamtes erstes Jahr lang war MCP ein Textprotokoll: ein Tool-Call gab JSON oder Markdown zurück, und der Client renderte, was ihm gefiel. MCP Apps — die erste offizielle Extension, finalisiert am 26. Januar 2026 und in die 2026-07-28 Core-Spec eingefaltet — fügt einen UI-Kanal hinzu. Ein Server kann jetzt ein Stück HTML ausliefern, der Client rendert es in einem sandboxed iframe, und der iframe spricht über JSON-RPC 2.0 auf postMessage zurück. Jeder Schreibvorgang läuft weiterhin über denselben Audit-Pfad wie jeder andere Tool-Call. Denke an interaktiver Bericht + Bestätigen-vor-Ausführen, nicht "eine ganze Webapp innerhalb von Claude laufen lassen".

What you'll learn
  • Was MCP Apps tatsächlich ist — und die vier Dinge, die es bewusst NICHT ist
  • Die Wire-Shape: Capability-Verhandlung, ui://-Resources, der Tool-_meta.ui-Link und die postMessage-Bridge
  • Das Sicherheitsmodell — Sandbox, CSP, Permission Policy, Host-Approval — und wo es dich trotzdem noch exponiert lässt
  • Wann man nach einer App statt einem einfachen Tool-Ergebnis greift (seltene, aber lohnenswerte Muster)
  • Wie sich das mit dem Rest der 2026-07-28-Stateless-Spec komponiert, die du bereits sprichst

Die Ein-Absatz-Version

Der Server deklariert eine oder mehrere UI-Resources an ui://<server>/<name>-URIs mit MIME-Typ text/html;profile=mcp-app. Ein Tool bewirbt "ich habe eine UI", indem es _meta.ui.resourceUri auf sein Schema legt. Bei einem tools/call kann der Server die üblichen Text-/Daten-Ergebnisse plus eine Referenz auf die UI-Resource zurückgeben; der Client holt das HTML mit resources/read, wirft es in einen sandboxed <iframe>, und jetzt chatten der iframe und der Host über postMessage mit JSON-RPC 2.0. UI-initiierte Tool-Calls erfordern weiterhin dieselbe Nutzerzustimmung wie jeder andere Tool-Call — die App kann rendern, sie kann vorschlagen, sie kann nicht still ausführen.

Was MCP Apps NICHT ist

Watch out
  • Keine vollwertige Webapp-Runtime. Der iframe hat standardmäßig kein Netzwerk (connect-src 'none'), keine Top-Level-Navigation und keine Drittanbieter-Skripte. Wenn deine Idee React von einem CDN laden und deine eigene API aufrufen muss, ist das nicht das Richtige.
  • Kein Weg, Tool-Call-Approval zu umgehen. UI-Aktionen, die etwas mutieren, reisen weiterhin als normale JSON-RPC-Tool-Calls, die der Host loggen, drosseln und für die er explizite Nutzerzustimmung verlangen kann.
  • Keine Sanitization. Die Sandbox begrenzt, was die UI TUN kann, nicht, wozu sie einen Nutzer verleiten kann. Behandle jede App wie Drittanbieter-Code — führe eine Allow-Liste, welche Server überhaupt UIs rendern dürfen.
  • Nicht persistent. Es gibt keine Session; wenn der Tool-Call endet, verschwindet der iframe. Jeder Zustand, den du über Calls hinweg brauchst, lebt in einem serverseitigen Handle, das du zurückgibst — genau wie im Rest der Stateless-Spec.

Die vier beweglichen Teile

Guided walkthrough1 of 4
  1. Der Client bewirbt die Extension in seinem Per-Request _meta.capabilities unter dem Reverse-DNS-Namespace io.modelcontextprotocol/ui und listet die MIME-Typen auf, die er rendern kann. Ein Server, der keine solche Capability sieht, überspringt einfach den UI-Kanal und gibt einfache Ergebnisse zurück — die gesamte Extension ist auf beiden Seiten opt-in.

Wire-Shapes, die du tatsächlich tippen wirst

Capability-Werbung auf einer Client-Request:

{
"jsonrpc": "2.0",
"method": "tools/call",
"params": { "name": "get_weather", "arguments": { "location": "Milan" } },
"_meta": {
"capabilities": {
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": ["text/html;profile=mcp-app"]
}
}
}
}
}

Das Tool-Schema auf der Server-Seite:

{
"name": "get_weather",
"description": "Get current weather and a 7-day forecast for a location.",
"inputSchema": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
},
"_meta": {
"ui": {
"resourceUri": "ui://weather-server/dashboard-template",
"visibility": ["model", "app"]
}
}
}

Die UI-Resource, direkt daneben deklariert:

{
"uri": "ui://weather-server/dashboard-template",
"mimeType": "text/html;profile=mcp-app",
"_meta": {
"ui": {
"connectDomains": [],
"permissions": []
}
}
}

Und die erste Message, die der iframe zurücksendet:

UI → host: JSON-RPC 2.0 over postMessage

window.parent.postMessage(
{
  jsonrpc: "2.0",
  id: 1,
  method: "ui/initialize",
  params: {
    toolName: "get_weather",
    toolArguments: { location: "Milan" },
    toolResult: /* whatever the server returned alongside the UI */
  }
},
"*"
);

Alles danach — den Host bitten, ein anderes Tool aufzurufen, eine Resource abonnieren, ein UI-seitiges Event senden — ist mehr JSON-RPC 2.0 auf demselben Kanal, strukturiert identisch zum Wire-Protocol, das du auf der Server-Seite bereits sprichst. Das ist der ganze Punkt: UI-Entwickler können das Standard-@modelcontextprotocol/sdk verwenden, statt einen maßgeschneiderten Shim zu lernen.

Sicherheitsmodell auf einem Screen

What you'll learn
  • Sandbox: Inhalt rendert in einem sandboxed <iframe>. Standard: keine Top-Level-Navigation, keine Formulare an beliebige Origins, keine Popups, keine Plugins.
  • CSP standardmäßig: connect-src 'none'. Die UI kann nirgendwo fetch()en. Um bestimmte Origins zu erlauben, deklariert der Server sie im _meta.ui.connectDomains der Resource, und der Host baut den CSP-Header aus dieser Liste.
  • Permission Policy: die _meta.ui.permissions der Resource werden in das allow-Attribut des iframes gemappt — Kamera, Mikrofon, Geolocation, clipboard-write. Nichts wird implizit gewährt.
  • Jeder UI-initiierte Schreibvorgang ist ein normaler Tool-Call. Der Host validiert ihn, kann Nutzerzustimmung verlangen und loggt ihn im selben Audit-Stream wie einen modell-initiierten Call.
  • Templates sind prefetchbar und hashbar. Ein Host, der auf einen bestimmten Hash pinnt, fängt einen Swap-under-you-Angriff ab; ein Host, der es nicht tut, bekommt, was der Server an diesem Tag ausliefert.

Wann man tatsächlich zu einer App greift

Die Latte liegt bewusst hoch — jede App ist Client-Surface für dich und Angriffsfläche für den Nutzer. Greife nur dann zu einer, wenn eine UI eine Chat-Runde mit klarem Abstand schlägt:

  • Data-Grid-Bestätigungen. "Hier sind 47 Zeilen, die ich gerade aktualisieren will — entcheck die, die du nicht willst." Ein Chat-Rendering davon ist entweder riesig oder unehrlich; ein Grid mit Checkboxen ist ehrlich und schnell.
  • Chart-getriebene Genehmigung. "Hier ist der Query-Plan / die Kostenprojektion / das Trace-Waterfall. Genehmigen oder ablehnen." Charts sind in HTML billig und als ASCII schrecklich.
  • Strukturierte Picker, bei denen die Form der Eingabe nicht Text ist. Datumsbereich mit einem Mini-Kalender, Tree-Select über einem Dateisystem oder einem Org-Chart, Map-Picker mit einer Bounding Box.
  • In-place-Editoren für den kleinen Schritt, in dem eine Diff-Ansicht + Accept/Reject das Regenerieren der ganzen Antwort schlägt.

Wenn deine Idee "lass mich ein ganzes Dashboard einbetten" ist, gehört sie nicht hierher — verlinke nach außen. Wenn deine Idee "lass mich beliebigen Nutzercode in der Sandbox ausführen" ist, gehört sie definitiv nicht hierher.

Der 2025-11-25-Kompatibilitätsvertrag

MCP Apps reitet auf dem Extension-Framework, das in der 2026-07-28 Core-Spec eingeführt wurde, aber die Extension selbst ist seit 2026-01-26 Final. Praktische Implikation: ein Client, der nur die ältere 2025-11-25-Revision plus diese Extension spricht, kann bereits Apps rendern; ein stateless 2026-07-28-Client nimmt sie als einen Eintrag in seiner Per-Request-Capability-Map auf. Weil die Extension auf beiden Seiten opt-in ist, bricht ein Server, der sie hinzufügt, nie einen alten Client — er überspringt einfach den UI-Zweig. Das ist die Form, die jede zukünftige MCP-Extension annehmen wird, sodass das Verständnis dieses Handshakes Schulden für die kommenden abbaut.

Wo MCP Apps auf der AILmanac-Karte landet

  • MCP 2026-07-28: Die Stateless-Spec — das Core-Protokoll, auf dem Apps reitet; insbesondere der Extensions-Framework-Abschnitt (SEP-2133).
  • MCP & Verbindung zu Tools — der API-seitige Connector. Er ist der Client, der den iframe rendert; der heutige Connector abstrahiert den Transport, sodass Apps unverändert durchfließt.
  • MCP in Claude Code — wohin sich Claude Codes MCP-Support entwickelt; UI-Rendering ist eine Client-Capability, keine Server-Capability, also ist dies die Oberfläche, die entscheidet, welche Apps überhaupt für dich rendern.
  • MCP-Server absichern — das Härtungsmuster für die Server auf der anderen Seite dieses iframes.

Schneller Check

Check yourself

0/4
  1. Wie spricht ein MCP-Apps-iframe zurück zum Host?
  2. Welchen Netzwerkzugriff hat ein MCP-Apps-iframe standardmäßig?
  3. Ein Tool will eine UI rendern. Was ist das EINE Stück Metadaten, das ein einfaches Tool in ein UI-tragendes verwandelt?
  4. Eine UI innerhalb des iframes will etwas auf dem Server mutieren. Was passiert?

Vokabular

MCP-Apps-Terminologie
Drücke Enter oder die Leertaste, um die Karte umzudrehen. Nutze die Pfeiltasten links und rechts, um zwischen den Karten zu wechseln.Begriff angezeigt.
1 / 9

Quellen & Weiterführendes

Weiter