EmDash stellt unter /_emdash/api/mcp einen integrierten Model Context Protocol-Server (MCP) bereit. MCP-Clients nutzen ihn, um Inhalte, Bylines, Schemas, Medien, Taxonomien, Menüs, Revisionen und Einstellungen zu lesen und zu verwalten sowie die gesamte Site zu exportieren oder zu importieren.
Authentifizierung
Der MCP-Endpunkt erfordert ein Bearer-Token. EmDash unterstützt diese Token-Abläufe:
| Methode | Verwendung |
|---|---|
| OAuth 2.1 Authorization Code with Proof Key for Code Exchange (PKCE) | Interaktive MCP-Clients. Der Benutzer genehmigt die angeforderten Scopes im Browser. |
| Personal access token | Langlebiger Zugriff für einen Client oder eine Automatisierung. Tokens verwenden das Präfix ec_pat_ und werden im Admin erstellt. |
| OAuth 2.0 Device Authorization Grant | Befehlszeilen-Clients, die den Benutzer bitten, einen Code im Browser zu genehmigen. emdash login verwendet diesen Ablauf. |
Sitzungs-Cookies authentifizieren den MCP-Endpunkt nicht.
Scopes
OAuth- und persönliche Zugriffstokens begrenzen, welche Tools ein Client aufrufen kann. Die Rolle des Benutzers wird separat geprüft, sodass ein Scope nie eine Berechtigung gewährt, die der Benutzer nicht hat.
| Scope | Zugriff |
|---|---|
content:read | Inhalte, Bylines, Taxonomien, Terms, Menüs und Revisionen lesen und durchsuchen. Entwurfsähnliche Inhalte erfordern zusätzlich die Berechtigung content:read_drafts des Benutzers. |
content:write | Inhalte, Bylines und Revisionen erstellen und ändern. Aus Kompatibilitätsgründen mit bestehenden Tokens gewährt er außerdem taxonomies:manage und menus:manage. |
media:read | Medieneinträge lesen. |
media:write | Medien hochladen, registrieren, aktualisieren und löschen. |
schema:read | Sammlungen und Felder lesen. |
schema:write | Sammlungen und Felder erstellen, aktualisieren und löschen. |
taxonomies:manage | Taxonomiedefinitionen und Terms erstellen, aktualisieren und löschen. |
menus:manage | Menüs und Menüeinträge erstellen, aktualisieren und löschen. |
settings:read | Site-Einstellungen lesen. |
settings:manage | Site-Einstellungen aktualisieren. |
mcp:tools | MCP-Tools aufrufen, die von einem beliebigen aktivierten Plugin bereitgestellt werden. |
mcp:tools:<pluginId> | MCP-Tools aufrufen, die von einem einzelnen aktivierten Plugin bereitgestellt werden. |
transfer:export | Die gesamte Site als Site-Paket exportieren und herunterladen. |
transfer:analyze | Ein Site-Paket hochladen und für den Import analysieren. |
transfer:execute | Einen Site-Import starten, fortsetzen, abbrechen und aufgeben. |
admin | Jedes Core-Tool aufrufen, einschließlich der Site-Transfer-Tools. Plugin-Tools erfordern weiterhin mcp:tools oder den pluginspezifischen Scope. |
Der Scope admin umfasst transfer:export, transfer:analyze und transfer:execute. Jeder Transfer-Scope gewährt nur die ihm eigenen Aktionen und setzt die Administratorrolle voraus. Damit ein Client, etwa ein Agent, ein Site-Paket analysieren kann, ohne zu exportieren oder zu importieren, vergeben Sie transfer:analyze statt admin.
Auf der Zustimmungsseite für den Authorization Code kann der Benutzer angeforderte Scopes entfernen. EmDash schneidet die Anfrage außerdem mit den registrierten Scopes des Clients und der Rolle des Benutzers und lehnt eine leere Gewährung ab.
Rollenanforderungen
Die folgende Tabelle zeigt die Mindestrolle für die jeweilige grobe Fähigkeit. Eigentümerprüfungen können eine höhere Rolle verlangen, wenn ein Benutzer auf die Inhalte eines anderen Benutzers zugreift.
| Fähigkeit | Mindestrolle |
|---|---|
| Veröffentlichte Inhalte, Medien, Taxonomien, Terms und Menüs lesen | Subscriber |
| Entwürfe, geplante Inhalte, Papierkorb, Vergleiche und Revisionen lesen | Contributor |
| Inhalte erstellen oder Medien hochladen | Contributor |
| Eigene Inhalte bearbeiten oder veröffentlichen und Medien registrieren | Author |
| Bylines, Taxonomien, Menüs oder die Inhalte aller Benutzer verwalten | Editor |
| Schemas oder Einstellungen lesen | Editor |
| Schemas oder Einstellungen ändern, Inhalte endgültig löschen oder die Medienverwendung reparieren | Admin |
| Die gesamte Site exportieren oder importieren | Admin |
Die vollständigen Rollendefinitionen finden Sie unter Benutzerrollen.
Transport
Der Server verwendet zustandsloses Streamable HTTP. Jede Anfrage ist unabhängig; der Server hält weder eine MCP-Sitzung noch eine Server-Sent-Events-Verbindung aufrecht.
| Methode | Endpunkt | Verhalten |
|---|---|---|
POST | /_emdash/api/mcp | Akzeptiert JSON-RPC-Initialisierung, Tool-Auflistung und Tool-Aufrufe. |
GET | /_emdash/api/mcp | Gibt 405 Method Not Allowed zurück. |
DELETE | /_emdash/api/mcp | Gibt 405 Method Not Allowed zurück. |
Antworten verwenden JSON-RPC 2.0. Rufen Sie tools/list auf, um die aktuellen Eingabeschemas und MCP-Annotationen zu erhalten, bevor Sie eine Tool-Anfrage aufbauen.
Tool-Übersicht
Die folgende Übersicht entspricht den statischen Tools, die tools/list zurückgibt. Der registrierte Titel ist aufgeführt, weil Clients ihn möglicherweise anstelle des Tool-Namens anzeigen.
Inhalts-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
content_list | List Content | content:read |
content_get | Get Content | content:read |
content_create | Create Content | content:write |
content_update | Update Content | content:write |
content_delete | Delete Content (Trash) | content:write |
content_restore | Restore Content | content:write |
content_permanent_delete | Permanently Delete Content | content:write |
content_publish | Publish Content | content:write |
content_unpublish | Unpublish Content | content:write |
content_schedule | Schedule Content | content:write |
content_unschedule | Cancel Scheduled Publication | content:write |
content_compare | Compare Live vs Draft | content:read |
content_discard_draft | Discard Draft | content:write |
content_list_trashed | List Trashed Content | content:read |
content_duplicate | Duplicate Content | content:write |
content_translations | Get Content Translations | content:read |
Byline-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
byline_list | List Bylines | content:read |
byline_get | Get Byline | content:read |
byline_create | Create Byline | content:write |
byline_update | Update Byline | content:write |
byline_delete | Delete Byline | content:write |
byline_translations | List Byline Translations | content:read |
Schema-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
schema_list_collections | List Collections | schema:read |
schema_get_collection | Get Collection Schema | schema:read |
schema_list_block_types | List Block Types | schema:read |
schema_get_block_type | Get Block Type | schema:read |
schema_create_block_type | Create Block Type | schema:write |
schema_update_block_type | Update Block Type | schema:write |
schema_activate_block_type_version | Activate Block Type Version | schema:write |
schema_create_collection | Create Collection | schema:write |
schema_delete_collection | Delete Collection | schema:write |
schema_update_collection | Update Collection | schema:write |
schema_create_field | Add Field to Collection | schema:write |
schema_delete_field | Remove Field from Collection | schema:write |
schema_update_field | Update Field | schema:write |
Medien-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
media_list | List Media | media:read |
media_create | Confirm Signed Media Upload | media:write |
media_upload | Upload Media | media:write |
media_get | Get Media Item | media:read |
media_update | Update Media Metadata | media:write |
media_delete | Delete Media | media:write |
media_usage_repair | Repair Media Usage Index | admin |
Such-Tool
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
search | Search Content | content:read |
Taxonomie-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
taxonomy_list | List Taxonomies | content:read |
taxonomy_get | Get Taxonomy Definition | content:read |
taxonomy_create | Create Taxonomy Definition | taxonomies:manage |
taxonomy_update | Update Taxonomy Definition | taxonomies:manage |
taxonomy_delete | Delete Taxonomy Definition | taxonomies:manage |
taxonomy_list_terms | List Taxonomy Terms | content:read |
taxonomy_create_term | Create Taxonomy Term | taxonomies:manage |
taxonomy_update_term | Update Taxonomy Term | taxonomies:manage |
taxonomy_delete_term | Delete Taxonomy Term | taxonomies:manage |
taxonomy_term_translations | List Term Translations | content:read |
Menü-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
menu_list | List Menus | content:read |
menu_get | Get Menu with Items | content:read |
menu_translations | List Menu Translations | content:read |
menu_create | Create Menu | menus:manage |
menu_update | Update Menu | menus:manage |
menu_delete | Delete Menu | menus:manage |
menu_set_items | Set Menu Items | menus:manage |
Revisions-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
revision_list | List Revisions | content:read |
revision_restore | Restore Revision | content:write |
Einstellungs-Tools
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
settings_get | Get Site Settings | settings:read |
settings_update | Update Site Settings | settings:manage |
Site-Transfer-Tools
transfer:* bedeutet einen beliebigen der Scopes transfer:export, transfer:analyze oder transfer:execute. Der Scope admin erfüllt jede Anforderung in dieser Tabelle.
| Tool | Registrierter Titel | Erforderlicher Scope |
|---|---|---|
site_transfer_capabilities | Get Site Transfer Capabilities | transfer:* |
site_export_start | Start Site Export | transfer:export |
site_export_status | Get Site Export Status | transfer:export |
site_import_analyze | Analyze Site Import | transfer:analyze |
site_import_start | Start Site Import | transfer:execute |
site_import_status | Get Site Import Status | transfer:* |
site_import_resume | Resume Site Import | transfer:execute |
site_import_receipt | Get Site Import Receipt | transfer:* |
site_export_start und site_import_start akzeptieren auch ein Token ohne den Scope, wenn ein Administrator die Anfrage genehmigt. Für die Operation, die eine genehmigte Anfrage startet, akzeptieren dann auch site_export_status, site_import_status, site_import_resume und site_import_receipt dasselbe Token ohne den Scope.
Tool-Schemas nutzen
tools/list gibt für jedes Tool die Beschreibung, das JSON-Eingabeschema und die Annotationen zurück. Lesen Sie diese Metadaten, bevor Sie einen Aufruf aufbauen, damit Ihr Client die Felder, zulässigen Werte und Grenzen verwendet, die die installierte EmDash-Version unterstützt.
Ein Client, der zum Beispiel einen Artikel aktualisiert, ruft zuerst content_get auf und behält das zurückgegebene _rev. Anschließend kann er diese JSON-RPC-Anfrage senden:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "content_update",
"arguments": {
"collection": "articles",
"id": "01JARTICLE0000000000000000",
"data": { "title": "Updated title" },
"_rev": "opaque-revision-token"
}
}
}
Das Ergebnis wird als JSON-Text im ersten Inhaltsblock zurückgegeben. Ein Tool mit einem Ausgabeschema kann denselben Wert zusätzlich in structuredContent zurückgeben.
Inhaltslebenszyklus und Bylines
Die Referenz zum Inhaltslebenszyklus definiert das Verhalten bei Zustand, Revisionen, Berechtigungen, Konflikten und Hooks, das MCP, REST, die CLI und das Admin-Panel gemeinsam haben.
content_get gibt einen undurchsichtigen _rev-Wert zurück. Übergeben Sie ihn an content_update, content_publish, content_unpublish, content_schedule oder content_discard_draft. Ein veralteter Wert führt zu einem Konflikt. Lesen Sie das Element daher erneut, bevor Sie es noch einmal versuchen.
content_update ist ein partielles Update: Ausgelassene Felder behalten ihre aktuellen Werte. Wird ein veröffentlichtes Element aktualisiert, entsteht ein Entwurf, während die Live-Version unverändert bleibt. Verwenden Sie content_compare, um die Live- und Entwurfswerte zu prüfen, und rufen Sie dann content_publish auf, um den Entwurf live zu schalten, oder content_discard_draft, um ihn zu entfernen. content_delete verschiebt ein Element in den Papierkorb; nur content_permanent_delete entfernt ein Element aus dem Papierkorb endgültig.
Bylines sind wiederverwendbare Autoren- oder Mitwirkenden-Nennungen. byline_create kann eine Gast-Nennung anlegen oder eine Byline mit einem CMS-Benutzer verknüpfen. Ein Benutzer kann pro Locale nur eine Byline haben. Eine mit translationOf erstellte Übersetzung behält den Benutzer der Quell-Byline, sofern Sie nicht userId übergeben; übergeben Sie null, um die Übersetzung unverknüpft zu lassen. Übergeben Sie die zurückgegebene Byline-ID in der bylines-Eingabe, die content_create und content_update akzeptieren. Das Löschen einer Byline entfernt diese Nennung aus den Inhalten und hebt sie als primäre Byline auf.
Solange ein anderer Benutzer die Bearbeitungssperre eines Eintrags hält, weil er ihn im Admin geöffnet hat, schlagen content_update, content_delete, content_publish, content_unpublish, content_schedule, content_unschedule, content_discard_draft und revision_restore mit ENTRY_LOCKED fehl, und der Fehler nennt den Inhaber. Das erneute Lesen des Elements hebt die Ablehnung nicht auf. Übergeben Sie overrideLock: true, um trotzdem zu schreiben.
Übersetzungen
Die Übersetzungs-Tools für Inhalte, Bylines, Taxonomie-Terms und Menüs geben jede Locale-Variante der jeweiligen Übersetzungsgruppe zurück. Verwenden Sie die Eingabe translationOf des Erstellungs-Tools, wenn dessen Schema eine vorsieht; für die Pflichtfelder ist tools/list maßgeblich.
content_translations akzeptiert eine Sammlung und eine Inhalts-ID oder einen Slug. Die Übersetzungs-Tools für Bylines, Taxonomie-Terms und Menüs akzeptieren entweder die ID eines einzelnen Datensatzes oder die gemeinsame ID der Übersetzungsgruppe. Ein Benutzer ohne Entwurfszugriff sieht nur veröffentlichte Inhaltsübersetzungen.
Schemas, Medien, Taxonomien und Menüs
Schema-Tools ändern die Datenbankstruktur. Verwenden Sie schema_get_collection, bevor Sie Inhalte erstellen oder Felder ändern; es gibt die verfügbaren Feldnamen, Typen, Einschränkungen und Validierungsregeln zurück. Das Löschen von Sammlungen und Feldern entfernt gespeicherte Inhalte oder Feldwerte und kann nicht rückgängig gemacht werden.
Verwenden Sie media_upload, um base64-kodierte Bytes zu senden. Uploads unterliegen den konfigurierten Größen- und MIME-Typ-Grenzen, und identische Bytes können ein vorhandenes Medienelement mit deduplicated: true zurückgeben.
media_create bestätigt einen ausstehenden Upload, der über POST /_emdash/api/media/upload-url angelegt wurde. Laden Sie die Datei mit der zurückgegebenen signierten URL hoch und rufen Sie dann media_create mit demselben Benutzerkonto und dem zurückgegebenen storageKey auf. Das Tool prüft, ob die gespeicherte Datei existiert und der Größe entspricht, die beim Anfordern der Upload-URL angegeben wurde, bevor es sie in der Medienbibliothek verfügbar macht.
Taxonomiedefinitionen beschreiben die Klassifizierung und die Sammlungen, auf die sie angewendet wird; Terms sind die einzelnen Werte, die Inhalten zugewiesen werden. Hierarchische Terms können parentId verwenden, aber ein übergeordneter Term muss zur selben Taxonomie gehören und darf keinen Zyklus erzeugen. Das Erstellen oder Aktualisieren eines Terms mit parentId in einer nicht hierarchischen Taxonomie gibt VALIDATION_ERROR zurück. Ein Term mit untergeordneten Terms muss vor dem Löschen von diesen befreit werden, indem sie entfernt oder verschoben werden.
menu_set_items ersetzt die vollständige Eintragsliste eines Menüs in einer einzigen atomaren Operation. Die Reihenfolge des Arrays wird zur Menüreihenfolge. Der parentIndex eines verschachtelten Eintrags verweist auf einen früheren Eintrag im selben Array, platzieren Sie daher jeden übergeordneten Eintrag vor seinen untergeordneten.
media_usage_repair kann eine Sammlung oder alle Sammlungen verarbeiten und auf einer großen Site lange laufen. Seine Status complete, partial, failed und stale sind erfolgreiche Tool-Antworten. Prüfen Sie den zurückgegebenen Status und die Zähler, statt sich auf isError zu verlassen; Authentifizierungs-, Validierungs- und unerwartete Ausführungsfehler setzen isError: true.
Site-Transfer
Die site_*-Tools exportieren eine gesamte Site als Site-Paket und importieren ein Paket in eine leere Site. Sie starten und steuern Operationen und geben begrenzte Zusammenfassungen zurück. Paket-Bytes, Medien, Datensatzinhalte, E-Mail-Adressen von Principals oder Download-URLs übertragen sie nie. Laden Sie einen Export herunter und ein Paket für den Import hoch, und zwar mit der CLI oder der REST-API, und verweisen Sie danach über seine ID auf die Operation.
Jedes Transfer-Tool erfordert die Rolle Admin. Die Rolle wird vor dem Scope geprüft, sodass ein Aufrufer ohne Administratorrolle INSUFFICIENT_PERMISSIONS erhält und keine Genehmigungsanfrage angelegt wird.
Export
site_export_start akzeptiert comments (Standard true) und gibt die neue Operation zurück. site_export_status führt bei jedem Aufruf einen begrenzten Export-Schritt aus und meldet die Operation sowie nextRequestInMs. Rufen Sie es nach dieser Verzögerung erneut auf, bis nextRequestInMs den Wert null hat. Übergeben Sie advance: false, um den Status zu lesen, ohne einen Schritt auszuführen. Sobald der Export abgeschlossen ist, enthält das Ergebnis zusätzlich totals: Datensatzzahlen nach Art, Anzahl und Bytes der Medien sowie Anzahl und Bytes der Paketdateien.
Import
Laden Sie zuerst das Paket hoch. Der CLI-Befehl emdash site import <file> --analyze lädt es hoch, analysiert es und gibt die Operations-ID aus.
site_import_analyze führt bei jedem Aufruf einen begrenzten Analyseschritt aus. Wiederholen Sie es, bis nextRequestInMs den Wert null hat; das Ergebnis enthält dann eine Planzusammenfassung mit packageDigest, planDigest, executable, Zählern, Größen, Principals, Entscheidungen, Transformationen, Warnungen und Blockern. Jede Transformation wird mit ihrem code, dem Datensatz-kind (falls vorhanden) und einem count aufgeführt, ohne die IDs oder Werte, auf die sie angewendet wird. Principals, Warnungen und Blocker werden mit höchstens 50 Einträgen aufgeführt, die vollständige Anzahl steht in total. Principals werden ohne E-Mail-Adressen aufgeführt, mit den vorgeschlagenen und den aktuell zugeordneten Ziel-Benutzer-IDs. Übergeben Sie decisions, um Principals Ziel-Benutzer-IDs (oder null) zuzuordnen und den Titel und Slogan des Pakets oder des Ziels zu wählen. Jede Änderung erzeugt einen neuen planDigest.
site_import_start nimmt die Operations-ID sowie packageDigest und planDigest des neuesten Plans entgegen. Der Plan darf keine Blocker haben. Das Tool hat destructiveHint: true: Nach dem Start schreibt der Import in die Site und blockiert andere Schreibvorgänge, bis er abgeschlossen ist oder ein Administrator ihn aufgibt. Zeigen Sie dem Benutzer den Plan und holen Sie seine Bestätigung ein, bevor Sie es aufrufen.
site_import_resume führt einen begrenzten Import-Schritt aus und meldet die Operation sowie nextRequestInMs. Rufen Sie es auf, bis nextRequestInMs den Wert null hat; nach einem Verbindungsabbruch ist eine Wiederholung unbedenklich. site_import_status meldet die Operation und die Anzahl der hochgeladenen Dateien, ohne den Import voranzubringen. site_import_receipt gibt nach Abschluss des Imports die vollständige Quittung einschließlich receiptDigest zurück.
Während ein Import ausgeführt wird, sowie nachdem er fehlgeschlagen ist oder abgebrochen wurde, bis er aufgegeben wird, schlägt jedes andere Tool, das schreiben kann, mit TRANSFER_IMPORT_IN_PROGRESS fehl. Das gilt auch für Plugin-Tools. Tools mit der Annotation readOnlyHint: true und die acht site_*-Tools funktionieren weiter, und initialize sowie tools/list werden nie blockiert. Während der Aktivierung der Medienverwendung schlagen Schreib-Tools auf dieselbe Weise mit MEDIA_USAGE_ACTIVATION_IN_PROGRESS fehl.
Operationszusammenfassungen enthalten id, kind, state, stage, progress, packageDigest, planDigest, error ({ code } oder null) und Zeitstempel. progress ist { done, total } Schritte, dazu records, die bisher von einem Export geschriebenen Datensätze, sowie bytesDone und bytesTotal, sobald sie bekannt sind. Die MCP-Tools können einen Import weder abbrechen noch aufgeben; verwenden Sie die REST-API.
Genehmigungen
Ein Token mit admin oder dem benötigten Transfer-Scope fordert nie eine Genehmigung an. Bei einem Token ohne beides, etwa für einen Agenten, dem nur transfer:analyze gewährt wurde, werden site_export_start und site_import_start ausgeführt, wenn ein Administrator die Anfrage genehmigt:
- Der erste Aufruf ohne den Scope legt eine ausstehende Genehmigungsanfrage an und schlägt mit
TRANSFER_APPROVAL_REQUIREDfehl. Der Meldungstext und_meta.detailsenthalten dieapprovalIdund derenexpiresAt. Ein erneuter Aufruf mit denselben Argumenten und ohneapprovalIdgibt dieselbe offene Anfrage zurück. - Ein Administrator genehmigt die Anfrage unter Approval requests in Settings → Transfer oder mit dem sitzungsgebundenen Genehmigungs-Endpunkt der REST-API. API-Tokens können Anfragen nicht genehmigen.
- Der Client wiederholt den Aufruf mit denselben Argumenten und der
approvalId. Die Genehmigung ist verbraucht, sobald dieser Aufruf die Operation startet. Schlägt der Start der Operation fehl, kann der Client es mit derselbenapprovalIderneut versuchen, bis sie abläuft.
Eine Anfrage ist an den Benutzer, das Token, die Aktion und die exakten Argumente gebunden: die Export-Optionen oder die Import-Operations-ID und beide Digests. Eine ausstehende Anfrage läuft 15 Minuten nach ihrer Erstellung ab, eine genehmigte 15 Minuten nach der Genehmigung. Ein Aufruf mit anderen Argumenten oder einem anderen Token oder mit einer abgelehnten, abgelaufenen oder verbrauchten Genehmigung schlägt mit TRANSFER_APPROVAL_INVALID fehl.
site_import_start prüft die Digests, den Zustand der Operation und die Blocker des Plans, bevor es eine Anfrage anlegt, sodass ein Administrator nur um die Genehmigung eines Imports gebeten wird, der auch ausgeführt werden kann. Eine Genehmigung benötigt eine Token-ID, daher erhält ein Aufrufer ohne eine solche INSUFFICIENT_SCOPE.
Nachdem ein genehmigter Aufruf eine Operation gestartet hat, können derselbe Benutzer und dasselbe Token für diese Operation site_export_status oder site_import_status, site_import_resume und site_import_receipt ohne den Scope aufrufen.
Plugin-Tools
Ein Administrator muss die MCP-Oberfläche jedes Plugins aktivieren. Aktivierte Tools erscheinen in tools/list mit einem MCP-tauglichen Plugin-Präfix, gefolgt von __<localName> (zum Beispiel werden @acme/calendar und createEvent zu acme__calendar__createEvent), und erfordern bei Token-authentifizierten Aufrufen mcp:tools oder mcp:tools:<pluginId>. EmDash prüft außerdem die Berechtigung, die die Plugin-Route deklariert, und protokolliert Plugin, Tool, Route und Akteur im Audit-Log.
Bei bereichsbezogenen (scoped) IDs mit mehrdeutigen Trennzeichen steht vor dem lokalen Tool-Namen ein kurzer Hash. Verwenden Sie tools/list, um die generierten Namen zu ermitteln. Erzeugen zwei Tools denselben Namen, behält EmDash das erste und protokolliert für das übersprungene Tool eine Warnung.
Da Plugin-Tools installationsspezifisch sind, gehören sie nicht zur statischen Übersicht oben.
OAuth-Discovery
MCP-Clients ermitteln den Autorisierungsserver aus den Metadaten der geschützten Ressource:
GET /.well-known/oauth-protected-resource
Die Antwort bezeichnet /_emdash/api/mcp als geschützte Ressource und verweist auf den Autorisierungsserver. Clients lesen dann dessen Metadaten unter:
GET /.well-known/oauth-authorization-server/_emdash
Dieses Dokument liefert die aktuellen Endpunkte für Autorisierung, Token, Registrierung und Geräteautorisierung, die unterstützten Scopes und Grant-Typen sowie die PKCE-Methode S256. Verwenden Sie die ermittelten Werte, statt die OAuth-Protokollrouten fest zu codieren.
Eine nicht authentifizierte MCP-Anfrage gibt eine 401-Antwort mit der Discovery-URL zurück:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
Fehler
Ein Tool-Fehler hat isError: true. Der erste Textblock beginnt mit einem stabilen Code, und _meta.code wiederholt ihn für Clients, die strukturierte Metadaten lesen:
{
"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'articles' not found" }],
"isError": true,
"_meta": { "code": "NOT_FOUND" }
}
Eine Ablehnung durch die Bearbeitungssperre eines Eintrags nennt den Inhaber in _meta.details:
{
"content": [{ "type": "text", "text": "[ENTRY_LOCKED] Ada is holding this entry" }],
"isError": true,
"_meta": {
"code": "ENTRY_LOCKED",
"details": {
"userId": "01JB...",
"userName": "Ada",
"acquiredAt": "2026-05-01T09:12:04.117Z",
"expiresAt": "2026-05-01T09:19:04.117Z"
}
}
}
Authentifizierungsfehler verwenden Codes wie INSUFFICIENT_SCOPE und INSUFFICIENT_PERMISSIONS. Transportfehler verwenden den JSON-RPC-Code für interne Fehler -32603 und legen die zugrunde liegende Ausnahme nicht offen.