@@ -0,0 +1,165 @@
|
||||
package mcpTool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// 注册工具
|
||||
func init() {
|
||||
// 注册工具将在enter.go中统一处理
|
||||
RegisterTool(&ApiLister{})
|
||||
}
|
||||
|
||||
// ApiInfo API信息结构
|
||||
type ApiInfo struct {
|
||||
ID uint `json:"id,omitempty"` // 数据库ID(仅数据库API有)
|
||||
Path string `json:"path"` // API路径
|
||||
Description string `json:"description,omitempty"` // API描述
|
||||
ApiGroup string `json:"apiGroup,omitempty"` // API组
|
||||
Method string `json:"method"` // HTTP方法
|
||||
Source string `json:"source"` // 来源:database 或 gin
|
||||
}
|
||||
|
||||
// ApiListResponse API列表响应结构
|
||||
type ApiListResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
DatabaseApis []ApiInfo `json:"databaseApis"` // 数据库中的API
|
||||
GinApis []ApiInfo `json:"ginApis"` // gin框架中的API
|
||||
TotalCount int `json:"totalCount"` // 总数量
|
||||
}
|
||||
|
||||
// ApiLister API列表工具
|
||||
type ApiLister struct{}
|
||||
|
||||
// New 创建API列表工具
|
||||
func (a *ApiLister) New() mcp.Tool {
|
||||
return mcp.NewTool("list_all_apis",
|
||||
mcp.WithDescription(`获取系统中所有的API接口,分为两组:
|
||||
|
||||
**功能说明:**
|
||||
- 返回数据库中已注册的API列表
|
||||
- 返回gin框架中实际注册的路由API列表
|
||||
- 帮助前端判断是使用现有API还是需要创建新的API,如果api在前端未使用且需要前端调用的时候,请到api文件夹下对应模块的js中添加方法并暴露给当前业务调用
|
||||
|
||||
**返回数据结构:**
|
||||
- databaseApis: 数据库中的API记录(包含ID、描述、分组等完整信息)
|
||||
- ginApis: gin路由中的API(仅包含路径和方法),需要AI根据路径自行揣摩路径的业务含义,例如:/api/user/:id 表示根据用户ID获取用户信息`),
|
||||
)
|
||||
}
|
||||
|
||||
// Handle 处理API列表请求
|
||||
func (a *ApiLister) Handle(_ context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
|
||||
// 获取数据库中的API
|
||||
databaseApis, err := a.getDatabaseApis()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取数据库API失败", zap.Error(err))
|
||||
errorResponse := ApiListResponse{
|
||||
Success: false,
|
||||
Message: "获取数据库API失败: " + err.Error(),
|
||||
}
|
||||
resultJSON, _ := json.Marshal(errorResponse)
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(resultJSON),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 获取gin路由中的API
|
||||
ginApis, err := a.getGinApis()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取gin路由API失败", zap.Error(err))
|
||||
errorResponse := ApiListResponse{
|
||||
Success: false,
|
||||
Message: "获取gin路由API失败: " + err.Error(),
|
||||
}
|
||||
resultJSON, _ := json.Marshal(errorResponse)
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(resultJSON),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := ApiListResponse{
|
||||
Success: true,
|
||||
Message: "获取API列表成功",
|
||||
DatabaseApis: databaseApis,
|
||||
GinApis: ginApis,
|
||||
TotalCount: len(databaseApis) + len(ginApis),
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("API列表获取成功",
|
||||
zap.Int("数据库API数量", len(databaseApis)),
|
||||
zap.Int("gin路由API数量", len(ginApis)),
|
||||
zap.Int("总数量", response.TotalCount))
|
||||
|
||||
resultJSON, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("序列化结果失败: %v", err)
|
||||
}
|
||||
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(resultJSON),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getDatabaseApis 获取数据库中的所有API
|
||||
func (a *ApiLister) getDatabaseApis() ([]ApiInfo, error) {
|
||||
var apis []system.SysApi
|
||||
err := global.GVA_DB.Model(&system.SysApi{}).Order("api_group ASC, path ASC").Find(&apis).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为ApiInfo格式
|
||||
var result []ApiInfo
|
||||
for _, api := range apis {
|
||||
result = append(result, ApiInfo{
|
||||
ID: api.ID,
|
||||
Path: api.Path,
|
||||
Description: api.Description,
|
||||
ApiGroup: api.ApiGroup,
|
||||
Method: api.Method,
|
||||
Source: "database",
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// getGinApis 获取gin路由中的所有API(包含被忽略的API)
|
||||
func (a *ApiLister) getGinApis() ([]ApiInfo, error) {
|
||||
// 从gin路由信息中获取所有API
|
||||
var result []ApiInfo
|
||||
for _, route := range global.GVA_ROUTERS {
|
||||
result = append(result, ApiInfo{
|
||||
Path: route.Path,
|
||||
Method: route.Method,
|
||||
Source: "gin",
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package mcpTool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// 注册工具
|
||||
func init() {
|
||||
// 注册工具将在enter.go中统一处理
|
||||
RegisterTool(&MenuLister{})
|
||||
}
|
||||
|
||||
// MenuListResponse 菜单列表响应结构
|
||||
type MenuListResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Menus []system.SysBaseMenu `json:"menus"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// MenuLister 菜单列表工具
|
||||
type MenuLister struct{}
|
||||
|
||||
// New 创建菜单列表工具
|
||||
func (m *MenuLister) New() mcp.Tool {
|
||||
return mcp.NewTool("list_all_menus",
|
||||
mcp.WithDescription(`获取系统中所有菜单信息,包括菜单树结构、路由信息、组件路径等,用于前端编写vue-router时正确跳转
|
||||
|
||||
**功能说明:**
|
||||
- 返回完整的菜单树形结构
|
||||
- 包含路由配置信息(path、name、component)
|
||||
- 包含菜单元数据(title、icon、keepAlive等)
|
||||
- 包含菜单参数和按钮配置
|
||||
- 支持父子菜单关系展示
|
||||
|
||||
**使用场景:**
|
||||
- 前端路由配置:获取所有菜单信息用于配置vue-router
|
||||
- 菜单权限管理:了解系统中所有可用的菜单项
|
||||
- 导航组件开发:构建动态导航菜单
|
||||
- 系统架构分析:了解系统的菜单结构和页面组织`),
|
||||
)
|
||||
}
|
||||
|
||||
// Handle 处理菜单列表请求
|
||||
func (m *MenuLister) Handle(_ context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
// 获取所有基础菜单
|
||||
allMenus, err := m.getAllMenus()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取菜单列表失败", zap.Error(err))
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: fmt.Sprintf("获取菜单列表失败: %v", err),
|
||||
},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
response := MenuListResponse{
|
||||
Success: true,
|
||||
Message: "获取菜单列表成功",
|
||||
Menus: allMenus,
|
||||
TotalCount: len(allMenus),
|
||||
Description: "系统中所有菜单信息的标准列表,包含路由配置和组件信息",
|
||||
}
|
||||
|
||||
// 序列化响应
|
||||
responseJSON, err := json.MarshalIndent(response, "", " ")
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("序列化菜单响应失败", zap.Error(err))
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: fmt.Sprintf("序列化响应失败: %v", err),
|
||||
},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(responseJSON),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getAllMenus 获取所有基础菜单
|
||||
func (m *MenuLister) getAllMenus() ([]system.SysBaseMenu, error) {
|
||||
var menus []system.SysBaseMenu
|
||||
err := global.GVA_DB.Order("sort").Preload("Parameters").Preload("MenuBtn").Find(&menus).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menus, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user