From c7d66f89ab1ee78a54d6cf9f109fb6c847bf38d7 Mon Sep 17 00:00:00 2001 From: BBQ Date: Fri, 13 Feb 2026 01:11:40 +0800 Subject: [PATCH] feat(bots): MCP add/import merge, batch select and batch delete/export --- internal/handlers/mcp.go | 41 ++ internal/mcp/connections.go | 21 + .../web/src/pages/bots/components/bot-mcp.vue | 620 ++++++++++++------ 3 files changed, 465 insertions(+), 217 deletions(-) diff --git a/internal/handlers/mcp.go b/internal/handlers/mcp.go index 78c15d90..3d1e1dd7 100644 --- a/internal/handlers/mcp.go +++ b/internal/handlers/mcp.go @@ -42,6 +42,7 @@ func (h *MCPHandler) Register(e *echo.Echo) { ops := e.Group("/bots/:bot_id/mcp-ops") ops.PUT("/import", h.Import) ops.GET("/export", h.Export) + ops.POST("/batch-delete", h.BatchDelete) } // List godoc @@ -252,6 +253,46 @@ func (h *MCPHandler) Import(c echo.Context) error { return c.JSON(http.StatusOK, mcp.ListResponse{Items: items}) } +// BatchDeleteRequest is the body for batch delete. +type BatchDeleteRequest struct { + IDs []string `json:"ids"` +} + +// BatchDelete godoc +// @Summary Batch delete MCP connections +// @Description Delete multiple MCP connections by IDs. +// @Tags mcp +// @Param payload body BatchDeleteRequest true "IDs to delete" +// @Success 204 "No Content" +// @Failure 400 {object} ErrorResponse +// @Failure 403 {object} ErrorResponse +// @Failure 500 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp-ops/batch-delete [post] +func (h *MCPHandler) BatchDelete(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + if botID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot id is required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + var req BatchDeleteRequest + if err := c.Bind(&req); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + if len(req.IDs) == 0 { + return echo.NewHTTPError(http.StatusBadRequest, "ids are required") + } + if err := h.service.BatchDelete(c.Request().Context(), botID, req.IDs); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + return c.NoContent(http.StatusNoContent) +} + // Export godoc // @Summary Export MCP connections // @Description Export all MCP connections for a bot in standard mcpServers format. diff --git a/internal/mcp/connections.go b/internal/mcp/connections.go index 01c9f82b..206e8951 100644 --- a/internal/mcp/connections.go +++ b/internal/mcp/connections.go @@ -304,6 +304,27 @@ func (s *ConnectionService) Delete(ctx context.Context, botID, id string) error }) } +// BatchDelete removes multiple MCP connections by IDs. Invalid IDs are skipped; at least one must succeed for no error. +func (s *ConnectionService) BatchDelete(ctx context.Context, botID string, ids []string) error { + if s.queries == nil { + return fmt.Errorf("mcp queries not configured") + } + if len(ids) == 0 { + return nil + } + var lastErr error + for _, id := range ids { + id = strings.TrimSpace(id) + if id == "" { + continue + } + if err := s.Delete(ctx, botID, id); err != nil { + lastErr = err + } + } + return lastErr +} + func normalizeMCPConnection(row sqlc.McpConnection) (Connection, error) { config, err := decodeMCPConfig(row.Config) if err != nil { diff --git a/packages/web/src/pages/bots/components/bot-mcp.vue b/packages/web/src/pages/bots/components/bot-mcp.vue index e4330d81..989b654d 100644 --- a/packages/web/src/pages/bots/components/bot-mcp.vue +++ b/packages/web/src/pages/bots/components/bot-mcp.vue @@ -20,7 +20,7 @@ v-if="loading" class="mr-1.5" /> - {{ $t('bots.container.actions.refresh') }} + {{ $t('common.refresh') }} - + + + + + +
- + - -
- - {{ editingItem ? $t('common.edit') : $t('common.add') }} MCP Server - - -
-
- - -
- -
- - -
- -
- - -
- -
- - - - - - - - -
- -
- - - - - - - - -
- -
- - -
- -
- - - - - - - - -
- -
- - -
- -
- - -
-
- - - - - - - -
-
-
- - - - {{ $t('common.import') }} mcpServers + {{ editingItem ? $t('common.edit') : $t('common.add') }} MCP Server -
-

- {{ $t('mcp.importHint') }} -

-