diff --git a/internal/http/mcp.go b/internal/http/mcp.go index 1faa95dd..a6eaa0b1 100644 --- a/internal/http/mcp.go +++ b/internal/http/mcp.go @@ -61,6 +61,9 @@ func (h *MCPHandler) RegisterRoutes(mux *http.ServeMux) { // Test connection (no save) mux.HandleFunc("POST /v1/mcp/servers/test", h.auth(h.handleTestConnection)) + // Reconnect (evict pooled connection so next use re-discovers tools) + mux.HandleFunc("POST /v1/mcp/servers/{id}/reconnect", h.auth(h.handleReconnectServer)) + // Server tools (runtime-discovered) mux.HandleFunc("GET /v1/mcp/servers/{id}/tools", h.auth(h.handleListServerTools)) @@ -231,3 +234,28 @@ func (h *MCPHandler) handleDeleteServer(w http.ResponseWriter, r *http.Request) emitAudit(h.msgBus, r, "mcp_server.deleted", "mcp_server", id.String()) writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) } + +func (h *MCPHandler) handleReconnectServer(w http.ResponseWriter, r *http.Request) { + locale := store.LocaleFromContext(r.Context()) + id, err := uuid.Parse(r.PathValue("id")) + if err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": i18n.T(locale, i18n.MsgInvalidID, "server")}) + return + } + + srv, err := h.store.GetServer(r.Context(), id) + if err != nil { + writeJSON(w, http.StatusNotFound, map[string]string{"error": i18n.T(locale, i18n.MsgNotFound, "server", id.String())}) + return + } + + if h.poolEvictor != nil { + tid := store.TenantIDFromContext(r.Context()) + h.poolEvictor.Evict(tid, srv.Name) + } + + h.emitCacheInvalidate() + emitAudit(h.msgBus, r, "mcp_server.reconnected", "mcp_server", id.String()) + slog.Info("mcp.server.reconnect_requested", "server", srv.Name, "id", id) + writeJSON(w, http.StatusOK, map[string]string{"status": "reconnected"}) +} diff --git a/ui/desktop/frontend/src/components/settings/mcp/McpServerList.tsx b/ui/desktop/frontend/src/components/settings/mcp/McpServerList.tsx index 22d5f2be..5682ddd5 100644 --- a/ui/desktop/frontend/src/components/settings/mcp/McpServerList.tsx +++ b/ui/desktop/frontend/src/components/settings/mcp/McpServerList.tsx @@ -14,7 +14,7 @@ export function McpServerList() { const { servers, loading, atLimit, fetchServers, createServer, updateServer, deleteServer, - testConnection, listServerTools, + testConnection, reconnectServer, listServerTools, listGrants, grantAgent, revokeAgent, } = useMcpServers() const { agents } = useAgentCrud() @@ -24,6 +24,7 @@ export function McpServerList() { const [deleteTarget, setDeleteTarget] = useState(null) const [grantsServer, setGrantsServer] = useState(null) const [toolsServer, setToolsServer] = useState(null) + const [reconnectingId, setReconnectingId] = useState(null) function openCreate() { setEditServer(null) @@ -163,6 +164,19 @@ export function McpServerList() { {/* Actions */}
+