server.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Package agentmcp 是新 AI 助手使用的业务数据 MCP 服务(fwh-agent-mcp)。
  2. //
  3. // 无用户状态:工具不接收、不推断调用者;由 AgentServer 后台登记为远程 HTTP 服务,经 MCP Gateway 转接给 Agent。
  4. // 设计见 docs/ai-assistant-agentserver/agent-mcp.md。与旧助手的 cmd/mcp 相互独立。
  5. package agentmcp
  6. import (
  7. "fmt"
  8. "strings"
  9. "github.com/mark3labs/mcp-go/server"
  10. "go.uber.org/zap"
  11. "fwh-toolbox-server/agentmcp/kit"
  12. "fwh-toolbox-server/agentmcp/tools"
  13. )
  14. const (
  15. ServerName = "fwh-agent-mcp"
  16. ServerVersion = "1.0.0"
  17. SetReadOnly = "readonly"
  18. SetOps = "ops"
  19. )
  20. // AllSets 全部工具集。一个进程可同时加载多个,各自挂在 EndpointPath(set) 上,共用一个端口。
  21. var AllSets = []string{SetReadOnly, SetOps}
  22. // Tools 返回指定工具集。
  23. func Tools(set string) ([]kit.Registrar, error) {
  24. switch set {
  25. case SetReadOnly:
  26. return tools.ReadOnly(), nil
  27. case SetOps:
  28. return tools.Ops(), nil
  29. }
  30. return nil, fmt.Errorf("未知的工具集:%s(可选 %s)", set, strings.Join(AllSets, " / "))
  31. }
  32. // EndpointPath 工具集的 MCP 路径:/mcp/<工具集>。只读工具集另外挂在 /mcp 上,兼容已登记的地址。
  33. func EndpointPath(set string) string {
  34. return "/mcp/" + set
  35. }
  36. // ParseSets 解析逗号分隔的工具集列表(去空白、去重,保持顺序);空串表示全部。
  37. func ParseSets(s string) ([]string, error) {
  38. if strings.TrimSpace(s) == "" {
  39. return append([]string(nil), AllSets...), nil
  40. }
  41. var sets []string
  42. seen := map[string]bool{}
  43. for _, part := range strings.Split(s, ",") {
  44. set := strings.TrimSpace(part)
  45. if set == "" || seen[set] {
  46. continue
  47. }
  48. if _, err := Tools(set); err != nil {
  49. return nil, err
  50. }
  51. seen[set] = true
  52. sets = append(sets, set)
  53. }
  54. if len(sets) == 0 {
  55. return nil, fmt.Errorf("未指定工具集")
  56. }
  57. return sets, nil
  58. }
  59. // NewServer 创建 MCPServer 并注册工具集;同时返回其中的持久化长任务工具(交给 Handler 的 TaskRouter 处理任务协议)。
  60. func NewServer(set string, log *zap.Logger, maxConcurrency int) (*server.MCPServer, []kit.TaskTool, error) {
  61. list, err := Tools(set)
  62. if err != nil {
  63. return nil, nil, err
  64. }
  65. var tasks []kit.TaskTool
  66. for _, t := range list {
  67. if tt, ok := t.(kit.TaskTool); ok {
  68. tasks = append(tasks, tt)
  69. }
  70. }
  71. opts := []server.ServerOption{
  72. server.WithToolCapabilities(false),
  73. server.WithInputSchemaValidation(),
  74. server.WithToolHandlerMiddleware(kit.Middleware(log, maxConcurrency)),
  75. }
  76. if len(tasks) > 0 {
  77. // 声明支持以任务方式调用工具与取消(tasks.requests.tools.call、tasks.cancel);任务协议由 kit.TaskRouter 处理
  78. opts = append(opts, server.WithTaskCapabilities(false, true, true))
  79. }
  80. s := server.NewMCPServer(ServerName+"-"+set, ServerVersion, opts...)
  81. for _, t := range list {
  82. t.Register(s)
  83. }
  84. return s, tasks, nil
  85. }