feat: add Go MCP server list API (#15253)

## What
#15240 
Implements `GET /api/v1/mcp/servers` in the Go API server.

## Changes

- Added MCP server DAO list query with tenant scoping.
- Added MCP service response wrapper.
- Added MCP handler for list request parsing and response formatting.
- Wired `GET /api/v1/mcp/servers` under authenticated `/api/v1` routes.
- Initialized MCP service and handler in the Go server startup.
- update_time and update_date now both map to update_date
- create_time and create_date now both map to create_date
- default ordering now returns create_date
## API Behavior

Matches the Python endpoint behavior:

- Requires authenticated user.
- Lists MCP servers for the current user tenant.
- Supports `keywords`.
- Supports `mcp_id` and repeated/comma-separated `mcp_ids`.
- Supports `page`, `page_size`, `orderby`, and `desc`.
- Returns:

```json
{
  "code": 0,
  "message": "success",
  "data": {
    "mcp_servers": [],
    "total": 0
  }
}
```
This commit is contained in:
Alexander Laurent
2026-06-01 15:37:05 -10:00
committed by GitHub
parent 3aea80f5f5
commit 1748723971
6 changed files with 371 additions and 0 deletions

View File

@@ -17,7 +17,10 @@
package handler
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
@@ -25,6 +28,12 @@ import (
"ragflow/internal/service"
)
const (
defaultMCPServerPage = 0
defaultMCPServerPageSize = 0
maxMCPServerPageSize = 100
)
// MCPHandler handles MCP server requests.
type MCPHandler struct {
mcpService *service.MCPService
@@ -64,6 +73,51 @@ func (h *MCPHandler) CreateMCPServer(c *gin.Context) {
})
}
// ListMCPServers lists MCP servers for the current user.
func (h *MCPHandler) ListMCPServers(c *gin.Context) {
user, errorCode, errorMessage := GetUser(c)
if errorCode != common.CodeSuccess {
jsonError(c, errorCode, errorMessage)
return
}
page, err := parseMCPServerPage(c.Query("page"))
if err != nil {
jsonError(c, common.CodeDataError, err.Error())
return
}
pageSize, err := parseMCPServerPageSize(c.Query("page_size"))
if err != nil {
jsonError(c, common.CodeDataError, err.Error())
return
}
orderby := c.DefaultQuery("orderby", "create_time")
desc := strings.ToLower(c.DefaultQuery("desc", "true")) != "false"
keywords := c.Query("keywords")
mcpIDs := getMCPIDsFromQuery(c)
result, code, err := h.mcpService.ListMCPServers(user.ID, mcpIDs, keywords, page, pageSize, orderby, desc)
if err != nil {
if code == common.CodeServerError {
c.JSON(http.StatusInternalServerError, gin.H{
"code": code,
"message": err.Error(),
"data": nil,
})
return
}
jsonError(c, code, err.Error())
return
}
c.JSON(http.StatusOK, gin.H{
"code": common.CodeSuccess,
"message": "success",
"data": result,
})
}
// DeleteMCPServer deletes an MCP server for the current user.
func (h *MCPHandler) DeleteMCPServer(c *gin.Context) {
user, errorCode, errorMessage := GetUser(c)
@@ -84,3 +138,46 @@ func (h *MCPHandler) DeleteMCPServer(c *gin.Context) {
"data": result,
})
}
func parseMCPServerPage(value string) (int, error) {
if value == "" {
return defaultMCPServerPage, nil
}
page, err := strconv.Atoi(value)
if err != nil {
return 0, fmt.Errorf("page must be an integer")
}
return page, nil
}
func parseMCPServerPageSize(value string) (int, error) {
if value == "" {
return defaultMCPServerPageSize, nil
}
pageSize, err := strconv.Atoi(value)
if err != nil {
return 0, fmt.Errorf("page_size must be an integer")
}
if pageSize > maxMCPServerPageSize {
return 0, fmt.Errorf("page_size must be less than or equal to %d", maxMCPServerPageSize)
}
return pageSize, nil
}
func getMCPIDsFromQuery(c *gin.Context) []string {
rawValues := c.QueryArray("mcp_ids")
if len(rawValues) == 0 {
rawValues = []string{c.Query("mcp_id")}
}
ids := make([]string, 0)
for _, rawValue := range rawValues {
for _, item := range strings.Split(rawValue, ",") {
id := strings.TrimSpace(item)
if id != "" {
ids = append(ids, id)
}
}
}
return ids
}