diff --git a/cmd/mcp/server.go b/cmd/mcp/server.go index 77f2cea..c9bf154 100644 --- a/cmd/mcp/server.go +++ b/cmd/mcp/server.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "os" "strconv" "strings" @@ -17,16 +18,35 @@ const ( serverVersion = "1.0.0" ) -// Run 启动 TaskPool MCP Server(stdio) -// 环境变量: -// TASKPOOL_URL 面板地址,如 http://127.0.0.1:8052 或 https://panel.example.com -// TASKPOOL_TOKEN 设置页 OpenAPI Token +// Run 启动 TaskPool MCP Server +// 模式: +// - stdio(默认):通过 stdin/stdout 通信,适用于 Claude Desktop / Cursor 等本地 Agent +// - http:通过 HTTP/SSE 通信,适用于 Hermes / OpenClaw 等远程 Agent +// +// 环境变量: +// TASKPOOL_URL 面板地址,如 http://127.0.0.1:8052 或 https://panel.example.com +// TASKPOOL_TOKEN 设置页 OpenAPI Token +// MCP_HTTP_ADDR HTTP 模式监听地址(默认 :8053) func Run(args []string) { - for _, a := range args { + mode := "stdio" + httpAddr := ":8053" + + for i, a := range args { if a == "-h" || a == "--help" { printHelp() return } + if a == "--http" { + mode = "http" + if i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") { + httpAddr = args[i+1] + } + } + } + + // HTTP 模式优先从环境变量读取地址 + if envAddr := os.Getenv("MCP_HTTP_ADDR"); envAddr != "" { + httpAddr = envAddr } baseURL := firstNonEmpty(os.Getenv("TASKPOOL_URL"), os.Getenv("BAIHU_URL"), "http://127.0.0.1:8052") @@ -46,8 +66,16 @@ func Run(args []string) { registerTools(s, client) registerPrompts(s) + if mode == "http" { + runHTTP(s, httpAddr, client) + } else { + runStdio(s, client) + } +} + +func runStdio(s *server.MCPServer, client *Client) { // 日志只能走 stderr,避免污染 stdio JSON-RPC - fmt.Fprintf(os.Stderr, "[taskpool-mcp] url=%s token=%s\n", client.BaseURL, maskToken(client.Token)) + fmt.Fprintf(os.Stderr, "[taskpool-mcp] mode=stdio url=%s token=%s\n", client.BaseURL, maskToken(client.Token)) if err := server.ServeStdio(s); err != nil { fmt.Fprintf(os.Stderr, "[taskpool-mcp] server error: %v\n", err) @@ -55,6 +83,26 @@ func Run(args []string) { } } +func runHTTP(s *server.MCPServer, addr string, client *Client) { + fmt.Fprintf(os.Stderr, "[taskpool-mcp] mode=http addr=%s url=%s token=%s\n", addr, client.BaseURL, maskToken(client.Token)) + + httpServer := server.NewStreamableHTTPServer(s, + server.WithEndpointPath("/mcp"), + ) + + // 添加健康检查端点 + http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"status":"ok"}`)) + }) + + fmt.Fprintf(os.Stderr, "[taskpool-mcp] MCP endpoint: http://%s/mcp\n", strings.TrimPrefix(addr, ":")) + if err := httpServer.Start(addr); err != nil { + fmt.Fprintf(os.Stderr, "[taskpool-mcp] http server error: %v\n", err) + os.Exit(1) + } +} + func printHelp() { fmt.Fprintf(os.Stderr, ` TaskPool MCP Server @@ -62,13 +110,21 @@ TaskPool MCP Server 通过 MCP 协议把 TaskPool OpenAPI 暴露给 Hermes / OpenClaw / Cursor 等 Agent。 用法: - taskpool mcp + taskpool mcp # stdio 模式(默认),适用于本地 Agent + taskpool mcp --http # HTTP 模式,监听 :8053 + taskpool mcp --http :9000 # HTTP 模式,监听指定端口 环境变量: TASKPOOL_URL 面板地址 (默认 http://127.0.0.1:8052) TASKPOOL_TOKEN 设置页生成的 OpenAPI Token(必填) + MCP_HTTP_ADDR HTTP 模式监听地址(默认 :8053) -Hermes / OpenClaw 配置示例: +模式说明: + stdio 通过 stdin/stdout 通信,需要本地安装 taskpool 二进制 + http 通过 HTTP/SSE 通信,支持远程访问,无需本地安装 + +--- stdio 模式配置示例 --- +Hermes / OpenClaw / Cursor 配置: { "mcpServers": { "taskpool": { @@ -82,6 +138,21 @@ Hermes / OpenClaw 配置示例: } } +--- HTTP 模式配置示例 --- +1. 启动 MCP HTTP Server: + taskpool mcp --http :8053 + +2. Hermes / OpenClaw 配置(使用 URL): + { + "mcpServers": { + "taskpool": { + "url": "http://your-server:8053/mcp" + } + } + } + +注意: HTTP 模式建议配置反向代理(如 Nginx)添加 HTTPS 和认证 + 前置条件: 1. 面板「系统设置」启用 OpenAPI 并生成 Token 2. 后端服务已启动 (taskpool server) diff --git a/docs/guide/mcp.md b/docs/guide/mcp.md index 085e79d..6703c27 100644 --- a/docs/guide/mcp.md +++ b/docs/guide/mcp.md @@ -12,7 +12,16 @@ TaskPool 提供官方 **MCP Server**,让 Hermes、OpenClaw、Cursor 等 AI Age 2. 系统设置 → **启用 OpenAPI** → **生成 Token** 3. 本机或 Agent 环境能访问面板地址(如 `http://127.0.0.1:8052`) -## 启动 +## 两种传输模式 + +| 模式 | 传输方式 | 适用场景 | Agent 配置 | +|------|----------|----------|------------| +| **stdio** | stdin/stdout | 本地 Agent(Claude Desktop、Cursor) | `command` | +| **http** | HTTP/SSE | 远程 Agent(Hermes、OpenClaw) | `url` | + +### stdio 模式(默认) + +由 Agent 拉起子进程,通过标准输入输出通信。日志输出在 **stderr**,不会污染协议。 ```bash export TASKPOOL_URL=http://127.0.0.1:8052 @@ -20,9 +29,29 @@ export TASKPOOL_TOKEN=你的OpenAPI_Token taskpool mcp ``` -仅 stdio 传输:由 Agent 拉起子进程,通过标准输入输出通信。日志输出在 **stderr**,不会污染协议。 +### HTTP 模式 -## Hermes / OpenClaw 配置 +独立 HTTP 服务,Agent 通过 URL 访问,无需本地安装二进制。 + +```bash +# 监听默认端口 :8053 +taskpool mcp --http + +# 指定端口 +taskpool mcp --http :9000 + +# 或通过环境变量 +export MCP_HTTP_ADDR=:8053 +taskpool mcp --http +``` + +HTTP 模式暴露端点: +- `POST /mcp` - MCP 协议端点 +- `GET /health` - 健康检查 + +## Agent 配置示例 + +### stdio 模式(Claude Desktop / Cursor) ```json { @@ -52,6 +81,18 @@ taskpool mcp } ``` +### HTTP 模式(Hermes / OpenClaw) + +```json +{ + "mcpServers": { + "taskpool": { + "url": "http://your-server:8053/mcp" + } + } +} +``` + Docker 部署时,把 `TASKPOOL_URL` 写成 Agent 能访问的地址(宿主机映射端口或内网域名)。 ## 工具清单(Tools)