refactor: 重构代码架构,解耦处理器和服务 (#13)

重大架构改进:
- 移除全局变量 xiaohongshuService,改用依赖注入
- 将代码按职责分离到不同文件:
  * app_server.go - 核心服务器结构
  * types.go - 统一类型定义
  * routes.go - 路由配置
  * middleware.go - 中间件
  * handlers_api.go - REST API 处理器
  * handlers_mcp.go - MCP 协议处理器
- 将通用工具函数从 AppServer 方法改为独立函数
- 删除未使用的类型定义(LoginWaitRequest)
- 修复 JSON 编码错误处理

优势:
 更好的依赖注入模式
 清晰的职责分离
 提高代码可测试性
 符合 Go 最佳实践
 降低耦合度,提高内聚性

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
zy
2025-08-17 16:15:54 +08:00
committed by GitHub
parent 0e4450b12c
commit a7e975cf7c
9 changed files with 248 additions and 212 deletions

View File

@@ -12,7 +12,10 @@
"Bash(rm:*)", "Bash(rm:*)",
"Bash(gofmt:*)", "Bash(gofmt:*)",
"Bash(goimports:*)", "Bash(goimports:*)",
"Bash(chmod:*)" "Bash(chmod:*)",
"Bash(true)",
"Bash(go vet:*)",
"Bash(golangci-lint run:*)"
], ],
"deny": [] "deny": []
} }

66
app_server.go Normal file
View File

