Compare commits
4 Commits
14d656eea3
...
b5b2c32477
| Author | SHA1 | Date | |
|---|---|---|---|
| b5b2c32477 | |||
| 11e26601be | |||
| 298ff7c79d | |||
| cab6488d71 |
@@ -128,8 +128,8 @@ func ensureAdminWorkspace() {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建子目录
|
||||
for _, dir := range []string{"projects", "files", "temp"} {
|
||||
// 创建子目录: skills(技能), scripts(脚本), sandbox(沙盒), files(文件), temp(临时)
|
||||
for _, dir := range []string{"skills", "scripts", "sandbox", "files", "temp"} {
|
||||
os.MkdirAll(filepath.Join(workspacePath, dir), 0755)
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func main() {
|
||||
}
|
||||
|
||||
// 3. 自动迁移表
|
||||
db.AutoMigrate(&model.DatabaseInfo{}, &model.SubTableInfo{}, &model.ModelInfo{}, &model.KnowledgeBase{}, &model.KnowledgeDocument{}, &model.User{}, &model.Role{}, &model.Tool{})
|
||||
db.AutoMigrate(&model.DatabaseInfo{}, &model.SubTableInfo{}, &model.ModelInfo{}, &model.KnowledgeBase{}, &model.KnowledgeDocument{}, &model.User{}, &model.Role{}, &model.Tool{}, &model.MCP{})
|
||||
|
||||
// 3.1 确保 users 和 roles 表存在(使用 SQL 强制创建)
|
||||
db.Exec(`
|
||||
@@ -209,6 +209,22 @@ func main() {
|
||||
if !migrator.HasColumn(&model.Tool{}, "parameters") {
|
||||
migrator.AddColumn(&model.Tool{}, "parameters")
|
||||
}
|
||||
if !migrator.HasColumn(&model.Tool{}, "description_cn") {
|
||||
migrator.AddColumn(&model.Tool{}, "description_cn")
|
||||
}
|
||||
// MCP 相关字段
|
||||
if !migrator.HasColumn(&model.Tool{}, "transport") {
|
||||
migrator.AddColumn(&model.Tool{}, "transport")
|
||||
}
|
||||
if !migrator.HasColumn(&model.Tool{}, "command") {
|
||||
migrator.AddColumn(&model.Tool{}, "command")
|
||||
}
|
||||
if !migrator.HasColumn(&model.Tool{}, "args") {
|
||||
migrator.AddColumn(&model.Tool{}, "args")
|
||||
}
|
||||
if !migrator.HasColumn(&model.Tool{}, "env") {
|
||||
migrator.AddColumn(&model.Tool{}, "env")
|
||||
}
|
||||
|
||||
log.Println("Database tables verified/created")
|
||||
|
||||
@@ -219,6 +235,7 @@ func main() {
|
||||
knowledgeRepo := repository.NewKnowledgeRepository(db)
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
toolRepo := repository.NewToolRepository(db)
|
||||
mcpRepo := repository.NewMCPRepository(db)
|
||||
|
||||
// 4.1 初始化默认管理员用户
|
||||
initDefaultAdmin(userRepo)
|
||||
@@ -235,6 +252,7 @@ func main() {
|
||||
knowledgeService := service.NewKnowledgeService(knowledgeRepo, modelRepo, uploadService, cfg.PythonServiceURL, cfg.AICoreServiceAddr, cfg.MarkdownLocalPath)
|
||||
authService := service.NewAuthService(cfg.JWTSecret, userRepo)
|
||||
toolService := service.NewToolService(toolRepo)
|
||||
mcpService := service.NewMCPService(mcpRepo)
|
||||
|
||||
// 4.2 初始化默认工具
|
||||
if err := toolService.InitDefaultTools(); err != nil {
|
||||
@@ -252,6 +270,7 @@ func main() {
|
||||
knowledgeHandler := handler.NewKnowledgeHandler(knowledgeService)
|
||||
authHandler := handler.NewAuthHandler(authService)
|
||||
toolHandler := handler.NewToolHandler(toolService)
|
||||
mcpHandler := handler.NewMCPHandler(mcpService)
|
||||
var uploadHandler *handler.UploadHandler
|
||||
if uploadService != nil {
|
||||
uploadHandler = handler.NewUploadHandler(uploadService, knowledgeRepo)
|
||||
@@ -396,6 +415,16 @@ func main() {
|
||||
toolGroup.DELETE("/:id", toolHandler.Delete)
|
||||
}
|
||||
|
||||
// MCP管理模块
|
||||
mcpGroup := r.Group("/mcp")
|
||||
{
|
||||
mcpGroup.GET("/list", mcpHandler.List)
|
||||
mcpGroup.GET("/:id", mcpHandler.GetByID)
|
||||
mcpGroup.POST("/add", mcpHandler.Create)
|
||||
mcpGroup.PUT("/:id", mcpHandler.Update)
|
||||
mcpGroup.DELETE("/:id", mcpHandler.Delete)
|
||||
}
|
||||
|
||||
// Swagger 文档
|
||||
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
|
||||
@@ -1166,6 +1166,177 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/add": {
|
||||
"post": {
|
||||
"description": "创建新的MCP工具配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "创建MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "MCP信息",
|
||||
"name": "mcp",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.MCP"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/list": {
|
||||
"get": {
|
||||
"description": "获取所有MCP工具配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "获取MCP列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "分类",
|
||||
"name": "category",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/{id}": {
|
||||
"get": {
|
||||
"description": "根据ID获取MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "获取MCP详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "更新MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "更新MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "MCP信息",
|
||||
"name": "mcp",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.MCP"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "删除MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "删除MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/model/add": {
|
||||
"post": {
|
||||
"description": "添加新的AI模型配置",
|
||||
@@ -2007,6 +2178,292 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/add": {
|
||||
"post": {
|
||||
"description": "创建新的工具",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "创建工具",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "工具信息",
|
||||
"name": "tool",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.Tool"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/list": {
|
||||
"get": {
|
||||
"description": "获取所有工具列表,支持按分类和状态筛选",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "获取工具列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具分类",
|
||||
"name": "category",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具状态",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/sync": {
|
||||
"get": {
|
||||
"description": "从代码中的默认配置同步工具到数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "手动同步工具",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/{id}": {
|
||||
"get": {
|
||||
"description": "根据ID获取工具详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "获取工具详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "更新工具信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "更新工具",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "工具信息",
|
||||
"name": "tool",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.Tool"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "删除工具",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "删除工具",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取所有用户列表(需要管理员权限)",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户管理"
|
||||
],
|
||||
"summary": "获取所有用户",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "根据ID获取用户详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户管理"
|
||||
],
|
||||
"summary": "获取用户详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -2363,6 +2820,54 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.MCP": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "参数,JSON数组格式",
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"description": "分类",
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"description": "启动命令",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "英文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"description_cn": {
|
||||
"description": "中文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"description": "环境变量,JSON对象格式",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"transport": {
|
||||
"description": "stdio, http, sse",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.MemoryInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2772,6 +3277,67 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Tool": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "参数,JSON数组格式",
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"description": "启动命令",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "英文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"description_cn": {
|
||||
"description": "中文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"description": "环境变量,JSON对象格式",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"description": "JSON格式存储",
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
"require_approval": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"security_level": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "状态",
|
||||
"type": "string"
|
||||
},
|
||||
"transport": {
|
||||
"description": "MCP 特有字段",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.UpdateDatabaseRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1155,6 +1155,177 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/add": {
|
||||
"post": {
|
||||
"description": "创建新的MCP工具配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "创建MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "MCP信息",
|
||||
"name": "mcp",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.MCP"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/list": {
|
||||
"get": {
|
||||
"description": "获取所有MCP工具配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "获取MCP列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "分类",
|
||||
"name": "category",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/mcp/{id}": {
|
||||
"get": {
|
||||
"description": "根据ID获取MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "获取MCP详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "更新MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "更新MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "MCP信息",
|
||||
"name": "mcp",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.MCP"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "删除MCP配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"MCP管理"
|
||||
],
|
||||
"summary": "删除MCP",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "MCP ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/model/add": {
|
||||
"post": {
|
||||
"description": "添加新的AI模型配置",
|
||||
@@ -1996,6 +2167,292 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/add": {
|
||||
"post": {
|
||||
"description": "创建新的工具",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "创建工具",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "工具信息",
|
||||
"name": "tool",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.Tool"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/list": {
|
||||
"get": {
|
||||
"description": "获取所有工具列表,支持按分类和状态筛选",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "获取工具列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具分类",
|
||||
"name": "category",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具状态",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/sync": {
|
||||
"get": {
|
||||
"description": "从代码中的默认配置同步工具到数据库",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "手动同步工具",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tool/{id}": {
|
||||
"get": {
|
||||
"description": "根据ID获取工具详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "获取工具详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "更新工具信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "更新工具",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "工具信息",
|
||||
"name": "tool",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.Tool"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "删除工具",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"工具管理"
|
||||
],
|
||||
"summary": "删除工具",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "工具ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取所有用户列表(需要管理员权限)",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户管理"
|
||||
],
|
||||
"summary": "获取所有用户",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "根据ID获取用户详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"用户管理"
|
||||
],
|
||||
"summary": "获取用户详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -2352,6 +2809,54 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.MCP": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "参数,JSON数组格式",
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"description": "分类",
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"description": "启动命令",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "英文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"description_cn": {
|
||||
"description": "中文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"description": "环境变量,JSON对象格式",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"transport": {
|
||||
"description": "stdio, http, sse",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.MemoryInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -2761,6 +3266,67 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.Tool": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "参数,JSON数组格式",
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"description": "启动命令",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "英文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"description_cn": {
|
||||
"description": "中文描述",
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"description": "环境变量,JSON对象格式",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"description": "JSON格式存储",
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
"require_approval": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"security_level": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "状态",
|
||||
"type": "string"
|
||||
},
|
||||
"transport": {
|
||||
"description": "MCP 特有字段",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"model.UpdateDatabaseRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -245,6 +245,40 @@ definitions:
|
||||
description: 中文映射名
|
||||
type: string
|
||||
type: object
|
||||
model.MCP:
|
||||
properties:
|
||||
args:
|
||||
description: 参数,JSON数组格式
|
||||
type: string
|
||||
category:
|
||||
description: 分类
|
||||
type: string
|
||||
command:
|
||||
description: 启动命令
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
description:
|
||||
description: 英文描述
|
||||
type: string
|
||||
description_cn:
|
||||
description: 中文描述
|
||||
type: string
|
||||
env:
|
||||
description: 环境变量,JSON对象格式
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
transport:
|
||||
description: stdio, http, sse
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
type: object
|
||||
model.MemoryInfo:
|
||||
properties:
|
||||
available:
|
||||
@@ -536,6 +570,49 @@ definitions:
|
||||
- model_type
|
||||
- provider
|
||||
type: object
|
||||
model.Tool:
|
||||
properties:
|
||||
args:
|
||||
description: 参数,JSON数组格式
|
||||
type: string
|
||||
category:
|
||||
type: string
|
||||
command:
|
||||
description: 启动命令
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
description:
|
||||
description: 英文描述
|
||||
type: string
|
||||
description_cn:
|
||||
description: 中文描述
|
||||
type: string
|
||||
env:
|
||||
description: 环境变量,JSON对象格式
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
parameters:
|
||||
description: JSON格式存储
|
||||
type: string
|
||||
provider:
|
||||
type: string
|
||||
require_approval:
|
||||
type: boolean
|
||||
security_level:
|
||||
type: string
|
||||
status:
|
||||
description: 状态
|
||||
type: string
|
||||
transport:
|
||||
description: MCP 特有字段
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
type: object
|
||||
model.UpdateDatabaseRequest:
|
||||
properties:
|
||||
charset:
|
||||
@@ -1399,6 +1476,120 @@ paths:
|
||||
summary: 获取数据库列表
|
||||
tags:
|
||||
- 数据库管理
|
||||
/mcp/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除MCP配置
|
||||
parameters:
|
||||
- description: MCP ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 删除MCP
|
||||
tags:
|
||||
- MCP管理
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 根据ID获取MCP配置
|
||||
parameters:
|
||||
- description: MCP ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 获取MCP详情
|
||||
tags:
|
||||
- MCP管理
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新MCP配置
|
||||
parameters:
|
||||
- description: MCP ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: MCP信息
|
||||
in: body
|
||||
name: mcp
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.MCP'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 更新MCP
|
||||
tags:
|
||||
- MCP管理
|
||||
/mcp/add:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建新的MCP工具配置
|
||||
parameters:
|
||||
- description: MCP信息
|
||||
in: body
|
||||
name: mcp
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.MCP'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 创建MCP
|
||||
tags:
|
||||
- MCP管理
|
||||
/mcp/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取所有MCP工具配置
|
||||
parameters:
|
||||
- description: 分类
|
||||
in: query
|
||||
name: category
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 获取MCP列表
|
||||
tags:
|
||||
- MCP管理
|
||||
/model/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
@@ -1957,4 +2148,192 @@ paths:
|
||||
summary: 获取系统信息
|
||||
tags:
|
||||
- 系统
|
||||
/tool/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除工具
|
||||
parameters:
|
||||
- description: 工具ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 删除工具
|
||||
tags:
|
||||
- 工具管理
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 根据ID获取工具详情
|
||||
parameters:
|
||||
- description: 工具ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 获取工具详情
|
||||
tags:
|
||||
- 工具管理
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新工具信息
|
||||
parameters:
|
||||
- description: 工具ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: 工具信息
|
||||
in: body
|
||||
name: tool
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.Tool'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 更新工具
|
||||
tags:
|
||||
- 工具管理
|
||||
/tool/add:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建新的工具
|
||||
parameters:
|
||||
- description: 工具信息
|
||||
in: body
|
||||
name: tool
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.Tool'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 创建工具
|
||||
tags:
|
||||
- 工具管理
|
||||
/tool/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取所有工具列表,支持按分类和状态筛选
|
||||
parameters:
|
||||
- description: 工具分类
|
||||
in: query
|
||||
name: category
|
||||
type: string
|
||||
- description: 工具状态
|
||||
in: query
|
||||
name: status
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 获取工具列表
|
||||
tags:
|
||||
- 工具管理
|
||||
/tool/sync:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 从代码中的默认配置同步工具到数据库
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: 手动同步工具
|
||||
tags:
|
||||
- 工具管理
|
||||
/user/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 根据ID获取用户详情
|
||||
parameters:
|
||||
- description: 用户ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 获取用户详情
|
||||
tags:
|
||||
- 用户管理
|
||||
/user/list:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取所有用户列表(需要管理员权限)
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 获取所有用户
|
||||
tags:
|
||||
- 用户管理
|
||||
swagger: "2.0"
|
||||
|
||||
154
server/internal/handler/mcp_handler.go
Normal file
154
server/internal/handler/mcp_handler.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"x-agents/server/internal/model"
|
||||
"x-agents/server/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// MCPHandler MCP工具处理器
|
||||
type MCPHandler struct {
|
||||
mcpService *service.MCPService
|
||||
}
|
||||
|
||||
// NewMCPHandler 创建MCP处理器
|
||||
func NewMCPHandler(mcpService *service.MCPService) *MCPHandler {
|
||||
return &MCPHandler{mcpService: mcpService}
|
||||
}
|
||||
|
||||
// List 获取MCP列表
|
||||
// @Summary 获取MCP列表
|
||||
// @Description 获取所有MCP工具配置
|
||||
// @Tags MCP管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param category query string false "分类"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /mcp/list [get]
|
||||
func (h *MCPHandler) List(c *gin.Context) {
|
||||
category := c.Query("category")
|
||||
|
||||
var mcps []model.MCP
|
||||
var err error
|
||||
|
||||
if category != "" {
|
||||
mcps, err = h.mcpService.GetMCPsByCategory(category)
|
||||
} else {
|
||||
mcps, err = h.mcpService.GetAllMCPs()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"list": mcps, "total": len(mcps)})
|
||||
}
|
||||
|
||||
// GetByID 获取MCP详情
|
||||
// @Summary 获取MCP详情
|
||||
// @Description 根据ID获取MCP配置
|
||||
// @Tags MCP管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "MCP ID"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /mcp/{id} [get]
|
||||
func (h *MCPHandler) GetByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "mcp id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
mcp, err := h.mcpService.GetMCPByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "mcp not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"mcp": mcp})
|
||||
}
|
||||
|
||||
// Create 创建MCP
|
||||
// @Summary 创建MCP
|
||||
// @Description 创建新的MCP工具配置
|
||||
// @Tags MCP管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param mcp body model.MCP true "MCP信息"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /mcp/add [post]
|
||||
func (h *MCPHandler) Create(c *gin.Context) {
|
||||
var mcp model.MCP
|
||||
if err := c.ShouldBindJSON(&mcp); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.mcpService.CreateMCP(&mcp); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "mcp created", "mcp": mcp})
|
||||
}
|
||||
|
||||
// Update 更新MCP
|
||||
// @Summary 更新MCP
|
||||
// @Description 更新MCP配置
|
||||
// @Tags MCP管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "MCP ID"
|
||||
// @Param mcp body model.MCP true "MCP信息"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /mcp/{id} [put]
|
||||
func (h *MCPHandler) Update(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "mcp id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
var mcp model.MCP
|
||||
if err := c.ShouldBindJSON(&mcp); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
mcp.ID = id
|
||||
if err := h.mcpService.UpdateMCP(&mcp); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "mcp updated"})
|
||||
}
|
||||
|
||||
// Delete 删除MCP
|
||||
// @Summary 删除MCP
|
||||
// @Description 删除MCP配置
|
||||
// @Tags MCP管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "MCP ID"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /mcp/{id} [delete]
|
||||
func (h *MCPHandler) Delete(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "mcp id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.mcpService.DeleteMCP(id); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "mcp deleted"})
|
||||
}
|
||||
32
server/internal/model/mcp.go
Normal file
32
server/internal/model/mcp.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// MCP MCP工具配置
|
||||
type MCP struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"name" gorm:"uniqueIndex;size:100;not null"`
|
||||
Description string `json:"description" gorm:"type:text"` // 英文描述
|
||||
DescriptionCN string `json:"description_cn" gorm:"type:text"` // 中文描述
|
||||
Category string `json:"category" gorm:"size:50;not null"` // 分类
|
||||
Transport string `json:"transport" gorm:"size:20;default:'stdio'"` // stdio, http, sse
|
||||
Command string `json:"command" gorm:"size:500"` // 启动命令
|
||||
Args string `json:"args" gorm:"type:text"` // 参数,JSON数组格式
|
||||
Env string `json:"env" gorm:"type:text"` // 环境变量,JSON对象格式
|
||||
Status string `json:"status" gorm:"size:20;default:'active'"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// BeforeCreate 创建前自动生成ID
|
||||
func (m *MCP) BeforeCreate(tx *gorm.DB) error {
|
||||
if m.ID == "" {
|
||||
m.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -11,15 +11,22 @@ import (
|
||||
type Tool struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"name" gorm:"uniqueIndex;size:100;not null"`
|
||||
Description string `json:"description" gorm:"type:text"`
|
||||
Description string `json:"description" gorm:"type:text"` // 英文描述
|
||||
DescriptionCN string `json:"description_cn" gorm:"type:text"` // 中文描述
|
||||
Category string `json:"category" gorm:"size:50;not null"`
|
||||
Provider string `json:"provider" gorm:"size:100"`
|
||||
SecurityLevel string `json:"security_level" gorm:"size:20;default:'safe'"`
|
||||
RequireApproval bool `json:"require_approval" gorm:"default:false"`
|
||||
Parameters string `json:"parameters" gorm:"type:text"` // JSON格式存储
|
||||
Status string `json:"status" gorm:"size:20;default:'active'"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
// MCP 特有字段
|
||||
Transport string `json:"transport" gorm:"size:20;default:'stdio'"` // stdio, http, sse
|
||||
Command string `json:"command" gorm:"size:500"` // 启动命令
|
||||
Args string `json:"args" gorm:"type:text"` // 参数,JSON数组格式
|
||||
Env string `json:"env" gorm:"type:text"` // 环境变量,JSON对象格式
|
||||
// 状态
|
||||
Status string `json:"status" gorm:"size:20;default:'active'"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// BeforeCreate 创建前自动生成ID
|
||||
|
||||
67
server/internal/repository/mcp_repo.go
Normal file
67
server/internal/repository/mcp_repo.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"x-agents/server/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type MCPRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewMCPRepository(db *gorm.DB) *MCPRepository {
|
||||
return &MCPRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *MCPRepository) DB() *gorm.DB {
|
||||
return r.db
|
||||
}
|
||||
|
||||
func (r *MCPRepository) Create(mcp *model.MCP) error {
|
||||
return r.db.Create(mcp).Error
|
||||
}
|
||||
|
||||
func (r *MCPRepository) FindAll() ([]model.MCP, error) {
|
||||
var mcps []model.MCP
|
||||
err := r.db.Order("created_at DESC").Find(&mcps).Error
|
||||
return mcps, err
|
||||
}
|
||||
|
||||
func (r *MCPRepository) FindByID(id string) (*model.MCP, error) {
|
||||
var mcp model.MCP
|
||||
err := r.db.First(&mcp, "id = ?", id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mcp, nil
|
||||
}
|
||||
|
||||
func (r *MCPRepository) FindByName(name string) (*model.MCP, error) {
|
||||
var mcp model.MCP
|
||||
err := r.db.First(&mcp, "name = ?", name).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mcp, nil
|
||||
}
|
||||
|
||||
func (r *MCPRepository) FindByCategory(category string) ([]model.MCP, error) {
|
||||
var mcps []model.MCP
|
||||
err := r.db.Where("category = ?", category).Find(&mcps).Error
|
||||
return mcps, err
|
||||
}
|
||||
|
||||
func (r *MCPRepository) Update(mcp *model.MCP) error {
|
||||
return r.db.Save(mcp).Error
|
||||
}
|
||||
|
||||
func (r *MCPRepository) Delete(id string) error {
|
||||
return r.db.Delete(&model.MCP{}, "id = ?", id).Error
|
||||
}
|
||||
|
||||
func (r *MCPRepository) Count() (int64, error) {
|
||||
var count int64
|
||||
err := r.db.Model(&model.MCP{}).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
@@ -193,8 +193,8 @@ func (s *AuthService) createUserWorkspace(username string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建子目录
|
||||
subDirs := []string{"projects", "files", "temp"}
|
||||
// 创建子目录: skills(技能), scripts(脚本), sandbox(沙盒), files(文件), temp(临时)
|
||||
subDirs := []string{"skills", "scripts", "sandbox", "files", "temp"}
|
||||
for _, dir := range subDirs {
|
||||
if err := os.MkdirAll(filepath.Join(workspacePath, dir), 0755); err != nil {
|
||||
return err
|
||||
|
||||
42
server/internal/service/mcp_service.go
Normal file
42
server/internal/service/mcp_service.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"x-agents/server/internal/model"
|
||||
"x-agents/server/internal/repository"
|
||||
)
|
||||
|
||||
type MCPService struct {
|
||||
mcpRepo *repository.MCPRepository
|
||||
}
|
||||
|
||||
func NewMCPService(mcpRepo *repository.MCPRepository) *MCPService {
|
||||
return &MCPService{mcpRepo: mcpRepo}
|
||||
}
|
||||
|
||||
func (s *MCPService) GetAllMCPs() ([]model.MCP, error) {
|
||||
return s.mcpRepo.FindAll()
|
||||
}
|
||||
|
||||
func (s *MCPService) GetMCPByID(id string) (*model.MCP, error) {
|
||||
return s.mcpRepo.FindByID(id)
|
||||
}
|
||||
|
||||
func (s *MCPService) GetMCPByName(name string) (*model.MCP, error) {
|
||||
return s.mcpRepo.FindByName(name)
|
||||
}
|
||||
|
||||
func (s *MCPService) GetMCPsByCategory(category string) ([]model.MCP, error) {
|
||||
return s.mcpRepo.FindByCategory(category)
|
||||
}
|
||||
|
||||
func (s *MCPService) CreateMCP(mcp *model.MCP) error {
|
||||
return s.mcpRepo.Create(mcp)
|
||||
}
|
||||
|
||||
func (s *MCPService) UpdateMCP(mcp *model.MCP) error {
|
||||
return s.mcpRepo.Update(mcp)
|
||||
}
|
||||
|
||||
func (s *MCPService) DeleteMCP(id string) error {
|
||||
return s.mcpRepo.Delete(id)
|
||||
}
|
||||
@@ -58,12 +58,12 @@ func (s *ToolService) DeleteTool(id string) error {
|
||||
func (s *ToolService) InitDefaultTools() error {
|
||||
log.Println("[ToolService] Starting init default tools...")
|
||||
|
||||
// 获取默认工具
|
||||
tools := s.getDefaultTools()
|
||||
|
||||
// 删除现有的系统工具,重新插入
|
||||
s.toolRepo.DB().Where("provider = ?", "system").Delete(&model.Tool{})
|
||||
log.Printf("[ToolService] Deleted existing system tools, inserting %d default tools...", len(tools))
|
||||
|
||||
// 插入默认工具
|
||||
tools := s.getDefaultTools()
|
||||
log.Printf("[ToolService] Inserting %d default tools...", len(tools))
|
||||
|
||||
for _, tool := range tools {
|
||||
if err := s.toolRepo.Create(&tool); err != nil {
|
||||
@@ -83,6 +83,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "read_file",
|
||||
Description: "Read the contents of a file from the filesystem.",
|
||||
DescriptionCN: "读取文件系统的文件内容。",
|
||||
Category: "file",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -93,6 +94,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "write_file",
|
||||
Description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does.",
|
||||
DescriptionCN: "写入内容到文件。如果文件不存在则创建,存在则覆盖。",
|
||||
Category: "file",
|
||||
SecurityLevel: "review",
|
||||
RequireApproval: true,
|
||||
@@ -103,6 +105,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "list_dir",
|
||||
Description: "List the contents of a directory.",
|
||||
DescriptionCN: "列出目录的内容。",
|
||||
Category: "file",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -113,6 +116,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "delete_file",
|
||||
Description: "Delete a file or directory.",
|
||||
DescriptionCN: "删除文件或目录。",
|
||||
Category: "file",
|
||||
SecurityLevel: "danger",
|
||||
RequireApproval: true,
|
||||
@@ -123,6 +127,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "search_files",
|
||||
Description: "Search for files by name pattern or content.",
|
||||
DescriptionCN: "按文件名模式或内容搜索文件。",
|
||||
Category: "file",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -134,6 +139,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "execute_python",
|
||||
Description: "Execute Python code in a sandboxed environment.",
|
||||
DescriptionCN: "在沙盒环境中执行Python代码。",
|
||||
Category: "executor",
|
||||
SecurityLevel: "review",
|
||||
RequireApproval: true,
|
||||
@@ -144,6 +150,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "execute_javascript",
|
||||
Description: "Execute JavaScript code in a sandboxed environment.",
|
||||
DescriptionCN: "在沙盒环境中执行JavaScript代码。",
|
||||
Category: "executor",
|
||||
SecurityLevel: "review",
|
||||
RequireApproval: true,
|
||||
@@ -154,6 +161,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "execute_bash",
|
||||
Description: "Execute a bash command in a sandboxed environment.",
|
||||
DescriptionCN: "在沙盒环境中执行Bash命令。",
|
||||
Category: "executor",
|
||||
SecurityLevel: "danger",
|
||||
RequireApproval: true,
|
||||
@@ -165,6 +173,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "web_fetch",
|
||||
Description: "Fetch content from a web URL.",
|
||||
DescriptionCN: "从网页URL获取内容。",
|
||||
Category: "web",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -175,6 +184,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "web_search",
|
||||
Description: "Search the web for information.",
|
||||
DescriptionCN: "在网络上搜索信息。",
|
||||
Category: "web",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -186,6 +196,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "http_request",
|
||||
Description: "Make HTTP requests to APIs.",
|
||||
DescriptionCN: "向API发送HTTP请求。",
|
||||
Category: "http",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -197,6 +208,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "send_notification",
|
||||
Description: "Send notifications via email, webhook, dingtalk, or slack.",
|
||||
DescriptionCN: "通过邮件、webhook、钉钉或Slack发送通知。",
|
||||
Category: "notification",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
@@ -208,6 +220,7 @@ func (s *ToolService) getDefaultTools() []model.Tool {
|
||||
{
|
||||
Name: "get_current_time",
|
||||
Description: "Get the current date and time.",
|
||||
DescriptionCN: "获取当前日期和时间。",
|
||||
Category: "system",
|
||||
SecurityLevel: "safe",
|
||||
RequireApproval: false,
|
||||
|
||||
@@ -28,7 +28,7 @@ import { useTools } from './tools/useTools'
|
||||
import '@/views/database/database.css'
|
||||
|
||||
// 使用工具 composable
|
||||
const { tools, toolsLoading, fetchTools, syncTools, deleteTool: deleteToolApi } = useTools()
|
||||
const { tools, toolsLoading, fetchTools, syncTools, deleteTool: deleteToolApi, createTool } = useTools()
|
||||
|
||||
// 图标组件映射
|
||||
const iconComponents: Record<string, any> = {
|
||||
@@ -65,7 +65,8 @@ interface Tool {
|
||||
parameters: string
|
||||
status: string
|
||||
type: 'built-in' | 'mcp'
|
||||
createdAt?: string
|
||||
icon?: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
// 页面加载时获取工具列表
|
||||
@@ -92,6 +93,7 @@ const editForm = ref({
|
||||
name: '',
|
||||
description: '',
|
||||
provider: '',
|
||||
icon: '',
|
||||
})
|
||||
|
||||
// Statistics
|
||||
@@ -123,7 +125,7 @@ const tabCounts = computed(() => ({
|
||||
|
||||
const openEdit = (tool: any) => {
|
||||
editingTool.value = tool
|
||||
editForm.value = { name: tool.name, description: tool.description, provider: tool.provider || '' }
|
||||
editForm.value = { name: tool.name, description: tool.description, provider: tool.provider || '', icon: tool.icon || '' }
|
||||
isEditing.value = true
|
||||
}
|
||||
|
||||
@@ -133,9 +135,32 @@ const saveEdit = () => {
|
||||
|
||||
const cancelEdit = () => { isEditing.value = false; editingTool.value = null }
|
||||
|
||||
const toggleStatus = async (tool: any) => {
|
||||
// 状态切换确认弹窗
|
||||
const showStatusConfirm = ref(false)
|
||||
const toolToToggle = ref<any>(null)
|
||||
|
||||
const confirmToggleStatus = (tool: any) => {
|
||||
toolToToggle.value = tool
|
||||
showStatusConfirm.value = true
|
||||
}
|
||||
|
||||
const toggleStatus = async () => {
|
||||
if (!toolToToggle.value) return
|
||||
|
||||
const tool = toolToToggle.value
|
||||
const newStatus = tool.status === 'active' ? 'inactive' : 'active'
|
||||
const action = newStatus === 'active' ? 'activate' : 'deactivate'
|
||||
|
||||
// TODO: 调用 API 更新状态
|
||||
console.log(`${action} tool:`, tool.name)
|
||||
|
||||
showStatusConfirm.value = false
|
||||
toolToToggle.value = null
|
||||
}
|
||||
|
||||
const cancelToggleStatus = () => {
|
||||
showStatusConfirm.value = false
|
||||
toolToToggle.value = null
|
||||
}
|
||||
|
||||
const handleDeleteTool = async (id: string) => {
|
||||
@@ -148,6 +173,67 @@ const handleDeleteTool = async (id: string) => {
|
||||
const handleSyncTools = async () => {
|
||||
await syncTools()
|
||||
}
|
||||
|
||||
// Add MCP 弹窗
|
||||
const showAddMcp = ref(false)
|
||||
const mcpForm = ref({
|
||||
name: '',
|
||||
description: '',
|
||||
description_cn: '',
|
||||
transport: 'stdio',
|
||||
command: '',
|
||||
args: '',
|
||||
env: '',
|
||||
})
|
||||
|
||||
const openAddMcp = () => {
|
||||
mcpForm.value = {
|
||||
name: '',
|
||||
description: '',
|
||||
description_cn: '',
|
||||
transport: 'stdio',
|
||||
command: '',
|
||||
args: '',
|
||||
env: '',
|
||||
}
|
||||
showAddMcp.value = true
|
||||
}
|
||||
|
||||
const closeAddMcp = () => {
|
||||
showAddMcp.value = false
|
||||
}
|
||||
|
||||
const submitMcp = async () => {
|
||||
try {
|
||||
// 组装参数
|
||||
const argsArray = mcpForm.value.args ? mcpForm.value.args.split('\n').filter((a: string) => a.trim()) : []
|
||||
const envObj: Record<string, string> = {}
|
||||
if (mcpForm.value.env) {
|
||||
mcpForm.value.env.split('\n').forEach((line: string) => {
|
||||
const [key, ...valueParts] = line.split('=')
|
||||
if (key && valueParts.length > 0) {
|
||||
envObj[key.trim()] = valueParts.join('=').trim()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
await createTool({
|
||||
name: mcpForm.value.name,
|
||||
description: mcpForm.value.description,
|
||||
description_cn: mcpForm.value.description_cn,
|
||||
category: 'mcp',
|
||||
provider: 'mcp',
|
||||
transport: mcpForm.value.transport,
|
||||
command: mcpForm.value.command,
|
||||
args: JSON.stringify(argsArray),
|
||||
env: JSON.stringify(envObj),
|
||||
status: 'active',
|
||||
})
|
||||
closeAddMcp()
|
||||
} catch (error) {
|
||||
console.error('Failed to add MCP:', error)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -163,7 +249,7 @@ const handleSyncTools = async () => {
|
||||
<i class="fa-solid fa-sync mr-1"></i>
|
||||
Sync Tools
|
||||
</button>
|
||||
<button v-if="activeTab === 'mcp'" class="btn-primary">
|
||||
<button v-if="activeTab === 'mcp'" @click="openAddMcp" class="btn-primary">
|
||||
<Plus class="w-4 h-4 mr-1" />
|
||||
Add MCP
|
||||
</button>
|
||||
@@ -247,15 +333,19 @@ const handleSyncTools = async () => {
|
||||
<td class="px-5 py-4 text-center text-gray-400 text-sm">{{ tool.created_at || '-' }}</td>
|
||||
<td class="px-5 py-4">
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<button @click="toggleStatus(tool)" class="btn-icon" :title="tool.status === 'active' ? 'Deactivate' : 'Activate'">
|
||||
<!-- 激活/停用按钮 - 所有工具都有 -->
|
||||
<button @click="confirmToggleStatus(tool)" class="btn-icon" :title="tool.status === 'active' ? 'Deactivate' : 'Activate'">
|
||||
<component :is="tool.status === 'active' ? Pause : Play" class="w-4 h-4 text-gray-400 hover:text-white" />
|
||||
</button>
|
||||
<button @click="openEdit(tool)" class="btn-icon" title="Edit">
|
||||
<Edit class="w-4 h-4 text-gray-400 hover:text-white" />
|
||||
</button>
|
||||
<button @click="handleDeleteTool(tool.id)" class="btn-icon" title="Delete">
|
||||
<Trash2 class="w-4 h-4 text-gray-400 hover:text-red-400" />
|
||||
</button>
|
||||
<!-- 编辑和删除按钮 - 只有 MCP 工具才有 -->
|
||||
<template v-if="tool.provider !== 'system'">
|
||||
<button @click="openEdit(tool)" class="btn-icon" title="Edit">
|
||||
<Edit class="w-4 h-4 text-gray-400 hover:text-white" />
|
||||
</button>
|
||||
<button @click="handleDeleteTool(tool.id)" class="btn-icon" title="Delete">
|
||||
<Trash2 class="w-4 h-4 text-gray-400 hover:text-red-400" />
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -292,6 +382,10 @@ const handleSyncTools = async () => {
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Provider</label>
|
||||
<input v-model="editForm.provider" type="text" class="input-field">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Icon</label>
|
||||
<input v-model="editForm.icon" type="text" placeholder="e.g., FileText, Globe, Code" class="input-field">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Description</label>
|
||||
<textarea v-model="editForm.description" rows="3" class="input-field resize-none"></textarea>
|
||||
@@ -305,6 +399,107 @@ const handleSyncTools = async () => {
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<!-- 状态切换确认弹窗 -->
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
<div v-if="showStatusConfirm" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50" @click="cancelToggleStatus">
|
||||
<div class="bg-dark-700 rounded-xl w-full max-w-sm border border-dark-500 shadow-2xl" @click.stop>
|
||||
<div class="p-6 text-center">
|
||||
<div class="w-14 h-14 rounded-full flex items-center justify-center mx-auto mb-4" :class="toolToToggle?.status === 'active' ? 'bg-yellow-500/20' : 'bg-green-500/20'">
|
||||
<component :is="toolToToggle?.status === 'active' ? Pause : Play" class="text-xl" :class="toolToToggle?.status === 'active' ? 'text-yellow-400' : 'text-green-400'" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-white mb-2">
|
||||
{{ toolToToggle?.status === 'active' ? 'Stop Tool' : 'Activate Tool' }}
|
||||
</h3>
|
||||
<p class="text-gray-400 text-sm">
|
||||
{{ toolToToggle?.status === 'active'
|
||||
? `Are you sure you want to stop "${toolToToggle?.name}"? This tool will no longer be available.`
|
||||
: `Are you sure you want to activate "${toolToToggle?.name}"? This tool will become available.`
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex border-t border-dark-500">
|
||||
<button @click="cancelToggleStatus" class="flex-1 py-3 text-gray-400 hover:text-white hover:bg-dark-600 transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button @click="toggleStatus" class="flex-1 py-3 transition-colors border-l border-dark-500" :class="toolToToggle?.status === 'active' ? 'text-yellow-400 hover:bg-yellow-500/10' : 'text-green-400 hover:bg-green-500/10'">
|
||||
{{ toolToToggle?.status === 'active' ? 'Stop' : 'Activate' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
<!-- Add MCP 弹窗 -->
|
||||
<Teleport to="body">
|
||||
<div v-if="showAddMcp" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50 modal-overlay" @click="closeAddMcp">
|
||||
<div class="bg-dark-700 rounded-2xl w-full max-w-xl border border-dark-500 shadow-2xl modal-content" @click.stop>
|
||||
<div class="flex items-center justify-between p-5 border-b border-dark-500">
|
||||
<h3 class="text-lg font-semibold">Add MCP Server</h3>
|
||||
<button @click="closeAddMcp" class="btn-icon">
|
||||
<X class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="p-5 space-y-4 max-h-[70vh] overflow-y-auto">
|
||||
<!-- MCP Name -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">MCP Name <span class="text-red-400">*</span></label>
|
||||
<input v-model="mcpForm.name" type="text" class="input-field" placeholder="e.g., filesystem, memory">
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Description (English)</label>
|
||||
<textarea v-model="mcpForm.description" rows="2" class="input-field resize-none" placeholder="Describe what this MCP server does"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Description CN -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Description (中文)</label>
|
||||
<textarea v-model="mcpForm.description_cn" rows="2" class="input-field resize-none" placeholder="描述这个 MCP 服务器的功能"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Transport -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Transport Protocol <span class="text-red-400">*</span></label>
|
||||
<select v-model="mcpForm.transport" class="input-field">
|
||||
<option value="stdio">stdio</option>
|
||||
<option value="http">HTTP</option>
|
||||
<option value="sse">SSE</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Command -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Start Command <span class="text-red-400">*</span></label>
|
||||
<input v-model="mcpForm.command" type="text" class="input-field" placeholder="e.g., npx, python, node">
|
||||
</div>
|
||||
|
||||
<!-- Args -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Arguments</label>
|
||||
<textarea v-model="mcpForm.args" rows="3" class="input-field resize-none" placeholder="One argument per line, e.g.: -y @modelcontextprotocol/server-filesystem /path/to/dir"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Environment Variables -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Environment Variables</label>
|
||||
<textarea v-model="mcpForm.env" rows="3" class="input-field resize-none" placeholder="KEY=value format, one per line, e.g.: API_KEY=xxx DEBUG=true"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 p-5 border-t border-dark-500">
|
||||
<button @click="closeAddMcp" class="btn-secondary">Cancel</button>
|
||||
<button @click="submitMcp" class="btn-primary" :disabled="!mcpForm.name || !mcpForm.command">
|
||||
Add MCP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,19 +1,49 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
|
||||
const API_BASE = 'http://localhost:8082'
|
||||
|
||||
export interface Skill {
|
||||
id: number
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
type: string
|
||||
description_cn?: string
|
||||
command: string
|
||||
args?: string
|
||||
env?: string
|
||||
category: string
|
||||
status: 'running' | 'stopped' | 'error'
|
||||
port: number
|
||||
createdAt: string
|
||||
tools: number
|
||||
status: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
export function useSkills() {
|
||||
// 从 API 获取 MCP 列表
|
||||
const fetchSkills = async () => {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/mcp/list`)
|
||||
const result = await response.json()
|
||||
if (result && Array.isArray(result)) {
|
||||
skills.value = result.map((mcp: any) => ({
|
||||
id: mcp.id,
|
||||
name: mcp.name,
|
||||
description: mcp.description || '',
|
||||
description_cn: mcp.description_cn || '',
|
||||
command: mcp.command || '',
|
||||
args: mcp.args || '',
|
||||
env: mcp.env || '',
|
||||
category: mcp.category || 'custom',
|
||||
status: mcp.status || 'stopped',
|
||||
created_at: mcp.created_at,
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch MCP list:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchSkills()
|
||||
})
|
||||
// Skill 数据
|
||||
const skills = ref<Skill[]>([
|
||||
{ id: 1, name: 'Linear', description: 'Linear API integration for project management', type: 'API', category: 'api', status: 'running', port: 3001, createdAt: '2025-04-10', tools: 12 },
|
||||
|
||||
Reference in New Issue
Block a user