cloudpods_servers_tool.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package tools
  15. import (
  16. "context"
  17. "encoding/json"
  18. "fmt"
  19. "strconv"
  20. "github.com/mark3labs/mcp-go/mcp"
  21. "yunion.io/x/log"
  22. "yunion.io/x/onecloud/pkg/mcp-server/adapters"
  23. "yunion.io/x/onecloud/pkg/mcp-server/models"
  24. )
  25. // CloudpodsServersTool 是用于查询 Cloudpods 虚拟机实例列表的工具
  26. type CloudpodsServersTool struct {
  27. // adapter 用于与 Cloudpods API 进行交互
  28. adapter *adapters.CloudpodsAdapter
  29. }
  30. // NewCloudpodsServersTool 创建一个新的 Cloudpods 虚拟机查询工具
  31. // adapter: 用于与Cloudpods API交互的适配器
  32. // 返回值: CloudpodsServersTool实例指针
  33. func NewCloudpodsServersTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServersTool {
  34. return &CloudpodsServersTool{
  35. adapter: adapter,
  36. }
  37. }
  38. // GetTool 定义并返回查询虚拟机实例列表工具的元数据
  39. // 该工具用于查询Cloudpods虚拟机实例列表,获取虚拟机信息
  40. // limit: 返回结果数量限制,默认为50
  41. // offset: 结果偏移量,默认为0
  42. // search: 按名称或ID模糊搜索
  43. // status: 虚拟机状态,例如:running、stopped、creating等
  44. // ak: 用户登录cloudpods后获取的access key
  45. // sk: 用户登录cloudpods后获取的secret key
  46. func (c *CloudpodsServersTool) GetTool() mcp.Tool {
  47. return mcp.NewTool(
  48. "cloudpods_list_servers",
  49. mcp.WithDescription("查询Cloudpods虚拟机实例列表,获取虚拟机信息"),
  50. mcp.WithString("limit", mcp.Description("返回结果数量限制,默认为50")),
  51. mcp.WithString("offset", mcp.Description("结果偏移量,默认为0")),
  52. mcp.WithString("search", mcp.Description("按名称或ID模糊搜索")),
  53. mcp.WithString("status", mcp.Description("虚拟机状态,例如:running、stopped、creating等")),
  54. mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
  55. mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
  56. )
  57. }
  58. // Handle 处理查询 Cloudpods 虚拟机实例列表的请求
  59. // ctx: 控制生命周期的上下文
  60. // req: 包含查询参数的请求对象
  61. // 返回值: 包含虚拟机列表的响应对象和可能的错误
  62. func (c *CloudpodsServersTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  63. // 获取可选参数:返回结果数量限制,如果指定则转换为整数
  64. limit := 50
  65. if limitStr := req.GetString("limit", ""); limitStr != "" {
  66. if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 {
  67. limit = parsedLimit
  68. }
  69. }
  70. // 获取可选参数:结果偏移量,如果指定则转换为整数
  71. offset := 0
  72. if offsetStr := req.GetString("offset", ""); offsetStr != "" {
  73. if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 {
  74. offset = parsedOffset
  75. }
  76. }
  77. // 获取可选参数:搜索关键词和虚拟机状态
  78. search := req.GetString("search", "")
  79. status := req.GetString("status", "")
  80. // 获取可选参数:访问凭证
  81. ak := req.GetString("ak", "")
  82. sk := req.GetString("sk", "")
  83. // 调用适配器查询虚拟机列表
  84. serversResponse, err := c.adapter.ListServers(ctx, limit, offset, search, status, ak, sk)
  85. if err != nil {
  86. log.Errorf("Fail to query server: %s", err)
  87. return nil, fmt.Errorf("fail to query server: %w", err)
  88. }
  89. // 格式化查询结果
  90. formattedResult := c.formatServersResult(serversResponse, limit, offset, search, status)
  91. // 将结果序列化为JSON格式
  92. resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
  93. if err != nil {
  94. log.Errorf("Fail to serialize result: %s", err)
  95. return nil, fmt.Errorf("fail to serialize result: %w", err)
  96. }
  97. // 返回格式化后的结果
  98. return mcp.NewToolResultText(string(resultJSON)), nil
  99. }
  100. // GetName 返回工具的名称标识符
  101. // 返回值: 工具名称字符串,用于唯一标识该工具
  102. func (c *CloudpodsServersTool) GetName() string {
  103. return "cloudpods_list_servers"
  104. }
  105. // formatServersResult 格式化虚拟机实例列表查询结果
  106. // response: 原始虚拟机列表响应数据
  107. // limit: 查询限制数量
  108. // offset: 查询偏移量
  109. // search: 搜索关键词
  110. // status: 虚拟机状态
  111. // 返回值: 包含虚拟机列表的格式化结果
  112. func (c *CloudpodsServersTool) formatServersResult(response *models.ServerListResponse, limit int, offset int, search string, status string) map[string]interface{} {
  113. // 初始化格式化结果结构
  114. formatted := map[string]interface{}{
  115. // 添加查询信息
  116. "query_info": map[string]interface{}{
  117. "limit": limit,
  118. "offset": offset,
  119. "search": search,
  120. "status": status,
  121. "total": response.Total,
  122. "count": len(response.Servers),
  123. },
  124. // 初始化虚拟机列表
  125. "servers": make([]map[string]interface{}, 0, len(response.Servers)),
  126. }
  127. // 遍历虚拟机列表,构造每个虚拟机的详细信息
  128. for _, server := range response.Servers {
  129. // 将内存大小从MB转换为GB
  130. memoryGB := float64(server.VmemSize) / 1024
  131. // 构造虚拟机信息
  132. serverInfo := map[string]interface{}{
  133. "id": server.Id,
  134. "name": server.Name,
  135. "status": server.Status,
  136. "vcpu_count": server.VcpuCount,
  137. "vmem_size": server.VmemSize,
  138. "memory_gb": fmt.Sprintf("%.1f GB", memoryGB),
  139. "os_name": server.OsName,
  140. "ips": server.Ips,
  141. "host": server.Host,
  142. "zone": server.Zone,
  143. "region": server.Cloudregion,
  144. "created_at": server.CreatedAt,
  145. }
  146. formatted["servers"] = append(formatted["servers"].([]map[string]interface{}), serverInfo)
  147. }
  148. // 构造摘要信息
  149. formatted["summary"] = map[string]interface{}{
  150. "total_servers": response.Total,
  151. "returned_count": len(response.Servers),
  152. }
  153. return formatted
  154. }