Agent Plugins: ein portables Paketformat für Skills und MCP-Server
Amazon, Cursor, Microsoft, OpenAI und Vercel treiben ein gemeinsames Paketformat für Agent Skills und MCP-Server. Was Agent Plugins 1.0 regelt und bewusst offenlässt.
Agent Skills und MCP haben bereits eigene Spezifikationen. Ein Skill ist ein Verzeichnis mit einer SKILL.md und Frontmatter, ein MCP-Server spricht ein dokumentiertes Protokoll. Beide Bausteine sind darauf ausgelegt, nicht an einen einzelnen Client gebunden zu sein.
Was bisher fehlte, ist die Ebene darüber: das Paket. Wer einen Skill zusammen mit dem dazugehörigen MCP-Server ausliefern wollte, musste sich am Plugin-Format des jeweiligen Clients orientieren. Die eigentlichen Komponenten konnten identisch sein, Verzeichnisstruktur, Manifest und Konfiguration waren es nicht.
Agent Plugins schliesst diese Lücke mit einem bewusst kleinen gemeinsamen Nenner. Version 1.0.0 ist die aktuelle Fassung. Die offizielle Website führt ihren Status derzeit als Working Draft, während der kanonische Spec-Quelltext im GitHub-Repository bereits Published enthält. Die beiden offiziellen Quellen sind an dieser Stelle also noch nicht synchron. Inhaltlich definiert v1.0.0 ein Verzeichnis, eine Manifestdatei, zwei feste Komponentenorte und klare Fehlergrenzen. Ebenso interessant ist, was sie nicht standardisiert.
Die kleinste gültige Form
Ein Plugin ist ein Verzeichnis mit einer plugin.json im Wurzelverzeichnis. Alles andere ist optional:
hello-plugin/
├── plugin.json
└── skills/
└── greet/
└── SKILL.md
Das Manifest kann auf zwei Felder schrumpfen:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "hello-plugin"
}
Bemerkenswert ist, was hier nicht steht: Das Manifest listet die Komponenten nicht auf. Es gibt keinen skills-Eintrag mit Pfaden und keine Registrierung von MCP-Servern. Ein Client findet Skills unter skills/ und MCP-Server über eine mcp.json im Wurzelverzeichnis. Diese Orte sind fest.
Ein Plugin mit beiden portablen Komponententypen und einer client-spezifischen Erweiterung kann so aussehen:
my-plugin/
├── plugin.json
├── mcp.json
├── skills/
│ └── summarize/
│ ├── SKILL.md
│ ├── scripts/
│ └── references/
└── com.example.client/
Wer dahintersteht
Agent Plugins wird als offener, herstellerneutraler Standard entwickelt. Das Technical Steering Committee besteht aktuell aus Core Maintainern mit Zugehörigkeit zu Amazon, Cursor, Microsoft, OpenAI und Vercel. Die Governance-Rollen gehören laut Technical Charter allerdings den Personen, nicht den Unternehmen: Es gibt keine reservierten Unternehmenssitze, und kein einzelner Anbieter darf eine Mehrheit der Core-Maintainer-Sitze kontrollieren. Spezifikationstext und Dokumentation stehen unter CC BY 4.0, Code und Schemas unter Apache 2.0.
Das ist für mich die eigentliche Nachricht. Mehrere direkte Wettbewerber einigen sich nicht auf eine gemeinsame Laufzeitumgebung, sondern auf die Schachtel. Der Charter nennt Portabilität, Wettbewerb und langfristige Stabilität ausdrücklich als Ziele. Ein gemeinsames Paketformat senkt die Wechselkosten zwischen Clients, ohne den Clients vorzuschreiben, wie Installation, Berechtigungen oder Oberfläche aussehen müssen.
Inzwischen gibt es auch eine offizielle Seite mit Compatible Clients. Sie listet aktuell VS Code, Cursor, GitHub Copilot, ChatGPT & Codex sowie Kiro. Alle fünf führen Agent Skills und MCP-Unterstützung auf; bei den MCP-Transporten gibt es kleinere Unterschiede. Das ist ein deutlich stärkeres Signal als eine reine Spezifikation auf Papier.
Ein Verzeichnis, kein Archiv
Die Design Decisions legen die Paketeinheit bewusst als Verzeichnis fest, nicht als .zip, .tar.gz oder Registry-Bundle. Das ist pragmatisch: Ein Verzeichnis lässt sich mit ls, cat und git inspizieren, während der Entwicklung direkt bearbeiten und ohne Sonderwerkzeug versionieren.
Der Kernstandard definiert dafür weder Archivformat noch Registry, Prüfsumme oder Signatur. Das bedeutet nicht, dass Distributionen darauf verzichten müssen. Es bedeutet nur, dass diese Ebene ausserhalb des portablen Paketformats liegt und vom Client oder Verteilsystem gelöst werden muss.
Das Manifest ist geschlossen
plugin.json benötigt $schema und name. Dazu kommt ein fester Satz optionaler Metadaten: version, description, author, homepage, repository, license, keywords und extensions. Andere Felder auf oberster Ebene sind Schemaverstösse.
Wer von einem client-spezifischen Format migriert, greift schnell nach genau den Feldern, die dort nicht hingehören: hooks, agents, commands, mcpServers oder lspServers. Client-spezifische Daten landen stattdessen unter extensions, hinter einem Reverse-Domain-Namensraum.
Das geschlossene Schema erlaubt strikte Validierung und verhindert, dass einzelne Clients den gemeinsamen Namensraum schleichend erweitern. Eine wichtige Besonderheit: Unbekannte Top-Level-Felder machen das Plugin nicht automatisch unbrauchbar. Clients müssen sie melden und ignorieren, sofern der Rest des Manifests gültig ist. Für fast alle anderen Schemafehler in plugin.json gilt das Gegenteil: Sie sind fatal für das gesamte Plugin.
Nur zwei Komponententypen
v1 kennt genau zwei portable Komponententypen: Agent Skills und MCP-Server. Commands, Hooks, Agents, Rules und LSP-Server sind ausdrücklich nicht Teil des Formats.
Die Begründung ist sinnvoll. Skills und MCP haben eigene Spezifikationen ausserhalb des Projekts und bereits relevante Verbreitung über mehrere Clients hinweg. Ein Paketformat kann nur portabel machen, was darunter schon einen portablen Vertrag besitzt. Hooks aufzunehmen hätte bedeutet, deren Semantik gleich mitstandardisieren zu müssen.
PLUGIN_ROOT und PLUGIN_DATA
Bei stdio-MCP-Servern werden zwei Variablen wichtig:
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
"mcpServers": {
"deploy-platform": {
"type": "stdio",
"command": "node",
"args": ["${PLUGIN_ROOT}/mcp/deploy-platform/server.mjs"],
"env": {
"CATALOG": "${PLUGIN_ROOT}/mcp/deploy-platform/data/environments.json",
"STATE": "${PLUGIN_DATA}/deployments.json"
}
}
}
}
Der Client setzt PLUGIN_ROOT und PLUGIN_DATA für den Subprozess und ersetzt beide Platzhalter einmalig und nicht rekursiv in args, env-Werten und cwd. Nicht ersetzt wird in command, URLs, HTTP-Headern oder Schlüsselnamen.
PLUGIN_ROOT zeigt auf das ausgelieferte Paket. PLUGIN_DATA zeigt auf ein vom Client verwaltetes, beschreibbares Verzeichnis, dessen Inhalt Plugin-Updates überlebt. Abhängigkeiten, Caches und anderer persistenter Zustand gehören deshalb nach PLUGIN_DATA; ausgelieferte Skripte und Konfiguration nach PLUGIN_ROOT.
command ist zusätzlich ein einzelnes ausführbares Token. "node" ist gültig, "node --inspect" nicht. Argumente gehören nach args. Ein mitgeliefertes Executable muss als plugin-relativer Pfad mit ./ angegeben werden.
Ein Detail ist leicht falsch zu implementieren: Nicht jeder String, der wie ein Pfad aussieht, unterliegt der Pfadeindämmung. command und cwd sind definierte Pfadfelder und dürfen den jeweiligen Root nicht verlassen. args und env sind dagegen opake Strings. Ein Client darf sie nicht allein deshalb als Paketpfade validieren, weil darin etwa ../ vorkommt.
Fehler bleiben möglichst lokal
Die Spezifikation zieht die Ausfallgrenzen eng. Eine ungültige mcp.json deaktiviert MCP für dieses Plugin, nicht die Skills. Ein ungültiger Servereintrag wird übersprungen, ohne die anderen Server zu blockieren. Dasselbe gilt, wenn ein Server nicht startet, keine Verbindung bekommt oder bei Authentifizierung beziehungsweise MCP-Handshake scheitert. Ein ungültiger Skill wird übersprungen, die übrigen Komponenten laden weiter.
Das zentrale Manifest ist strenger. Fehlt plugin.json, ist die deklarierte Version unbekannt oder verletzt das Manifest abseits der expliziten Ausnahmen sein Schema, muss der Client das gesamte Plugin ablehnen. Die zwei bemerkenswerten Ausnahmen sind unbekannte Top-Level-Felder sowie ein extensions-Feld mit falschem Typ; beides wird gemeldet und ignoriert.
Diese Abstufung ist sinnvoll: Ein kaputter optionaler Server soll nicht zwei funktionierende Skills mitreissen. Ein ungültiges Manifest ist dagegen ein Fehler in der gemeinsamen Vertragsgrundlage.
Client-Extensions: der Ausweg für alles andere
Hooks sind kein portabler Komponententyp. Ein Client kann sie trotzdem über einen eigenen Reverse-Domain-Namensraum ergänzen:
my-plugin/
├── plugin.json
├── skills/
├── mcp.json
└── com.vendor.client/
└── hooks/
Passend dazu kann plugin.json unter extensions Daten mit demselben Namespace enthalten. Ein Client, der diesen Namespace nicht implementiert, ignoriert ihn. Der portable Kern bleibt dadurch weiterhin nutzbar.
Das macht Migrationen additiv statt verlustbehaftet. Die Grenze ist ebenfalls klar: Ein selbst erfundener Namespace schafft noch keine Funktion. Erst ein Client, der ihn dokumentiert und implementiert, gibt den darin liegenden Dateien oder Metadaten eine Bedeutung.
Was beim Bauen auffällt
Zum Nachvollziehen habe ich ein Demo-Plugin mit zwei Skills, einem stdio-MCP-Server für eine fingierte Deployment-Plattform und einem minimalen Client gebaut: github.com/dprinz/agent-plugins.
Beim Implementieren fallen vor allem die festen Discovery-Regeln auf. Skills werden genau eine Ebene unter skills/ gesucht. skills/greet/SKILL.md kann entdeckt werden, skills/greet/nested/SKILL.md nicht; Clients dürfen nicht rekursiv suchen. Ein entdeckter Skill, dessen name nicht zum Verzeichnisnamen passt, ist nach der Agent-Skills-Spezifikation ungültig und muss übersprungen werden.
Die zweite Stolperstelle ist die Pfadsemantik. Paketdateien und ausdrücklich als Pfade definierte Felder müssen nach Auflösung innerhalb des erlaubten Roots bleiben, Symlinks eingeschlossen. Gleichzeitig sind args und env bewusst keine Pfadfelder. Ein Konformitätsprüfer, der jeden String mit ${PLUGIN_ROOT} oder ../ automatisch als Dateipfad behandelt, ist strenger als die Spezifikation.
Genau solche Details zeigen den Wert des kleinen Formats. Die Regeln sind überschaubar, aber präzise genug, dass zwei unabhängige Clients beim selben Paket nicht völlig unterschiedliche Dinge erraten müssen.
Was die Spezifikation offenlässt
Das Projekt führt mit FUTURE_CONSIDERATIONS.md eine ausdrücklich nicht normative Liste möglicher späterer Themen. Darin stehen unter anderem Berechtigungsmodell, Sandboxing, Signaturen und Provenance, Secret-Handling, Enterprise-Policies, Audit-Events, Plugin-Abhängigkeiten und Testkonventionen. Keiner dieser Punkte ist für eine spätere Version zugesagt.
Das fehlende Vertrauensmodell halte ich für verkraftbar. Ein Paketformat muss nicht gleichzeitig Registry, Signaturprüfung und Unternehmens-Policy standardisieren. Ein Client, der Plugins aus dem Netz installiert, braucht diese Schichten trotzdem; Agent Plugins überlässt sie bewusst dem Client oder Verteilsystem.
Bei Secrets ist die Lücke praktischer spürbar. Viele MCP-Integrationen brauchen API-Keys oder andere Credentials. v1 verbietet deren Einbettung in konfigurierte env-Werte und HTTP-Header, bietet aber noch keinen portablen Ersatz wie Secret-Referenzen oder OAuth-Konfiguration. Das Paket bleibt portabel, die Bereitstellung der Zugangsdaten ist es noch nicht zwingend.
Meine Einschätzung
Agent Plugins löst ein enges Problem gut. Die Entscheidung, nur Skills und MCP aufzunehmen und Client-Sonderfälle hinter Reverse-Domain-Namensräumen zu halten, begrenzt den Standard auf Dinge, für die bereits ein gemeinsamer Vertrag existiert. Die Fehlergrenzen und die Trennung von PLUGIN_ROOT und PLUGIN_DATA sind dabei keine Nebensachen, sondern die Details, die Portabilität im Betrieb erst brauchbar machen.
Die offizielle Liste kompatibler Clients verändert die Ausgangslage: Das Format ist nicht mehr nur eine Spezifikation mit prominenten Unterstützern. VS Code, Cursor, GitHub Copilot, ChatGPT & Codex und Kiro führen bereits konkrete Unterstützung auf. Entscheidend wird nun, ob Agent Plugins bei diesen Produkten zum normalen Paketformat wird oder dauerhaft als zusätzlicher Kompatibilitäts-Ladepfad neben den nativen Formaten lebt. Im zweiten Fall sinkt die Fragmentierung, verschwindet aber nicht vollständig.
Für ein Plugin, das mehrere Clients bedienen soll, würde ich den portablen Kern trotzdem als Quelle der Wahrheit nehmen und Client-Extensions nur dort ergänzen, wo sie wirklich nötig sind. Selbst wenn Distribution, Berechtigungen und Secrets vorerst client-spezifisch bleiben, liegt die Abweichung dann wenigstens am Rand und nicht mehr mitten in Skills und MCP-Konfiguration.