You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

144 lines
4.0 KiB

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)
})
}