diff --git a/internal/config/config.go b/internal/config/config.go index 72db8808..8d37e9eb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -52,8 +52,9 @@ type OpenAIConfig struct { } type SecurityConfig struct { - Tools []ToolConfig `yaml:"tools,omitempty"` // 向后兼容:支持在主配置文件中定义工具 - ToolsDir string `yaml:"tools_dir,omitempty"` // 工具配置文件目录(新方式) + Tools []ToolConfig `yaml:"tools,omitempty"` // 向后兼容:支持在主配置文件中定义工具 + ToolsDir string `yaml:"tools_dir,omitempty"` // 工具配置文件目录(新方式) + ToolDescriptionMode string `yaml:"tool_description_mode,omitempty"` // 工具描述模式: "short" | "full",默认 short } type DatabaseConfig struct { diff --git a/internal/handler/config.go b/internal/handler/config.go index eeeb22c4..a8aa4112 100644 --- a/internal/handler/config.go +++ b/internal/handler/config.go @@ -174,18 +174,10 @@ func (h *ConfigHandler) GetConfig(c *gin.Context) { configToolMap[tool.Name] = true tools = append(tools, ToolConfigInfo{ Name: tool.Name, - Description: tool.ShortDescription, + Description: h.pickToolDescription(tool.ShortDescription, tool.Description), Enabled: tool.Enabled, IsExternal: false, }) - // 如果没有简短描述,使用详细描述的前10000个字符 - if tools[len(tools)-1].Description == "" { - desc := tool.Description - if len(desc) > 10000 { - desc = desc[:10000] + "..." - } - tools[len(tools)-1].Description = desc - } } // 从MCP服务器获取所有已注册的工具(包括直接注册的工具,如知识检索工具) @@ -291,18 +283,10 @@ func (h *ConfigHandler) GetTools(c *gin.Context) { configToolMap[tool.Name] = true toolInfo := ToolConfigInfo{ Name: tool.Name, - Description: tool.ShortDescription, + Description: h.pickToolDescription(tool.ShortDescription, tool.Description), Enabled: tool.Enabled, IsExternal: false, } - // 如果没有简短描述,使用详细描述的前10000个字符 - if toolInfo.Description == "" { - desc := tool.Description - if len(desc) > 10000 { - desc = desc[:10000] + "..." - } - toolInfo.Description = desc - } // 根据角色配置标注工具状态 if roleName != "" { @@ -1193,7 +1177,7 @@ func (h *ConfigHandler) getExternalMCPTools(ctx context.Context) []ToolConfigInf enabled := h.calculateExternalToolEnabled(mcpName, actualToolName, externalMCPConfigs) // 处理描述信息 - description := h.formatToolDescription(externalTool.ShortDescription, externalTool.Description) + description := h.pickToolDescription(externalTool.ShortDescription, externalTool.Description) result = append(result, ToolConfigInfo{ Name: actualToolName, @@ -1249,10 +1233,13 @@ func (h *ConfigHandler) calculateExternalToolEnabled(mcpName, toolName string, c return true } -// formatToolDescription 格式化工具描述(限制长度) -func (h *ConfigHandler) formatToolDescription(shortDesc, fullDesc string) string { +// pickToolDescription 根据 security.tool_description_mode 选择 short 或 full 描述并限制长度 +func (h *ConfigHandler) pickToolDescription(shortDesc, fullDesc string) string { + useFull := strings.TrimSpace(strings.ToLower(h.config.Security.ToolDescriptionMode)) == "full" description := shortDesc - if description == "" { + if useFull { + description = fullDesc + } else if description == "" { description = fullDesc } if len(description) > 10000 { diff --git a/internal/security/executor.go b/internal/security/executor.go index 96de9620..48ec06ad 100644 --- a/internal/security/executor.go +++ b/internal/security/executor.go @@ -224,13 +224,13 @@ func (e *Executor) RegisterTools(mcpServer *mcp.Server) { toolName := toolConfig.Name toolConfigCopy := toolConfig - // 使用简短描述(如果存在),否则使用详细描述的前10000个字符 + // 根据配置决定暴露给 AI/API 的描述:short_description 或 description + useFullDescription := strings.TrimSpace(strings.ToLower(e.config.ToolDescriptionMode)) == "full" shortDesc := toolConfigCopy.ShortDescription if shortDesc == "" { // 如果没有简短描述,从详细描述中提取第一行或前10000个字符 desc := toolConfigCopy.Description if len(desc) > 10000 { - // 尝试找到第一个换行符 if idx := strings.Index(desc, "\n"); idx > 0 && idx < 10000 { shortDesc = strings.TrimSpace(desc[:idx]) } else { @@ -240,6 +240,9 @@ func (e *Executor) RegisterTools(mcpServer *mcp.Server) { shortDesc = desc } } + if useFullDescription { + shortDesc = "" // 使用 description 时清空 ShortDescription,下游会回退到 Description + } tool := mcp.Tool{ Name: toolConfigCopy.Name, @@ -303,7 +306,23 @@ func (e *Executor) buildCommandArgs(toolName string, toolConfig *config.ToolConf } } - // 先处理标志参数(对于大多数命令,标志应该在位置参数之前) + // 对于需要子命令的工具(如 gobuster dir),position 0 必须紧跟在命令名后、所有 flag 之前 + for _, param := range positionalParams { + if param.Name == "additional_args" || param.Name == "scan_type" || param.Name == "action" { + continue + } + if param.Position != nil && *param.Position == 0 { + value := e.getParamValue(args, param) + if value == nil && param.Default != nil { + value = param.Default + } + if value != nil { + cmdArgs = append(cmdArgs, e.formatParamValue(param, value)) + } + break + } + } + // 处理标志参数 for _, param := range flagParams { // 跳过特殊参数,它们会在后面单独处理 @@ -416,7 +435,11 @@ func (e *Executor) buildCommandArgs(toolName string, toolConfig *config.ToolConf } // 按位置顺序处理参数,确保即使某些位置没有参数或使用默认值,也能正确传递 + // position 0 已在前面插入(子命令优先),此处从 1 开始 for i := 0; i <= maxPosition; i++ { + if i == 0 { + continue + } for _, param := range positionalParams { // 跳过特殊参数,它们会在后面单独处理 // action 参数仅用于工具内部逻辑,不传递给命令