Zum Inhalt springen
Farbschema wählenSprache wählen

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.

  • Die Instanz muss die Enterprise-Edition betreiben. Das Gateway ist über das Feature mcp_gateway_external geschützt (fail-closed in interfaces/http/external_mcp.rs); auf einer Community-Instanz liefert jeder Request an /api/mcp ein 403.
  • 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).
  1. 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), inklusive run.list / run.get / run.events.
    • mcp:ops — impliziert mcp:read und ergänzt die Ops- und Script-Run-Tools (workflow.trigger, script.run, die gesamte schedule.*-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 mit scmt_) ist dein MCP-Bearer. Hinterlege ihn in $SC_MCP_TOKEN.

  2. 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 statischen Authorization-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 Protokollversion 2025-06-18 und eine tools-Capability an.

  3. Die für dein Token erreichbaren Tools auflisten.

    tools/list liefert 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": { } }
    ]
    }
    }
  4. Ein Tool aufrufen.

    tools/call nimmt einen name und ein optionales arguments-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 structuredContent die typisierte Tool-Ausgabe ist (der content-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": "…" } }
    }'

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.

  • Der Deploy-Tier ist nie erreichbar. app.deploy / app.migration.apply sind 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. Dein scmt_-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.

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 einen Forbidden-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.

  • 401 Unauthorized — fehlender oder leerer Authorization: Bearer-Header oder ein Token, das nicht auflöst.
  • 403 Forbidden auf Transport-Ebene — eines von: die Instanz ist nicht Enterprise-Edition (mcp_gateway_external deaktiviert); das Token ist global/Bootstrap, nicht workspace-scoped; oder ein vorhandener Origin-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 ein mcp:ops-Token, wenn du den Ops-Tier brauchst.
  • JSON-RPC-Fehler -32700 „parse error“ — der Request-Body war kein JSON-Objekt.
  • "isError": true in einem tools/call-Ergebnis — der Aufruf lief, aber das Tool schlug fehl (HTTP ist weiterhin 200). Server-Klassen-Detail (SQL/Vault/intern) wird auf eine generische Nachricht redigiert; der Roh-Fehler wird server-seitig geloggt.
  • Ops-Call als Forbidden abgelehnt — du hast den Stunden-Ops-Cap (Default 30) oder den Workspace-Tages-Ops-Cap erreicht.