Files
2026-06-12 11:44:19 +08:00

97 lines
3.0 KiB
Go

// mcp_inject.go 构造 session/new 下发的 mcpServers 列表。
//
// 组成:ACW 自家 MCP(http 类型,per-session system token 做 Bearer 认证)+
// AgentKind 上配置的第三方 MCP。能力门控(ACP v1):stdio 是基线直接下发;
// http / sse 需 agent 在 initialize 响应中声明 mcpCapabilities.http / .sse,
// 未声明的条目逐条跳过并记日志——session 照常启动,自家 MCP 仍可由管理员
// 通过配置文件 + ACW_MCP_TOKEN 环境变量引用做静态接入兜底。
package acp
import (
"log/slog"
"sort"
"github.com/google/uuid"
"github.com/yan1h/agent-coding-workflow/internal/acp/handlers"
)
// buildMcpServers 按 agent 能力构造 mcpServers。acwURL / acwToken 任一为空时
// 不注入自家 MCP(如 MCP 模块未配置 public_url)。
func buildMcpServers(specs []McpServerSpec, acwURL, acwToken string, httpOK, sseOK bool,
log *slog.Logger, sessionID uuid.UUID) []any {
out := []any{}
if acwURL != "" && acwToken != "" {
if httpOK {
out = append(out, handlers.McpServerHTTP{
Type: "http", Name: AcwMcpServerName, URL: acwURL,
Headers: []handlers.HttpHeader{{Name: "Authorization", Value: "Bearer " + acwToken}},
})
} else {
log.Warn("acp.mcp_inject.acw_skipped_no_http_capability",
"session_id", sessionID,
"hint", "agent 未声明 mcpCapabilities.http;可在 AgentKind 配置文件中静态引用 ACW_MCP_TOKEN 接入")
}
}
for _, sp := range specs {
switch sp.Type {
case McpStdio:
args := sp.Args
if args == nil {
args = []string{}
}
out = append(out, handlers.McpServerStdio{
Name: sp.Name, Command: sp.Command, Args: args, Env: toEnvVariables(sp.Env),
})
case McpHTTP:
if !httpOK {
log.Warn("acp.mcp_inject.server_skipped_no_capability",
"session_id", sessionID, "name", sp.Name, "type", "http")
continue
}
out = append(out, handlers.McpServerHTTP{
Type: "http", Name: sp.Name, URL: sp.URL, Headers: toHTTPHeaders(sp.Headers),
})
case McpSSE:
if !sseOK {
log.Warn("acp.mcp_inject.server_skipped_no_capability",
"session_id", sessionID, "name", sp.Name, "type", "sse")
continue
}
out = append(out, handlers.McpServerHTTP{
Type: "sse", Name: sp.Name, URL: sp.URL, Headers: toHTTPHeaders(sp.Headers),
})
}
}
return out
}
// toEnvVariables / toHTTPHeaders 把 map 转为 ACP wire 的 name-value 数组,
// 按 key 排序保证序列化确定性(map 迭代随机)。
func toEnvVariables(m map[string]string) []handlers.EnvVariable {
out := make([]handlers.EnvVariable, 0, len(m))
for _, k := range sortedKeys(m) {
out = append(out, handlers.EnvVariable{Name: k, Value: m[k]})
}
return out
}
func toHTTPHeaders(m map[string]string) []handlers.HttpHeader {
out := make([]handlers.HttpHeader, 0, len(m))
for _, k := range sortedKeys(m) {
out = append(out, handlers.HttpHeader{Name: k, Value: m[k]})
}
return out
}
func sortedKeys(m map[string]string) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}