api_creator.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package mcpTool
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/flipped-aurora/gin-vue-admin/server/global"
  8. "github.com/flipped-aurora/gin-vue-admin/server/model/system"
  9. "github.com/flipped-aurora/gin-vue-admin/server/service"
  10. "github.com/mark3labs/mcp-go/mcp"
  11. "go.uber.org/zap"
  12. )
  13. // 注册工具
  14. func init() {
  15. RegisterTool(&ApiCreator{})
  16. }
  17. // ApiCreateRequest API创建请求结构
  18. type ApiCreateRequest struct {
  19. Path string `json:"path"` // API路径
  20. Description string `json:"description"` // API中文描述
  21. ApiGroup string `json:"apiGroup"` // API组
  22. Method string `json:"method"` // HTTP方法
  23. }
  24. // ApiCreateResponse API创建响应结构
  25. type ApiCreateResponse struct {
  26. Success bool `json:"success"`
  27. Message string `json:"message"`
  28. ApiID uint `json:"apiId"`
  29. Path string `json:"path"`
  30. Method string `json:"method"`
  31. }
  32. // ApiCreator API创建工具
  33. type ApiCreator struct{}
  34. // New 创建API创建工具
  35. func (a *ApiCreator) New() mcp.Tool {
  36. return mcp.NewTool("create_api",
  37. mcp.WithDescription(`创建后端API记录,用于AI编辑器自动添加API接口时自动创建对应的API权限记录。
  38. **重要限制:**
  39. - 当使用gva_auto_generate工具且needCreatedModules=true时,模块创建会自动生成API权限,不应调用此工具
  40. - 仅在以下情况使用:1) 单独创建API(不涉及模块创建);2) AI编辑器自动添加API;3) router下的文件产生路径变化时`),
  41. mcp.WithString("path",
  42. mcp.Required(),
  43. mcp.Description("API路径,如:/user/create"),
  44. ),
  45. mcp.WithString("description",
  46. mcp.Required(),
  47. mcp.Description("API中文描述,如:创建用户"),
  48. ),
  49. mcp.WithString("apiGroup",
  50. mcp.Required(),
  51. mcp.Description("API组名称,用于分类管理,如:用户管理"),
  52. ),
  53. mcp.WithString("method",
  54. mcp.Description("HTTP方法"),
  55. mcp.DefaultString("POST"),
  56. ),
  57. mcp.WithString("apis",
  58. mcp.Description("批量创建API的JSON字符串,格式:[{\"path\":\"/user/create\",\"description\":\"创建用户\",\"apiGroup\":\"用户管理\",\"method\":\"POST\"}]"),
  59. ),
  60. )
  61. }
  62. // Handle 处理API创建请求
  63. func (a *ApiCreator) Handle(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  64. args := request.GetArguments()
  65. var apis []ApiCreateRequest
  66. // 检查是否是批量创建
  67. if apisStr, ok := args["apis"].(string); ok && apisStr != "" {
  68. if err := json.Unmarshal([]byte(apisStr), &apis); err != nil {
  69. return nil, fmt.Errorf("apis 参数格式错误: %v", err)
  70. }
  71. } else {
  72. // 单个API创建
  73. path, ok := args["path"].(string)
  74. if !ok || path == "" {
  75. return nil, errors.New("path 参数是必需的")
  76. }
  77. description, ok := args["description"].(string)
  78. if !ok || description == "" {
  79. return nil, errors.New("description 参数是必需的")
  80. }
  81. apiGroup, ok := args["apiGroup"].(string)
  82. if !ok || apiGroup == "" {
  83. return nil, errors.New("apiGroup 参数是必需的")
  84. }
  85. method := "POST"
  86. if val, ok := args["method"].(string); ok && val != "" {
  87. method = val
  88. }
  89. apis = append(apis, ApiCreateRequest{
  90. Path: path,
  91. Description: description,
  92. ApiGroup: apiGroup,
  93. Method: method,
  94. })
  95. }
  96. if len(apis) == 0 {
  97. return nil, errors.New("没有要创建的API")
  98. }
  99. // 创建API记录
  100. apiService := service.ServiceGroupApp.SystemServiceGroup.ApiService
  101. var responses []ApiCreateResponse
  102. successCount := 0
  103. for _, apiReq := range apis {
  104. api := system.SysApi{
  105. Path: apiReq.Path,
  106. Description: apiReq.Description,
  107. ApiGroup: apiReq.ApiGroup,
  108. Method: apiReq.Method,
  109. }
  110. err := apiService.CreateApi(api)
  111. if err != nil {
  112. global.GVA_LOG.Warn("创建API失败",
  113. zap.String("path", apiReq.Path),
  114. zap.String("method", apiReq.Method),
  115. zap.Error(err))
  116. responses = append(responses, ApiCreateResponse{
  117. Success: false,
  118. Message: fmt.Sprintf("创建API失败: %v", err),
  119. Path: apiReq.Path,
  120. Method: apiReq.Method,
  121. })
  122. } else {
  123. // 获取创建的API ID
  124. var createdApi system.SysApi
  125. err = global.GVA_DB.Where("path = ? AND method = ?", apiReq.Path, apiReq.Method).First(&createdApi).Error
  126. if err != nil {
  127. global.GVA_LOG.Warn("获取创建的API ID失败", zap.Error(err))
  128. }
  129. responses = append(responses, ApiCreateResponse{
  130. Success: true,
  131. Message: fmt.Sprintf("成功创建API %s %s", apiReq.Method, apiReq.Path),
  132. ApiID: createdApi.ID,
  133. Path: apiReq.Path,
  134. Method: apiReq.Method,
  135. })
  136. successCount++
  137. }
  138. }
  139. // 构建总体响应
  140. var resultMessage string
  141. if len(apis) == 1 {
  142. resultMessage = responses[0].Message
  143. } else {
  144. resultMessage = fmt.Sprintf("批量创建API完成,成功 %d 个,失败 %d 个", successCount, len(apis)-successCount)
  145. }
  146. result := map[string]interface{}{
  147. "success": successCount > 0,
  148. "message": resultMessage,
  149. "totalCount": len(apis),
  150. "successCount": successCount,
  151. "failedCount": len(apis) - successCount,
  152. "details": responses,
  153. }
  154. resultJSON, err := json.MarshalIndent(result, "", " ")
  155. if err != nil {
  156. return nil, fmt.Errorf("序列化结果失败: %v", err)
  157. }
  158. // 添加权限分配提醒
  159. permissionReminder := "\n\n⚠️ 重要提醒:\n" +
  160. "API创建完成后,请前往【系统管理】->【角色管理】中为相关角色分配新创建的API权限," +
  161. "以确保用户能够正常访问新接口。\n" +
  162. "具体步骤:\n" +
  163. "1. 进入角色管理页面\n" +
  164. "2. 选择需要授权的角色\n" +
  165. "3. 在API权限中勾选新创建的API接口\n" +
  166. "4. 保存权限配置"
  167. return &mcp.CallToolResult{
  168. Content: []mcp.Content{
  169. mcp.TextContent{
  170. Type: "text",
  171. Text: fmt.Sprintf("API创建结果:\n\n%s%s", string(resultJSON), permissionReminder),
  172. },
  173. },
  174. }, nil
  175. }