cloudpods_regions_tool.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. // CloudpodsRegionsTool 是用于查询 Cloudpods 区域列表的工具
  26. type CloudpodsRegionsTool struct {
  27. // adapter 用于与 Cloudpods API 进行交互
  28. adapter *adapters.CloudpodsAdapter
  29. }
  30. // NewCloudpodsRegionsTool 创建一个新的 Cloudpods 区域查询工具
  31. // adapter: 用于与 Cloudpods API 进行交互的适配器
  32. // 返回值: 指向新创建的 CloudpodsRegionsTool 实例的指针
  33. func NewCloudpodsRegionsTool(adapter *adapters.CloudpodsAdapter) *CloudpodsRegionsTool {
  34. return &CloudpodsRegionsTool{
  35. adapter: adapter,
  36. }
  37. }
  38. // GetTool 返回 MCP 工具定义,用于查询 Cloudpods 区域列表
  39. // 该工具用于查询Cloudpods中的区域列表,获取所有可用的云区域信息
  40. // 支持的参数包括:
  41. // - limit: 返回结果数量限制,默认为50
  42. // - offset: 返回结果偏移量,默认为0
  43. // - search: 搜索关键词,可以按区域名称搜索
  44. // - provider: 云平台提供商,例如:aws、azure、aliyun等
  45. // - ak: 用户登录cloudpods后获取的access key
  46. // - sk: 用户登录cloudpods后获取的secret key
  47. func (c *CloudpodsRegionsTool) GetTool() mcp.Tool {
  48. return mcp.NewTool(
  49. "cloudpods_list_regions",
  50. mcp.WithDescription("查询Cloudpods区域列表,获取所有可用的云区域信息"),
  51. mcp.WithString("limit", mcp.Description("返回结果数量限制,默认为50")),
  52. mcp.WithString("offset", mcp.Description("返回结果偏移量,默认为0")),
  53. mcp.WithString("search", mcp.Description("搜索关键词,可以按区域名称搜索")),
  54. mcp.WithString("provider", mcp.Description("云平台提供商,例如:aws、azure、aliyun等")),
  55. mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
  56. mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
  57. )
  58. }
  59. // Handle 处理查询 Cloudpods 区域列表的请求
  60. // ctx: 控制请求生命周期的上下文
  61. // req: 包含查询参数的请求对象
  62. // 返回值: 包含查询结果的工具结果对象或错误信息
  63. func (c *CloudpodsRegionsTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  64. // 设置默认查询限制为50
  65. limit := 50
  66. if limitStr := req.GetString("limit", ""); limitStr != "" {
  67. // 解析limit参数,如果解析成功且大于0,则使用解析后的值
  68. if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 {
  69. limit = parsedLimit
  70. }
  71. }
  72. // 设置默认偏移量为0
  73. offset := 0
  74. if offsetStr := req.GetString("offset", ""); offsetStr != "" {
  75. // 解析offset参数,如果解析成功且大于等于0,则使用解析后的值
  76. if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 {
  77. offset = parsedOffset
  78. }
  79. }
  80. // 获取搜索关键词和提供商参数
  81. search := req.GetString("search", "")
  82. provider := req.GetString("provider", "")
  83. // 获取访问凭证
  84. ak := req.GetString("ak", "")
  85. sk := req.GetString("sk", "")
  86. // 调用适配器获取区域列表
  87. regionsResponse, err := c.adapter.ListCloudRegions(ctx, limit, offset, search, provider, ak, sk)
  88. if err != nil {
  89. log.Errorf("Fail to query region: %s", err)
  90. return nil, fmt.Errorf("fail to query region: %w", err)
  91. }
  92. // 格式化查询结果
  93. formattedResult := c.formatRegionsResult(regionsResponse, limit, offset, search, provider)
  94. // 将结果序列化为JSON格式
  95. resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
  96. if err != nil {
  97. log.Errorf("Fail to serialize result: %s", err)
  98. return nil, fmt.Errorf("fail to serialize result: %w", err)
  99. }
  100. // 返回格式化后的结果
  101. return mcp.NewToolResultText(string(resultJSON)), nil
  102. }
  103. // formatRegionsResult 格式化区域列表查询结果
  104. // response: 从适配器获取的原始区域数据
  105. // limit: 查询限制数量
  106. // offset: 查询偏移量
  107. // search: 搜索关键词
  108. // provider: 云平台提供商
  109. // 返回值: 格式化后的区域列表数据,包含查询信息、区域列表和摘要信息
  110. func (c *CloudpodsRegionsTool) formatRegionsResult(response *models.CloudregionListResponse, limit, offset int, search, provider string) map[string]interface{} {
  111. // 初始化结果结构,包含查询信息和区域列表
  112. formatted := map[string]interface{}{
  113. "query_info": map[string]interface{}{
  114. "limit": limit,
  115. "offset": offset,
  116. "search": search,
  117. "provider": provider,
  118. "total": response.Total,
  119. "count": len(response.Cloudregions),
  120. },
  121. "cloudregions": make([]map[string]interface{}, 0, len(response.Cloudregions)),
  122. }
  123. // 遍历原始区域数据,构造每个区域的详细信息
  124. for _, region := range response.Cloudregions {
  125. // 构造单个区域信息
  126. regionInfo := map[string]interface{}{
  127. "id": region.Id,
  128. "name": region.Name,
  129. "description": region.Description,
  130. "provider": region.Provider,
  131. "cloud_env": region.CloudEnv,
  132. "environment": region.Environment,
  133. "city": region.City,
  134. "country_code": region.CountryCode,
  135. "latitude": region.Latitude,
  136. "longitude": region.Longitude,
  137. "status": region.Status,
  138. "enabled": region.Enabled,
  139. "external_id": region.ExternalId,
  140. "guest_count": region.GuestCount,
  141. "guest_increment_count": region.GuestIncrementCount,
  142. "network_count": region.NetworkCount,
  143. "vpc_count": region.VpcCount,
  144. "zone_count": region.ZoneCount,
  145. "progress": region.Progress,
  146. "source": region.Source,
  147. "can_delete": region.CanDelete,
  148. "can_update": region.CanUpdate,
  149. "is_emulated": region.IsEmulated,
  150. "metadata": region.Metadata,
  151. "created_at": region.CreatedAt,
  152. "updated_at": region.UpdatedAt,
  153. "imported_at": region.ImportedAt,
  154. }
  155. // 将区域信息添加到结果数组中
  156. formatted["cloudregions"] = append(formatted["cloudregions"].([]map[string]interface{}), regionInfo)
  157. }
  158. // 构造摘要信息
  159. formatted["summary"] = map[string]interface{}{
  160. "total_cloudregions": response.Total,
  161. "returned_count": len(response.Cloudregions),
  162. "has_more": response.Total > int64(offset+len(response.Cloudregions)),
  163. "next_offset": offset + len(response.Cloudregions),
  164. }
  165. // 返回格式化后的结果
  166. return formatted
  167. }
  168. // GetName 返回工具名称
  169. // 返回值: 工具名称字符串,用于唯一标识该工具
  170. func (c *CloudpodsRegionsTool) GetName() string {
  171. return "cloudpods_list_regions"
  172. }