Add files via upload

This commit is contained in:
公明
2025-11-15 21:37:24 +08:00
committed by GitHub
parent 8cd2536ccb
commit b5b8a2cb14
5 changed files with 165 additions and 40 deletions
+14 -12
View File
@@ -465,24 +465,26 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
// 在循环外部统一更新,避免重复调用
h.externalMCPMgr.LoadConfigs(&h.config.ExternalMCP)
// 处理MCP连接状态
// 处理MCP连接状态(异步启动,避免阻塞)
for mcpName := range externalMCPToolMap {
cfg := h.config.ExternalMCP.Servers[mcpName]
// 如果MCP需要启用,确保客户端已启动
if cfg.ExternalMCPEnable {
// 启动外部MCP(如果未启动)
// 启动外部MCP(如果未启动)- 异步执行,避免阻塞
client, exists := h.externalMCPMgr.GetClient(mcpName)
if !exists || !client.IsConnected() {
if err := h.externalMCPMgr.StartClient(mcpName); err != nil {
h.logger.Warn("启动外部MCP失败",
zap.String("mcp", mcpName),
zap.Error(err),
)
} else {
h.logger.Info("启动外部MCP",
zap.String("mcp", mcpName),
)
}
go func(name string) {
if err := h.externalMCPMgr.StartClient(name); err != nil {
h.logger.Warn("启动外部MCP失败",
zap.String("mcp", name),
zap.Error(err),
)
} else {
h.logger.Info("启动外部MCP",
zap.String("mcp", name),
)
}
}(mcpName)
}
}
}
+20 -6
View File
@@ -56,11 +56,16 @@ func (h *ExternalMCPHandler) GetExternalMCPs(c *gin.Context) {
}
toolCount := toolCounts[name]
errorMsg := ""
if status == "error" {
errorMsg = h.manager.GetError(name)
}
result[name] = ExternalMCPResponse{
Config: cfg,
Status: status,
ToolCount: toolCount,
Error: errorMsg,
}
}
@@ -102,10 +107,17 @@ func (h *ExternalMCPHandler) GetExternalMCP(c *gin.Context) {
}
}
// 获取错误信息
errorMsg := ""
if status == "error" {
errorMsg = h.manager.GetError(name)
}
c.JSON(http.StatusOK, ExternalMCPResponse{
Config: cfg,
Status: status,
ToolCount: toolCount,
Error: errorMsg,
})
}
@@ -238,7 +250,7 @@ func (h *ExternalMCPHandler) StartExternalMCP(c *gin.Context) {
return
}
// 启动客户端(这可能会花费一些时间
// 启动客户端(立即创建客户端并设置状态为connecting,实际连接在后台进行
h.logger.Info("开始启动外部MCP", zap.String("name", name))
if err := h.manager.StartClient(name); err != nil {
h.logger.Error("启动外部MCP失败", zap.String("name", name), zap.Error(err))
@@ -249,16 +261,17 @@ func (h *ExternalMCPHandler) StartExternalMCP(c *gin.Context) {
return
}
// 获取连接状态
// 获取客户端状态(应该是connecting)
client, exists := h.manager.GetClient(name)
status := "disconnected"
status := "connecting"
if exists {
status = client.GetStatus()
}
h.logger.Info("外部MCP启动完成", zap.String("name", name), zap.String("status", status))
// 立即返回,不等待连接完成
// 客户端会在后台异步连接,用户可以通过状态查询接口查看连接状态
c.JSON(http.StatusOK, gin.H{
"message": "外部MCP启动完成",
"message": "外部MCP启动请求已提交,正在后台连接中",
"status": status,
})
}
@@ -504,7 +517,8 @@ type AddOrUpdateExternalMCPRequest struct {
// ExternalMCPResponse 外部MCP响应
type ExternalMCPResponse struct {
Config config.ExternalMCPServerConfig `json:"config"`
Status string `json:"status"` // "connected", "disconnected", "disabled", "error"
Status string `json:"status"` // "connected", "disconnected", "disabled", "error", "connecting"
ToolCount int `json:"tool_count"` // 工具数量
Error string `json:"error,omitempty"` // 错误信息(仅在status为error时存在)
}
+112 -21
View File
@@ -22,6 +22,7 @@ type ExternalMCPManager struct {
storage MonitorStorage // 可选的持久化存储
executions map[string]*ToolExecution // 执行记录
stats map[string]*ToolStats // 工具统计信息
errors map[string]string // 错误信息
mu sync.RWMutex
}
@@ -39,6 +40,7 @@ func NewExternalMCPManagerWithStorage(logger *zap.Logger, storage MonitorStorage
storage: storage,
executions: make(map[string]*ToolExecution),
stats: make(map[string]*ToolStats),
errors: make(map[string]string),
}
}
@@ -117,12 +119,12 @@ func (m *ExternalMCPManager) StartClient(name string) error {
// 检查是否已经有连接的客户端
m.mu.RLock()
_, hasClient := m.clients[name]
existingClient, hasClient := m.clients[name]
m.mu.RUnlock()
if hasClient {
// 检查客户端是否已连接
if client, ok := m.GetClient(name); ok && client.IsConnected() {
if existingClient.IsConnected() {
// 客户端已连接,直接返回成功(目标状态已达成)
// 更新配置为启用(确保配置一致)
m.mu.Lock()
@@ -132,22 +134,55 @@ func (m *ExternalMCPManager) StartClient(name string) error {
return nil
}
// 如果有客户端但未连接,先关闭
if client, ok := m.GetClient(name); ok {
client.Close()
m.mu.Lock()
delete(m.clients, name)
m.mu.Unlock()
}
existingClient.Close()
m.mu.Lock()
delete(m.clients, name)
m.mu.Unlock()
}
// 更新配置为启用
m.mu.Lock()
serverCfg.ExternalMCPEnable = true
m.configs[name] = serverCfg
// 清除之前的错误信息(重新启动时)
delete(m.errors, name)
m.mu.Unlock()
// 连接客户端
return m.connectClient(name, serverCfg)
// 立即创建客户端并设置为"connecting"状态,这样前端可以立即看到状态
client := m.createClient(serverCfg)
if client == nil {
return fmt.Errorf("无法创建客户端:不支持的传输模式")
}
// 设置状态为connecting
m.setClientStatus(client, "connecting")
// 立即保存客户端,这样前端查询时就能看到"connecting"状态
m.mu.Lock()
m.clients[name] = client
m.mu.Unlock()
// 在后台异步进行实际连接
go func() {
if err := m.doConnect(name, serverCfg, client); err != nil {
m.logger.Error("连接外部MCP客户端失败",
zap.String("name", name),
zap.Error(err),
)
// 连接失败,设置状态为error并保存错误信息
m.setClientStatus(client, "error")
m.mu.Lock()
m.errors[name] = err.Error()
m.mu.Unlock()
} else {
// 连接成功,清除错误信息
m.mu.Lock()
delete(m.errors, name)
m.mu.Unlock()
}
}()
return nil
}
// StopClient 停止客户端
@@ -166,6 +201,9 @@ func (m *ExternalMCPManager) StopClient(name string) error {
delete(m.clients, name)
}
// 清除错误信息
delete(m.errors, name)
// 更新配置为禁用
serverCfg.ExternalMCPEnable = false
m.configs[name] = serverCfg
@@ -182,6 +220,14 @@ func (m *ExternalMCPManager) GetClient(name string) (ExternalMCPClient, bool) {
return client, exists
}
// GetError 获取错误信息
func (m *ExternalMCPManager) GetError(name string) string {
m.mu.RLock()
defer m.mu.RUnlock()
return m.errors[name]
}
// GetAllTools 获取所有外部MCP的工具
func (m *ExternalMCPManager) GetAllTools(ctx context.Context) ([]Tool, error) {
m.mu.RLock()
@@ -543,10 +589,8 @@ func (m *ExternalMCPManager) GetToolCounts() map[string]int {
return result
}
// connectClient 连接客户端(异步
func (m *ExternalMCPManager) connectClient(name string, serverCfg config.ExternalMCPServerConfig) error {
var client ExternalMCPClient
// createClient 创建客户端(不连接
func (m *ExternalMCPManager) createClient(serverCfg config.ExternalMCPServerConfig) ExternalMCPClient {
timeout := time.Duration(serverCfg.Timeout) * time.Second
if timeout <= 0 {
timeout = 30 * time.Second
@@ -561,29 +605,77 @@ func (m *ExternalMCPManager) connectClient(name string, serverCfg config.Externa
} else if serverCfg.URL != "" {
transport = "http"
} else {
return fmt.Errorf("无法确定传输模式: 需要指定command或url")
return nil
}
}
switch transport {
case "http":
if serverCfg.URL == "" {
return fmt.Errorf("HTTP模式需要URL")
return nil
}
client = NewHTTPMCPClient(serverCfg.URL, timeout, m.logger)
return NewHTTPMCPClient(serverCfg.URL, timeout, m.logger)
case "stdio":
if serverCfg.Command == "" {
return fmt.Errorf("stdio模式需要command")
return nil
}
client = NewStdioMCPClient(serverCfg.Command, serverCfg.Args, timeout, m.logger)
return NewStdioMCPClient(serverCfg.Command, serverCfg.Args, timeout, m.logger)
default:
return fmt.Errorf("不支持的传输模式: %s", transport)
return nil
}
}
// doConnect 执行实际连接
func (m *ExternalMCPManager) doConnect(name string, serverCfg config.ExternalMCPServerConfig, client ExternalMCPClient) error {
timeout := time.Duration(serverCfg.Timeout) * time.Second
if timeout <= 0 {
timeout = 30 * time.Second
}
// 初始化连接
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if err := client.Initialize(ctx); err != nil {
return err
}
m.logger.Info("外部MCP客户端已连接",
zap.String("name", name),
)
return nil
}
// setClientStatus 设置客户端状态(通过类型断言)
func (m *ExternalMCPManager) setClientStatus(client ExternalMCPClient, status string) {
switch c := client.(type) {
case *HTTPMCPClient:
c.setStatus(status)
case *StdioMCPClient:
c.setStatus(status)
}
}
// connectClient 连接客户端(异步)- 保留用于向后兼容
func (m *ExternalMCPManager) connectClient(name string, serverCfg config.ExternalMCPServerConfig) error {
client := m.createClient(serverCfg)
if client == nil {
return fmt.Errorf("无法创建客户端:不支持的传输模式")
}
// 设置状态为connecting
m.setClientStatus(client, "connecting")
// 初始化连接
timeout := time.Duration(serverCfg.Timeout) * time.Second
if timeout <= 0 {
timeout = 30 * time.Second
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if err := client.Initialize(ctx); err != nil {
m.logger.Error("初始化外部MCP客户端失败",
zap.String("name", name),
@@ -599,7 +691,6 @@ func (m *ExternalMCPManager) connectClient(name string, serverCfg config.Externa
m.logger.Info("外部MCP客户端已连接",
zap.String("name", name),
zap.String("transport", transport),
)
return nil