Back to docs
Guide 07

MCP Marketplace

Install and manage MCP servers.

Il MCP Marketplace permette di installare, abilitare e scoping MCP server esterni da un catalogo curato. Gli MCP server espongono tool che l'agente ReAct può invocare durante le chat, estendendo le capacità senza codice.

Il sistema spanna: modelli Prisma (McpCatalogEntry, MCPConnection, ChatMCPPin), route (marketplace.ts, mcp.ts), agent skill registry (skills.ts), servizi (health-check scheduler, DLP filter, audit logging).

Concetti

  • McpCatalogEntry — template di catalogo (seedato 20-40 entry). Campi: name, description, category, tags, url, transportType (sse/streamable-http), tools, headers, verificationTier (official/verified_community/unverified), healthStatus (healthy/stale/down), installCount, lastCommitDate.
  • MCPConnection — connessione workspace-scoped. source (manual/marketplace), catalogEntryId (FK se da marketplace), enabled, headers (JSON string), workspaceId/projectId.
  • ChatMCPPin — scoping per-chat. PK composita [chatId, mcpConnectionId]. Hard-deleted on unpin.

Catalogo (browse + install)

Tutti gli endpoint /api/mcp-marketplace richiedono authMiddleware + requireAdmin.

MetodoPathNote
GET/api/mcp-marketplaceLista; query ?search, ?category, ?workspaceId (aggiunge isInstalled)
GET/api/mcp-marketplace/:entryIdDettaglio con tools JSON
POST/api/mcp-marketplaceCrea entry di catalogo
POST/api/mcp-marketplace/:entryId/installInstalla nel workspace
POST/api/mcp-marketplace/:entryId/uninstallDisinstalla

Install flow (marketplace.ts:146)

  1. Validate installMcpServerSchema ({ workspaceId: uuid, name?, headers? }).
  2. Check entry esiste (404), non già installato (409).
  3. Crea MCPConnection: source="marketplace", catalogEntryId, url/transportType copiati dal catalogo, enabled=true, name = override || catalog.name.
  4. logEvent("mcp_connection", ..., "mcp.installed", ...).
  5. Fire-and-forget connectMCPServer(connection.id) — fallimento logged, non propagato (201 restituito comunque).

Uninstall flow (marketplace.ts:286)

  1. Trova MCPConnection per { catalogEntryId, workspaceId, source: "marketplace" } (404 se no).
  2. disconnectMCPServer + unregisterSkillsForConnection (rimuove skill prefisso mcp_<conn>_).
  3. Hard delete MCPConnection (no soft delete).
  4. logEvent("mcp.uninstalled").

Re-install = rifai l'install flow (nuovo MCPConnection con nuovo ID).

Connessioni manuali (CRUD)

/api/mcp-connections (mcp.ts, authMiddleware + requireAdmin): GET, GET /statuses (live da activeConnections Map, non DB), POST crea, PUT /:id (auto-disconnect/ reconnect se enabled), DELETE /:id, POST /:id/toggle, POST /:id/test (10s timeout, ritorna { success, toolCount?, error? }).

Le connessioni marketplace-installate sono indistinguibili da quelle manuali a livello CRUD — il campo source differenzia l'origine.

MCP client (agent/mcpClient.ts)

  • connectMCPServer(connectionId) (:223): valida headers (mcpHeadersSchema D-12), transport fallback D-09 (streamable-http primario → 4xx → SSE fallback; sse dichiarato = solo SSE; 5xx non triggera fallback), Client.listTools() → registra ogni tool come skill mcp_<connectionId>_<toolName> (UUID prefix collision-free).
  • Per-connection mutex withConnectionLock.
  • activeConnections: Map<connectionId, MCPConnectionState> (non persistito, rebuild al restart).
  • disconnectMCPServer (:347): delete-first + unregister + client.close().
  • shutdownMCPConnections per graceful shutdown.
  • resolveMcpSourceName(toolName) → nome human-readable per mcpSources SSE.

Pinning per-chat

Le pin permettono di limitare quali connessioni MCP forniscono tool a una specifica chat.

/api/chats/:chatId/pins (mcpPins.ts): GET, POST (createMcpPinSchema), DELETE /:pinId.

Risoluzione (agent/skills.ts:110 resolveSkillsForChat):

  • No pin → tutti i connection MCP enabled del workspace forniscono skill.
  • Pin presenti → filtra connection pinned AND enabled AND stesso workspace.
  • Tutti pinned disabilitati/out-of-scope → fallback workspace defaults + warn log.
  • Union MCP-02: builtin + pinned MCP skill.

Health check

services/mcpHealthCheckJob.ts — Bree job 30-min (initMCPHealthCheckScheduler() da src/index.ts). Per ogni McpCatalogEntry: ping url, aggiorna healthStatus (healthy / stale 1-2 fail / down 3+ fail), lastHealthCheck, lastHealthError, consecutiveFailures. Non bloccante: entry stale/down restano visibili con badge warning.

Trust layer (verification tier)

verificationTier è seed-data-only (non scritto a runtime):

  • official — mantenuto dal progetto Simmetric Chat.
  • verified_community — approvato dai maintainer.
  • unverified — community, non revisionato.

lastCommitDate = indicatore di recenza. I tier sono informativi (non bloccano install) ma renderizzati come badge. L'installazione di entry unverified/down è a rischio dell'admin.

Audit logging

Tutte le operazioni loggano via eventLogService.logEvent con entityType = "mcp_connection":

AzioneEvent action
Install da marketplacemcp.installed
Uninstall da marketplacemcp.uninstalled
Enable connectionmcp.enabled
Disable connectionmcp.disabled

Eventi immutabili quando audit_log_immutable (Enterprise) è attivo. Filtra con entityType = "mcp_connection" per l'audit trail completo.

mcpSources in SSE

L'SSE done include mcpSources: string[] — nomi delle connessioni MCP i cui tool sono stati invocati. Derivato dal prefix del tool call (mcp_<conn>_<tool>). Frontend e widget lo mostrano per informare quali integrazioni hanno contribuito.

Come si usa (admin)

  1. Settings → MCP Connections o /mcp-marketplace (admin/superuser).
  2. Sfoglia catalogo (search, category filter, badge tier/health).
  3. Installa in un workspace → badge "Installed" + menu contestuale Uninstall.
  4. (Opzionale) Pin tool specifici a una chat via McpPinnerPopover nell'header chat.
  5. Test connessione (POST /:id/test) per verificare toolCount live.

Come si estende

  • Nuovo catalog entry: POST /api/mcp-marketplace (admin) o seed diretto in Prisma.
  • Nuovo transport: estendi buildTransport (mcpClient.ts:126) + TransportKind.
  • Scope custom: getMCPToolsForWorkspace(workspaceId) filtra per scope.workspaceId (global inclusi).

Cross-link