package vTool import ( "context" "fmt" "io/ioutil" "os" "strings" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "golang.org/x/crypto/ssh" "mcp-go-db/vConfig" ) // WarDeployTool 创建war包部署工具 func WarDeployTool(config *vConfig.Config, name string) mcp.Tool { return mcp.NewTool(name, mcp.WithDescription("部署war包到服务器"), mcp.WithString("warPath", mcp.Required(), mcp.Description("war包路径"), mcp.DefaultString("/path/to/default.war"), ), mcp.WithString("server", mcp.Required(), mcp.Description("服务器地址"), mcp.DefaultString("user@example.com:22"), ), mcp.WithString("targetPath", mcp.Required(), mcp.Description("目标部署路径"), mcp.DefaultString("/opt/tomcat/webapps/"), ), mcp.WithString("startCmd", mcp.Required(), mcp.Description("启动服务命令"), mcp.DefaultString("/opt/tomcat/bin/startup.sh"), ), mcp.WithString("appName", mcp.Required(), mcp.Description("应用名称(用于进程过滤)"), ), ) } // deployWar 部署war包到服务器 func deployWar(ctx context.Context, request mcp.CallToolRequest, config *vConfig.Config) (*mcp.CallToolResult, error) { args := request.Params.Arguments // 获取密码 pwd := os.Getenv("pwd") if pwd == "" { return mcp.NewToolResultError("环境变量pwd未设置"), nil } // 解析服务器地址 serverParts := strings.Split(args["server"].(string), "@") if len(serverParts) != 2 { return mcp.NewToolResultError("服务器地址格式错误,应为user@host:port"), nil } hostParts := strings.Split(serverParts[1], ":") if len(hostParts) != 2 { return mcp.NewToolResultError("服务器地址格式错误,应为user@host:port"), nil } // 创建SSH配置 sshConfig := &ssh.ClientConfig{ User: serverParts[0], Auth: []ssh.AuthMethod{ ssh.Password(pwd), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } // 连接服务器 client, err := ssh.Dial("tcp", hostParts[0]+":"+hostParts[1], sshConfig) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("SSH连接失败: %v", err)), nil } defer client.Close() // 检查并杀死进程 session, err := client.NewSession() if err != nil { return mcp.NewToolResultError(fmt.Sprintf("创建会话失败: %v", err)), nil } defer session.Close() // 查找并杀死进程 killCmd := fmt.Sprintf("ps -ef | grep %s | grep -v grep | awk '{print $2}' | xargs kill -9", args["appName"].(string)) if err := session.Run(killCmd); err != nil { // 忽略错误,可能没有进程运行 } // 上传war包 warData, err := ioutil.ReadFile(args["warPath"].(string)) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("读取war包失败: %v", err)), nil } targetFile := args["targetPath"].(string) + "/" + strings.Split(args["warPath"].(string), "/")[len(strings.Split(args["warPath"].(string), "/"))-1] if err := scpUpload(client, warData, targetFile); err != nil { return mcp.NewToolResultError(fmt.Sprintf("上传war包失败: %v", err)), nil } // 启动服务 if err := session.Run(args["startCmd"].(string)); err != nil { return mcp.NewToolResultError(fmt.Sprintf("启动服务失败: %v", err)), nil } return &mcp.CallToolResult{ Content: []mcp.Content{ mcp.NewTextContent("war包部署成功"), }, }, nil } // scpUpload 通过SCP上传文件 func scpUpload(client *ssh.Client, data []byte, remotePath string) error { session, err := client.NewSession() if err != nil { return err } defer session.Close() go func() { w, _ := session.StdinPipe() defer w.Close() fmt.Fprintf(w, "C0644 %d %s\n", len(data), remotePath) w.Write(data) fmt.Fprint(w, "\x00") }() return session.Run("/usr/bin/scp -tr ./") } // RegisterWarTools 注册war包相关工具 func RegisterWarTools(s *server.MCPServer, config *vConfig.Config) { tool := WarDeployTool(config, "部署war包") s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return deployWar(ctx, request, config) }) }