MCP Marketplace
Der MCP Marketplace ermöglicht die Installation, Aktivierung und das Scoping externer MCP-Server aus einem kuratierten Katalog. MCP-Server stellen Tools bereit, die der ReAct-Agent während der Chats aufrufen kann, wodurch die Fähigkeiten ohne Code erweit…
Der MCP Marketplace ermöglicht die Installation, Aktivierung und das Scoping externer MCP-Server aus einem kuratierten Katalog. MCP-Server stellen Tools bereit, die der ReAct-Agent während der Chats aufrufen kann, wodurch die Fähigkeiten ohne Code erweitert werden.
Das System umspannt: Prisma-Modelle (McpCatalogEntry, MCPConnection, ChatMCPPin), Routes (marketplace.ts, mcp.ts), Agent-Skill-Registry (skills.ts), Services (Health-Check-Scheduler, DLP-Filter, Audit-Logging).
Konzepte
- `McpCatalogEntry` - Katalog-Template (27 geseedete Einträge: 12 Platzhalter + 15 kuratierte). Felder:
name,url,transportType(sse/streamable-http),headers(JSON-String),description,category,version,author,verificationTier(official/verified_community/unverified),healthStatus(healthy/stale/down),lastHealthCheck,lastHealthError,lastCommitDate,consecutiveFailures. - `MCPConnection` - Workspace-scoped Verbindung.
source(manual/marketplace),catalogEntryId(FK wenn aus dem Marketplace),enabled,headers(JSON-String),workspaceId/projectId. - `ChatMCPPin` - Scoping pro Chat.
@@unique([chatId, connectionId]). Hard-Deleted beim Unpin.
Katalog (Browse + Install)
Das Browse (Liste und Detail) erfordert nur JWT-Authentifizierung; Schreiboperationen erfordern authMiddleware + requireAdmin. Das Frontend filtert Search/Category clientseitig.
| Methode | Path | Auth | Hinweis |
|---|---|---|---|
| GET | /api/mcp-marketplace | JWT | Liste; Query ?workspaceId (ergänzt isInstalled) |
| GET | /api/mcp-marketplace/:entryId | JWT | Entry-Detail |
| POST | /api/mcp-marketplace | JWT + admin | Katalog-Eintrag erstellen |
| POST | /api/mcp-marketplace/:entryId/install | JWT + admin | Im Workspace installieren |
| POST | /api/mcp-marketplace/:entryId/uninstall | JWT + admin | Deinstallieren |
Install Flow (marketplace.ts:165)
- Validate
installMcpServerSchema({ workspaceId: uuid, name?, headers? }); Override-Header werden write-seitig mitmcpHeadersSchemavalidiert (D-12: Hop-by-Hop-Blocklist, Name-Regex, Size Limits). - Check Entry existiert (404), nicht bereits installiert (409, Filter
source: "marketplace"- eine manuelle Verbindung mit derselbencatalogEntryIdblockiert nicht). - Erstellt
MCPConnection:source="marketplace",catalogEntryId,url/transportTypeaus dem Katalog kopiert,enabled=true,name = override || catalog.name. logEvent("mcp_connection", ..., "mcp.installed", ...).- Fire-and-forget
connectMCPServer(connection.id)- Fehler wird geloggt, nicht propagiert (201 wird trotzdem zurückgegeben).
Uninstall Flow (marketplace.ts:291)
- Findet
MCPConnectionüber{ catalogEntryId, workspaceId, source: "marketplace" }(404 wenn nicht). disconnectMCPServer+unregisterSkillsForConnection(entfernt Skills mit Präfixmcp_<conn>_).- Hard Delete
MCPConnection(kein Soft Delete). logEvent("mcp.uninstalled").
Re-Install = Install Flow erneut ausführen (neue MCPConnection mit neuer ID).
Manuelle Verbindungen (CRUD)
/api/mcp-connections (mcp.ts, authMiddleware + requireAdmin): GET, GET /statuses (live aus der activeConnections Map, nicht der DB), POST erstellt, PUT /:id (Auto-Disconnect/Reconnect wenn enabled), DELETE /:id, POST /:id/toggle, POST /:id/test (10s Timeout, gibt { success, toolCount?, error? } zurück).
Marketplace-installierte Verbindungen sind auf CRUD-Ebene nicht von manuellen zu unterscheiden - das Feld source differenziert die Herkunft.
MCP Client (agent/mcpClient.ts)
connectMCPServer(connectionId)(:233): ensureConnected Cache-Hit → Read-Side-Header-Validierung (mcpHeadersSchemaD-12), Transport-Fallback D-09 (streamable-httpprimär → 4xx → SSE-Fallback;ssedeklariert = nur SSE; 5xx triggert keinen Fallback),Client.listTools()→ registriert jedes Tool als Skillmcp_<connectionId>_<toolName>(UUID-Präfix kollisionsfrei).- Per-Connection-Mutex
withConnectionLock. activeConnections: Map<connectionId, MCPConnectionState>(nicht persistiert, Rebuild beim Restart; derscopeWorkspace/Project wird zur Connect-Zeit erfasst für den D-14-Filter).disconnectMCPServer(:363): delete-first + unregister +client.close().shutdownMCPConnectionsfür den Graceful Shutdown.resolveMcpSourceName(toolName)→ human-readable Name fürmcpSourcesSSE.
Per-Chat-Pinning
Die Pins erlauben es, die MCP-Verbindungen einzuschränken, die einer bestimmten Chat Tools bereitstellen.
/api/chats/:chatId/pins (mcpPins.ts): GET, POST (createMcpPinSchema), DELETE /:pinId.
Auflösung (agent/skills.ts:136 resolveSkillsForChat):
- Kein Pin → alle MCP-Verbindungen enabled des Workspace stellen Skills bereit.
- Pins vorhanden → filtert Verbindungen pinned AND enabled AND derselbe Workspace (globale beide-null inklusive; project-scoped ausgeschlossen).
- Alle gepinnten deaktiviert/out-of-scope → Fallback Workspace-Defaults + Warn-Log.
- Union MCP-02 (strict, D-04): Builtin + Pinned-MCP-Skills + Union mit den aktiven workspace-scoped Tools (Pins entfernen nie Tools - sie fügen nur hinzu).
Health Check
services/mcpHealthCheckJob.ts - pg-boss Cron 30-min (initMCPHealthCheckScheduler() aus src/index.ts; */30 * * * *, kein Fallback-Timer wenn pg-boss unavailable - D-02). Loopt über die installierten + enabled Verbindungen mit catalogEntryId: Ping url mit exponentiellem Retry (1s/2s/4s, Timeout 10s), aktualisiert healthStatus (healthy / stale beim 1.-2. Fehler / down ab dem 3.), lastHealthCheck, lastHealthError, consecutiveFailures. Nicht blockierend: Stale/Down-Einträge bleiben mit Warning-Badge sichtbar; der Reset beginnt bei einem erfolgreichen Ping.
Trust Layer (Verification Tier)
verificationTier ist Seed-Data-Only (nicht zur Runtime geschrieben):
- official - vom Projekt Simmetric Chat gepflegt.
- verified_community - von den Maintainern freigegeben.
- unverified - Community, nicht reviewt.
lastCommitDate = Aktualitätsindikator. Die Tiers sind informativ (sie blockieren die Installation nicht), werden aber als Badges gerendert. Die Installation von unverified/down-Einträgen erfolgt auf Risiko des Admins.
Audit Logging
Alle Operationen loggen via eventLogService.logEvent mit entityType = "mcp_connection":
| Aktion | Event Action |
|---|---|
| Install aus Marketplace | mcp.installed |
| Uninstall aus Marketplace | mcp.uninstalled |
| Enable Connection | mcp.enabled |
| Disable Connection | mcp.disabled |
| Delete Connection | mcp.deleted |
In Community laufen die Events über logEvent (Schreib-No-op ohne das Enterprise-Plugin, Webhook-Dispatch trotzdem aktiv); mit audit_log_immutable (Enterprise) werden die Events in das unveränderliche Audit Log geschrieben. Filtere mit entityType = "mcp_connection" für den vollständigen Audit Trail.
mcpSources im SSE
Das SSE done enthält mcpSources: string[] - Namen der MCP-Verbindungen, deren Tools aufgerufen wurden. Abgeleitet aus dem Präfix des Tool Calls (mcp_<conn>_<tool>) via resolveMcpSourceName. Das Frontend zeigt die Source-Chips an der Nachricht; der Widget-Proxy relayt das Event byte-verbatim, sodass die Daten clientseitig verfügbar bleiben.
Verwendung (Admin)
- Settings → MCP Connections (Unter-Sektion Advanced) oder /mcp-marketplace (Admin/Superuser).
- Katalog durchstöbern (Search, Category Filter, Tier-/Health-Badges - Client-seitige Filter).
- In einem Workspace installieren → "Installed"-Badge + Kontextmenü Uninstall.
- (Optional) Spezifische Tools an eine Chat pinnen via
McpPinnerPopoverim Chat-Header. - Verbindungstest (
POST /:id/test) zum Prüfen des Live-toolCount.
Erweitern
- Neuer Catalog Entry:
POST /api/mcp-marketplace(Admin) oder direktes Seed in Prisma (seedCatalogEntries, idempotenter Upsert - Runtime-Felder wieinstallCountwerden beim Re-Seed nie überschrieben). - Neuer Transport:
buildTransporterweitern (mcpClient.ts:136) +TransportKind. - Custom Scope:
getMCPToolsForWorkspace(workspaceId)filtert nachscope.workspaceId(global inklusive).
Cross-Link
- Endpoints: 04 - API Reference
- Agent Loop: 05 - Feature Guide
- License/Audit-Flag: 03 - Configuration / 08 - Administration