Einen externen MCP-Client anbinden
SupaCloud stellt ein entwickler-gerichtetes MCP-Gateway unter POST /api/mcp
bereit. Es ist ein standardkonformer Model-Context-Protocol-
Streamable-HTTP-Endpoint (stateless JSON-RPC 2.0), sodass jeder konforme MCP-Client
— eine lokale IDE, ein Coding-Agent oder ein handgeschriebenes curl — eine
kuratierte Menge an SupaCloud-Tools auflisten und aufrufen kann. Die
Authentifizierung erfolgt per scoped scmt_-Management-Token, nicht über einen
OAuth-Flow: SupaCloud ist eine OIDC-Relying-Party, kein Authorization-Server — das
Gateway liefert daher weder /token noch /.well-known aus. Folge diesen
Schritten, um einen Client anzubinden.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“- Die Instanz muss die Enterprise-Edition betreiben. Das Gateway ist über das
Feature
mcp_gateway_externalgeschützt (fail-closed ininterfaces/http/external_mcp.rs); auf einer Community-Instanz liefert jeder Request an/api/mcpein403. - Du brauchst die Berechtigung, ein Management-Token für den Ziel-Workspace zu prägen (das Token muss workspace-scoped sein — ein globales/Bootstrap-Token wird abgelehnt).
-
Ein scoped
scmt_-Token prägen.Das Gateway verwendet das bestehende Management-API-Token (
scmt_…, hash-only), erweitert um zwei MCP-Scopes:mcp:read— die Read-Tools (listen/lesen/beobachten), inklusiverun.list/run.get/run.events.mcp:ops— impliziertmcp:readund ergänzt die Ops- und Script-Run-Tools (workflow.trigger,script.run, die gesamteschedule.*-Gruppe, Issue-/PR-/ Repo-Sync-Ops). Nutze dies, wenn dein lokales Dev Workflows und Skripte tatsächlich ausführen soll, nicht nur zuschauen.
Erstelle das Token über die Management-API. Die Antwort enthält den Klartext-Bearer genau einmal — er ist nicht erneut lesbar:
Terminal window curl -sS -X POST \"$SUPACLOUD_URL/api/management/v1/workspaces/$WORKSPACE_SLUG/api-tokens" \-H "Authorization: Bearer $BOOTSTRAP_MGMT_TOKEN" \-H "Content-Type: application/json" \-d '{ "label": "local-ide-mcp", "scopes": ["mcp:ops"] }'Das zurückgegebene Feld
token(beginnt mitscmt_) ist dein MCP-Bearer. Hinterlege ihn in$SC_MCP_TOKEN. -
Deinen MCP-Client auf das Gateway zeigen lassen.
Der Transport ist Streamable HTTP, stateless — ein einziger Endpoint, keine
Mcp-Session-Id, jeder Request aus dem Bearer selbsttragend. Die meisten Clients erwarten eine HTTP-MCP-Server-URL plus einen statischenAuthorization-Header. Beispiel für eine lokale IDE-/Agent-MCP-Konfiguration:{"mcpServers": {"supacloud": {"url": "https://your-instance.example.com/api/mcp","headers": {"Authorization": "Bearer scmt_your_token_here"}}}}Das Gateway gibt in seinem
initialize-Ergebnis die Protokollversion2025-06-18und einetools-Capability an. -
Die für dein Token erreichbaren Tools auflisten.
tools/listliefert nur die Tools auf der externen Fläche für deinen Scope. Ein Read-Token sieht das Read-Tier; ein Ops-Token zusätzlich Ops + Script-Run:Terminal window curl -sS -X POST "$SUPACLOUD_URL/api/mcp" \-H "Authorization: Bearer $SC_MCP_TOKEN" \-H "Content-Type: application/json" \-d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'{"jsonrpc": "2.0","id": 1,"result": {"tools": [{ "name": "run.list", "description": "…", "inputSchema": { … }, "outputSchema": { … } }]}} -
Ein Tool aufrufen.
tools/callnimmt einennameund ein optionalesarguments-Objekt. Ein Read-Beispiel (listet die letzten Runs im Workspace):Terminal window curl -sS -X POST "$SUPACLOUD_URL/api/mcp" \-H "Authorization: Bearer $SC_MCP_TOKEN" \-H "Content-Type: application/json" \-d '{"jsonrpc": "2.0","id": 2,"method": "tools/call","params": { "name": "run.list", "arguments": {} }}'Ein erfolgreicher Aufruf liefert ein Ergebnis, dessen
structuredContentdie typisierte Tool-Ausgabe ist (dercontent-Text-Block ist derselbe Wert als JSON-String):{"jsonrpc": "2.0","id": 2,"result": {"content": [ { "type": "text", "text": "{\"runs\":[…]}" } ],"structuredContent": { "runs": [ … ] },"isError": false}}Ein Ops-Beispiel (braucht ein
mcp:ops-Token) triggert einen Workflow:Terminal window curl -sS -X POST "$SUPACLOUD_URL/api/mcp" \-H "Authorization: Bearer $SC_MCP_TOKEN" \-H "Content-Type: application/json" \-d '{"jsonrpc": "2.0","id": 3,"method": "tools/call","params": { "name": "workflow.trigger", "arguments": { "workflow_id": "…" } }}'
Was dein Token erreichen kann
Abschnitt betitelt „Was dein Token erreichen kann“Die Fläche ist ein positiver Filter
(services/mcp/external.rs::external_tool_allowed), der auf tools/list und
tools/call greift, zusätzlich zur geerbten Tier-Allowlist:
| Scope | Erreichbare Tools |
|---|---|
mcp:read |
Read-Tier — run.list, run.get, run.events, workflow.list/get, project.list, issue.list/get, Conversation-Reads, App-Build-/Migration-Reads, memory.list_closeouts |
mcp:ops (ergänzt) |
Ops + ScriptRun — workflow.trigger, script.run, die gesamte schedule.*-Gruppe (create/update/pause/resume), Issue-/PR-/Repo-Sync-Ops |
Einige Read-Tier-Tools sind bewusst ausgeschlossen, weil sie eine
Agent-Identität brauchen, die ein M2M-Token nicht hat: memory.create
(profil-geguardeter Write) und permission.list. Auf der Ops-Fläche sind
permission.grant / permission.revoke aus demselben Grund ausgeschlossen.
Was es bewusst NICHT tut
Abschnitt betitelt „Was es bewusst NICHT tut“- Der Deploy-Tier ist nie erreichbar.
app.deploy/app.migration.applysind durch den Surface-Filter und das externe Allowlist-Set ausgeschlossen, und sie bräuchten das HMAC-Confirmation-Secret, das ein externer Caller nie hat. Deploy bleibt im Agent-Runner. - Kein Token-Passthrough. Jeder Tool-Call läuft über SupaClouds interne
services::*— die als eigener OAuth-Client gegen GitHub/Linear/etc. agieren. Deinscmt_-Token verlässt SupaCloud nie. - Es ist kein OAuth-Provider. Es gibt keinen
/token-Endpoint, kein JWKS, kein Audience-Modell. Voller OAuth 2.1 (DCR/PRM/PKCE) ist ein aufgeschobenes Authelia-Arbeitspaket, das dem Gateway vorgelagert ist — nicht in SupaCloud gebaut.
Rate-Limits
Abschnitt betitelt „Rate-Limits“Die externe Identität ist die Token-Row, daher keyen die Limits auf das Token, nicht auf einen User:
- Ein Per-Identität-In-Process-Burst-Limit verhindert, dass ein Token das Gateway flutet.
- Ein Per-Identität-Stunden-Ops-Cap — das externe Analog des Profil-Caps —
zählt die eigenen Ops-Audit-Rows des Tokens im rollenden Stundenfenster. Default
30, einstellbar über
AGENT_MCP_EXTERNAL_OPS_HOURLY_LIMIT. Über dem Cap liefert ein Ops-Call einenForbidden-Tool-Fehler. - Ein Ops-Call reserviert zusätzlich einen Slot gegen den geteilten Workspace-Tages-Ops-Cap.
So kann das Token eines einzelnen Entwicklers das Workspace-Ops-Budget nicht alleine leersaugen.
Fehlerbehebung
Abschnitt betitelt „Fehlerbehebung“401 Unauthorized— fehlender oder leererAuthorization: Bearer-Header oder ein Token, das nicht auflöst.403 Forbiddenauf Transport-Ebene — eines von: die Instanz ist nicht Enterprise-Edition (mcp_gateway_externaldeaktiviert); das Token ist global/Bootstrap, nicht workspace-scoped; oder ein vorhandenerOrigin-Header passt nicht zum Control-Plane-Host (der DNS-Rebind-Guard — ein abwesender Origin, wie ihn ein Server-to-Server-Client sendet, ist erlaubt).- JSON-RPC-Fehler
-32601„tool not available on the external surface“ — das Tool liegt nicht auf der Fläche deines Scopes. Ein Read-Token, das ein Ops-Tool aufruft, oder jeder Caller, der ein ausgeschlossenes Tool trifft (Deploy,memory.create,permission.*), landet hier. Präge einmcp:ops-Token, wenn du den Ops-Tier brauchst. - JSON-RPC-Fehler
-32700„parse error“ — der Request-Body war kein JSON-Objekt. "isError": truein einemtools/call-Ergebnis — der Aufruf lief, aber das Tool schlug fehl (HTTP ist weiterhin200). Server-Klassen-Detail (SQL/Vault/intern) wird auf eine generische Nachricht redigiert; der Roh-Fehler wird server-seitig geloggt.- Ops-Call als
Forbiddenabgelehnt — du hast den Stunden-Ops-Cap (Default 30) oder den Workspace-Tages-Ops-Cap erreicht.
Siehe auch
Abschnitt betitelt „Siehe auch“server/src/interfaces/http/external_mcp.rs— derPOST /api/mcp-Handlerserver/src/services/mcp/external.rs— derexternal_tool_allowed-Surface-Filter- ADR 0054 — das Secure-External-MCP-Exposure-Design