@@ -0,0 +1,66 @@
package main
import (
"context"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
// AppServer 应用服务器结构体,封装所有服务和处理器
type AppServer struct {
xiaohongshuService *XiaohongshuService
router *gin.Engine
httpServer *http.Server
}
// NewAppServer 创建新的应用服务器实例
func NewAppServer(xiaohongshuService *XiaohongshuService) *AppServer {
return &AppServer{
xiaohongshuService: xiaohongshuService,
}
}
// Start 启动服务器
func (s *AppServer) Start(port string) error {
s.router = setupRoutes(s)
s.httpServer = &http.Server{
Addr: port,
Handler: s.router,
}
// 启动服务器的 goroutine
go func() {
logrus.Infof("启动 HTTP 服务器: %s", port)
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logrus.Errorf("服务器启动失败: %v", err)
os.Exit(1)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logrus.Infof("正在关闭服务器...")
// 优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// 关闭 HTTP 服务器
if err := s.httpServer.Shutdown(ctx); err != nil {
logrus.Errorf("服务器关闭失败: %v", err)
return err
}
logrus.Infof("服务器已关闭")
return nil
}

View File

@@ -7,25 +7,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// LoginWaitRequest 等待登录请求
type LoginWaitRequest struct {
Timeout int `json:"timeout"`
}
// ErrorResponse 错误响应
type ErrorResponse struct {
Error string `json:"error"`
Code string `json:"code"`
Details any `json:"details,omitempty"`
}
// SuccessResponse 成功响应
type SuccessResponse struct {
Success bool `json:"success"`
Data any `json:"data"`
Message string `json:"message,omitempty"`
}
// respondError 返回错误响应 // respondError 返回错误响应
func respondError(c *gin.Context, statusCode int, code, message string, details any) { func respondError(c *gin.Context, statusCode int, code, message string, details any) {
response := ErrorResponse{ response := ErrorResponse{
@@ -54,12 +35,9 @@ func respondSuccess(c *gin.Context, data any, message string) {
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
// XiaohongshuService 全局服务实例
var xiaohongshuService = NewXiaohongshuService()
// checkLoginStatusHandler 检查登录状态 // checkLoginStatusHandler 检查登录状态
func checkLoginStatusHandler(c *gin.Context) { func (s *AppServer) checkLoginStatusHandler(c *gin.Context) {
status, err := xiaohongshuService.CheckLoginStatus(c.Request.Context()) status, err := s.xiaohongshuService.CheckLoginStatus(c.Request.Context())
if err != nil { if err != nil {
respondError(c, http.StatusInternalServerError, "STATUS_CHECK_FAILED", respondError(c, http.StatusInternalServerError, "STATUS_CHECK_FAILED",
"检查登录状态失败", err.Error()) "检查登录状态失败", err.Error())
@@ -71,7 +49,7 @@ func checkLoginStatusHandler(c *gin.Context) {
} }
// publishHandler 发布内容 // publishHandler 发布内容
func publishHandler(c *gin.Context) { func (s *AppServer) publishHandler(c *gin.Context) {
var req PublishRequest var req PublishRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
respondError(c, http.StatusBadRequest, "INVALID_REQUEST", respondError(c, http.StatusBadRequest, "INVALID_REQUEST",
@@ -80,7 +58,7 @@ func publishHandler(c *gin.Context) {
} }
// 执行发布 // 执行发布
result, err := xiaohongshuService.PublishContent(c.Request.Context(), &req) result, err := s.xiaohongshuService.PublishContent(c.Request.Context(), &req)
if err != nil { if err != nil {
respondError(c, http.StatusInternalServerError, "PUBLISH_FAILED", respondError(c, http.StatusInternalServerError, "PUBLISH_FAILED",
"发布失败", err.Error()) "发布失败", err.Error())
@@ -91,9 +69,9 @@ func publishHandler(c *gin.Context) {
} }
// listFeedsHandler 获取Feeds列表 // listFeedsHandler 获取Feeds列表
func listFeedsHandler(c *gin.Context) { func (s *AppServer) listFeedsHandler(c *gin.Context) {
// 获取 Feeds 列表 // 获取 Feeds 列表
result, err := xiaohongshuService.ListFeeds(c.Request.Context()) result, err := s.xiaohongshuService.ListFeeds(c.Request.Context())
if err != nil { if err != nil {
respondError(c, http.StatusInternalServerError, "LIST_FEEDS_FAILED", respondError(c, http.StatusInternalServerError, "LIST_FEEDS_FAILED",
"获取Feeds列表失败", err.Error()) "获取Feeds列表失败", err.Error())
@@ -113,29 +91,3 @@ func healthHandler(c *gin.Context) {
"timestamp": "now", "timestamp": "now",
}, "服务正常") }, "服务正常")
} }
// corsMiddleware CORS 中间件
func corsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
// errorHandlingMiddleware 错误处理中间件
func errorHandlingMiddleware() gin.HandlerFunc {
return gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
logrus.Errorf("服务器内部错误: %v, path: %s", recovered, c.Request.URL.Path)
respondError(c, http.StatusInternalServerError, "INTERNAL_ERROR",
"服务器内部错误", recovered)
})
}

View File

@@ -9,50 +9,13 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// JSON-RPC 结构定义
type JSONRPCRequest struct {
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params,omitempty"`
ID interface{} `json:"id"`
}
type JSONRPCResponse struct {
JSONRPC string `json:"jsonrpc"`
Result interface{} `json:"result,omitempty"`
Error *JSONRPCError `json:"error,omitempty"`
ID interface{} `json:"id"`
}
type JSONRPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
type MCPToolCall struct {
Name string `json:"name"`
Arguments map[string]interface{} `json:"arguments"`
}
type MCPToolResult struct {
Content []MCPContent `json:"content"`
IsError bool `json:"isError,omitempty"`
}
type MCPContent struct {
Type string `json:"type"`
Text string `json:"text"`
}
// MCP 工具处理函数 // MCP 工具处理函数
// handleCheckLoginStatus 处理检查登录状态 // handleCheckLoginStatus 处理检查登录状态
func handleCheckLoginStatus(ctx context.Context) *MCPToolResult { func (s *AppServer) handleCheckLoginStatus(ctx context.Context) *MCPToolResult {
logrus.Info("MCP: 检查登录状态") logrus.Info("MCP: 检查登录状态")
status, err := xiaohongshuService.CheckLoginStatus(ctx) status, err := s.xiaohongshuService.CheckLoginStatus(ctx)
if err != nil { if err != nil {
return &MCPToolResult{ return &MCPToolResult{
Content: []MCPContent{{ Content: []MCPContent{{
@@ -73,7 +36,7 @@ func handleCheckLoginStatus(ctx context.Context) *MCPToolResult {
} }
// handlePublishContent 处理发布内容 // handlePublishContent 处理发布内容
func handlePublishContent(ctx context.Context, args map[string]interface{}) *MCPToolResult { func (s *AppServer) handlePublishContent(ctx context.Context, args map[string]interface{}) *MCPToolResult {
logrus.Info("MCP: 发布内容") logrus.Info("MCP: 发布内容")
// 解析参数 // 解析参数
@@ -98,7 +61,7 @@ func handlePublishContent(ctx context.Context, args map[string]interface{}) *MCP
} }
// 执行发布 // 执行发布
result, err := xiaohongshuService.PublishContent(ctx, req) result, err := s.xiaohongshuService.PublishContent(ctx, req)
if err != nil { if err != nil {
return &MCPToolResult{ return &MCPToolResult{
Content: []MCPContent{{ Content: []MCPContent{{
@@ -119,10 +82,10 @@ func handlePublishContent(ctx context.Context, args map[string]interface{}) *MCP
} }
// handleListFeeds 处理获取Feeds列表 // handleListFeeds 处理获取Feeds列表
func handleListFeeds(ctx context.Context) *MCPToolResult { func (s *AppServer) handleListFeeds(ctx context.Context) *MCPToolResult {
logrus.Info("MCP: 获取Feeds列表") logrus.Info("MCP: 获取Feeds列表")
result, err := xiaohongshuService.ListFeeds(ctx) result, err := s.xiaohongshuService.ListFeeds(ctx)
if err != nil { if err != nil {
return &MCPToolResult{ return &MCPToolResult{
Content: []MCPContent{{ Content: []MCPContent{{
@@ -154,11 +117,11 @@ func handleListFeeds(ctx context.Context) *MCPToolResult {
} }
// handleMCPRequest 处理 MCP 请求 // handleMCPRequest 处理 MCP 请求
func handleMCPRequest(w http.ResponseWriter, r *http.Request) { func (s *AppServer) handleMCPRequest(w http.ResponseWriter, r *http.Request) {
var req JSONRPCRequest var req JSONRPCRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logrus.Errorf("解析请求失败: %v", err) logrus.Errorf("解析请求失败: %v", err)
sendJSONRPCError(w, req.ID, -32700, "Parse error", nil) s.sendJSONRPCError(w, req.ID, -32700, "Parse error", nil)
return return
} }
@@ -166,19 +129,19 @@ func handleMCPRequest(w http.ResponseWriter, r *http.Request) {
switch req.Method { switch req.Method {
case "initialize": case "initialize":
handleInitialize(w, req) s.handleInitialize(w, req)
case "tools/list": case "tools/list":
handleToolsList(w, req) s.handleToolsList(w, req)
case "tools/call": case "tools/call":
handleToolsCall(w, r, req) s.handleToolsCall(w, r, req)
default: default:
logrus.Warnf("不支持的方法: %s", req.Method) logrus.Warnf("不支持的方法: %s", req.Method)
sendJSONRPCError(w, req.ID, -32601, "Method not found", nil) s.sendJSONRPCError(w, req.ID, -32601, "Method not found", nil)
} }
} }
// handleInitialize 处理初始化请求 // handleInitialize 处理初始化请求
func handleInitialize(w http.ResponseWriter, req JSONRPCRequest) { func (s *AppServer) handleInitialize(w http.ResponseWriter, req JSONRPCRequest) {
result := map[string]interface{}{ result := map[string]interface{}{
"protocolVersion": "2024-11-05", "protocolVersion": "2024-11-05",
"capabilities": map[string]interface{}{ "capabilities": map[string]interface{}{
@@ -190,11 +153,11 @@ func handleInitialize(w http.ResponseWriter, req JSONRPCRequest) {
}, },
} }
sendJSONRPCResponse(w, req.ID, result) s.sendJSONRPCResponse(w, req.ID, result)
} }
// handleToolsList 处理工具列表请求 // handleToolsList 处理工具列表请求
func handleToolsList(w http.ResponseWriter, req JSONRPCRequest) { func (s *AppServer) handleToolsList(w http.ResponseWriter, req JSONRPCRequest) {
tools := []map[string]interface{}{ tools := []map[string]interface{}{
{ {
"name": "check_login_status", "name": "check_login_status",
@@ -242,16 +205,16 @@ func handleToolsList(w http.ResponseWriter, req JSONRPCRequest) {
"tools": tools, "tools": tools,
} }
sendJSONRPCResponse(w, req.ID, result) s.sendJSONRPCResponse(w, req.ID, result)
} }
// handleToolsCall 处理工具调用请求 // handleToolsCall 处理工具调用请求
func handleToolsCall(w http.ResponseWriter, r *http.Request, req JSONRPCRequest) { func (s *AppServer) handleToolsCall(w http.ResponseWriter, r *http.Request, req JSONRPCRequest) {
var toolCall MCPToolCall var toolCall MCPToolCall
paramsBytes, _ := json.Marshal(req.Params) paramsBytes, _ := json.Marshal(req.Params)
if err := json.Unmarshal(paramsBytes, &toolCall); err != nil { if err := json.Unmarshal(paramsBytes, &toolCall); err != nil {
logrus.Errorf("解析工具调用参数失败: %v", err) logrus.Errorf("解析工具调用参数失败: %v", err)
sendJSONRPCError(w, req.ID, -32602, "Invalid params", nil) s.sendJSONRPCError(w, req.ID, -32602, "Invalid params", nil)
return return
} }
@@ -260,22 +223,22 @@ func handleToolsCall(w http.ResponseWriter, r *http.Request, req JSONRPCRequest)
switch toolCall.Name { switch toolCall.Name {
case "check_login_status": case "check_login_status":
result = handleCheckLoginStatus(ctx) result = s.handleCheckLoginStatus(ctx)
case "publish_content": case "publish_content":
result = handlePublishContent(ctx, toolCall.Arguments) result = s.handlePublishContent(ctx, toolCall.Arguments)
case "list_feeds": case "list_feeds":
result = handleListFeeds(ctx) result = s.handleListFeeds(ctx)
default: default:
logrus.Warnf("不支持的工具: %s", toolCall.Name) logrus.Warnf("不支持的工具: %s", toolCall.Name)
sendJSONRPCError(w, req.ID, -32601, "Tool not found", nil) s.sendJSONRPCError(w, req.ID, -32601, "Tool not found", nil)
return return
} }
sendJSONRPCResponse(w, req.ID, result) s.sendJSONRPCResponse(w, req.ID, result)
} }
// sendJSONRPCResponse 发送JSON-RPC响应 // sendJSONRPCResponse 发送JSON-RPC响应
func sendJSONRPCResponse(w http.ResponseWriter, id interface{}, result interface{}) { func (s *AppServer) sendJSONRPCResponse(w http.ResponseWriter, id interface{}, result interface{}) {
response := JSONRPCResponse{ response := JSONRPCResponse{
JSONRPC: "2.0", JSONRPC: "2.0",
Result: result, Result: result,
@@ -283,11 +246,13 @@ func sendJSONRPCResponse(w http.ResponseWriter, id interface{}, result interface
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response) if err := json.NewEncoder(w).Encode(response); err != nil {
logrus.Errorf("Failed to encode JSON-RPC response: %v", err)
}
} }
// sendJSONRPCError 发送JSON-RPC错误响应 // sendJSONRPCError 发送JSON-RPC错误响应
func sendJSONRPCError(w http.ResponseWriter, id interface{}, code int, message string, data interface{}) { func (s *AppServer) sendJSONRPCError(w http.ResponseWriter, id interface{}, code int, message string, data interface{}) {
response := JSONRPCResponse{ response := JSONRPCResponse{
JSONRPC: "2.0", JSONRPC: "2.0",
Error: &JSONRPCError{ Error: &JSONRPCError{
@@ -300,11 +265,13 @@ func sendJSONRPCError(w http.ResponseWriter, id interface{}, code int, message s
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // JSON-RPC错误仍然返回200状态码 w.WriteHeader(http.StatusOK) // JSON-RPC错误仍然返回200状态码
json.NewEncoder(w).Encode(response) if err := json.NewEncoder(w).Encode(response); err != nil {
logrus.Errorf("Failed to encode JSON-RPC error response: %v", err)
}
} }
// createMCPHandler 创建MCP HTTP处理器 // createMCPHandler 创建MCP HTTP处理器
func createMCPHandler() http.HandlerFunc { func (s *AppServer) createMCPHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// 设置 CORS 头 // 设置 CORS 头
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
@@ -323,6 +290,6 @@ func createMCPHandler() http.HandlerFunc {
} }
// 处理 MCP JSON-RPC 请求 // 处理 MCP JSON-RPC 请求
handleMCPRequest(w, r) s.handleMCPRequest(w, r)
} }
} }

View File

@@ -8,7 +8,6 @@ import (
) )
func main() { func main() {
var ( var (
headless bool headless bool
) )
@@ -17,7 +16,12 @@ func main() {
configs.InitHeadless(headless) configs.InitHeadless(headless)
if err := startServer(); err != nil { // 初始化服务
xiaohongshuService := NewXiaohongshuService()
// 创建并启动应用服务器
appServer := NewAppServer(xiaohongshuService)
if err := appServer.Start(":18060"); err != nil {
logrus.Fatalf("failed to run server: %v", err) logrus.Fatalf("failed to run server: %v", err)
} }
} }

34
middleware.go Normal file
View File

@@ -0,0 +1,34 @@
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
// corsMiddleware CORS 中间件
func corsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
// errorHandlingMiddleware 错误处理中间件
func errorHandlingMiddleware() gin.HandlerFunc {
return gin.CustomRecovery(func(c *gin.Context, recovered any) {
logrus.Errorf("服务器内部错误: %v, path: %s", recovered, c.Request.URL.Path)
respondError(c, http.StatusInternalServerError, "INTERNAL_ERROR",
"服务器内部错误", recovered)
})
}

37
routes.go Normal file
View File

@@ -0,0 +1,37 @@
package main
import (
"github.com/gin-gonic/gin"
)
// setupRoutes 设置路由配置
func setupRoutes(appServer *AppServer) *gin.Engine {
// 设置 Gin 模式
gin.SetMode(gin.ReleaseMode)
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
// 添加中间件
router.Use(errorHandlingMiddleware())
router.Use(corsMiddleware())
// 健康检查
router.GET("/health", healthHandler)
// MCP 端点 - 使用 SSE 协议
mcpHandler := appServer.createMCPHandler()
router.Any("/mcp", gin.WrapH(mcpHandler))
router.Any("/mcp/*path", gin.WrapH(mcpHandler))
// API 路由组
api := router.Group("/api/v1")
{
api.GET("/login/status", appServer.checkLoginStatusHandler)
api.POST("/publish", appServer.publishHandler)
api.GET("/feeds/list", appServer.listFeedsHandler)
}
return router
}

View File

@@ -1,89 +0,0 @@
package main
import (
"context"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
// setupRouter 设置路由
func setupRouter() *gin.Engine {
// 设置 Gin 模式
gin.SetMode(gin.ReleaseMode)
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
// 添加中间件
router.Use(errorHandlingMiddleware())
router.Use(corsMiddleware())
// 健康检查
router.GET("/health", healthHandler)
// MCP 端点 - 使用 SSE 协议
mcpHandler := createMCPHandler()
router.Any("/mcp", gin.WrapH(mcpHandler))
router.Any("/mcp/*path", gin.WrapH(mcpHandler))
// API 路由组
api := router.Group("/api/v1")
{
api.GET("/login/status", checkLoginStatusHandler)
api.POST("/publish", publishHandler)
// Feeds 相关路由
api.GET("/feeds/list", listFeedsHandler)
}
return router
}
// startServer 启动服务器
func startServer() error {
router := setupRouter()
port := ":18060"
server := &http.Server{
Addr: port,
Handler: router,
}
// 启动服务器的 goroutine
go func() {
logrus.Infof("启动 HTTP 服务器: %s", port)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logrus.Errorf("服务器启动失败: %v", err)
os.Exit(1)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logrus.Infof("正在关闭服务器...")
// 优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// 关闭 HTTP 服务器
if err := server.Shutdown(ctx); err != nil {
logrus.Errorf("服务器关闭失败: %v", err)
return err
}
logrus.Infof("服务器已关闭")
return nil
}

62
types.go Normal file
View File

@@ -0,0 +1,62 @@
package main
// HTTP API 响应类型
// ErrorResponse 错误响应
type ErrorResponse struct {
Error string `json:"error"`
Code string `json:"code"`
Details any `json:"details,omitempty"`
}
// SuccessResponse 成功响应
type SuccessResponse struct {
Success bool `json:"success"`
Data any `json:"data"`
Message string `json:"message,omitempty"`
}
// JSON-RPC 相关类型
// JSONRPCRequest JSON-RPC 请求
type JSONRPCRequest struct {
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params any `json:"params,omitempty"`
ID any `json:"id"`
}
// JSONRPCResponse JSON-RPC 响应
type JSONRPCResponse struct {
JSONRPC string `json:"jsonrpc"`
Result any `json:"result,omitempty"`
Error *JSONRPCError `json:"error,omitempty"`
ID any `json:"id"`
}
// JSONRPCError JSON-RPC 错误
type JSONRPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
// MCP 相关类型
// MCPToolCall MCP 工具调用
type MCPToolCall struct {
Name string `json:"name"`
Arguments map[string]interface{} `json:"arguments"`
}
// MCPToolResult MCP 工具结果
type MCPToolResult struct {
Content []MCPContent `json:"content"`
IsError bool `json:"isError,omitempty"`
}
// MCPContent MCP 内容
type MCPContent struct {
Type string `json:"type"`
Text string `json:"text"`
}