package tools import ( "context" "encoding/json" "strings" "github.com/mark3labs/mcp-go/mcp" "fwh-toolbox-server/agentmcp/kit" "fwh-toolbox-server/dto" "fwh-toolbox-server/services" ) // ServiceAccount 写操作在业务系统中的执行身份(Agent MCP 不区分调用者) const ServiceAccount = "AI 助手" // ---- feedback_create ---- type feedbackCreateArgs struct { Title string `json:"title" jsonschema:"标题"` Type string `json:"type" jsonschema:"类型:bug 或 feature"` Priority string `json:"priority,omitempty" jsonschema:"优先级:urgent、high、medium(默认)、low、none"` Category string `json:"category,omitempty" jsonschema:"分类:bug 类为 bug、ui、performance、other;feature 类为 new、improvement、experience"` Description string `json:"description,omitempty" jsonschema:"详细描述:背景、现象、影响站点、复现步骤等"` } var FeedbackCreate = kit.Def[feedbackCreateArgs]{ Name: "feedback_create", Title: "提交问题反馈到 Plane", Description: "在 Plane 中创建一条 Intake 工作项(问题反馈或需求)。提交人固定为服务账号“AI 助手”,请在描述中写明背景与来源。" + "返回 Plane 创建结果(工作项 ID 等)。这是写操作,执行前会请求确认。", ReadOnly: false, Handler: func(ctx context.Context, a feedbackCreateArgs) (*mcp.CallToolResult, error) { title, err := kit.Required("title", a.Title) if err != nil { return kit.Fail(err), nil } typ, err := kit.Enum("type", a.Type, "", "bug", "feature") if err != nil { return kit.Fail(err), nil } if typ == "" { return kit.Failf("参数 type 必填:bug 或 feature"), nil } priority, err := kit.Enum("priority", a.Priority, "medium", "urgent", "high", "medium", "low", "none") if err != nil { return kit.Fail(err), nil } res, err := services.SubmitFeedback(dto.FeedbackSubmitDTO{ Title: title, Type: typ, Priority: priority, Category: strings.TrimSpace(a.Category), Description: a.Description, }, ServiceAccount) if err != nil { return kit.Upstream("Plane", err), nil } return kit.Object(res), nil }, } // ---- tou_template_save ---- type touTemplateSaveArgs struct { Payload string `json:"payload" jsonschema:"模版请求体 JSON:{\"template\":{...},\"strategyList\":[{...}],\"lang\":\"ZH_CN\"}。template.templateId 有值为更新、省略为新增;字段定义见技能 references 中的 TOU 模版说明"` } var TouTemplateSave = kit.Def[touTemplateSaveArgs]{ Name: "tou_template_save", Title: "保存 TOU 调度模版(测试服)", Description: "在 FWH 测试服新增或更新 TOU 调度模版,只支持测试服。保存前校验每个策略的时段首尾衔接覆盖全天、sourceType 为 0;" + "返回 templateId 与按调度模式识别后的策略摘要。这是写操作,执行前会请求确认。", ReadOnly: false, Handler: func(ctx context.Context, a touTemplateSaveArgs) (*mcp.CallToolResult, error) { raw, err := kit.Required("payload", a.Payload) if err != nil { return kit.Fail(err), nil } var payload dto.FwhTestUpdateOrSaveTouTemplatePayload if err := json.Unmarshal([]byte(raw), &payload); err != nil { return kit.Failf("参数 payload 不是有效的 JSON:%v", err), nil } if payload.Template.SourceType != 0 { return kit.Failf("template.sourceType 只能为 0(系统模版)"), nil } if len(payload.StrategyList) == 0 { return kit.Failf("strategyList 不能为空"), nil } organized, _ := OrganizeTouDetail(payload) if issues := strategyIssues(organized); len(issues) > 0 { return kit.Failf("模版校验未通过:%s", strings.Join(issues, ";")), nil } if payload.Lang == "" { payload.Lang = "ZH_CN" } id, err := services.FwhTestSaveTouTemplate(payload) if err != nil { return kit.Upstream("FWH 测试服 TOU 模版接口", err), nil } return kit.Object(map[string]any{"templateId": id, "message": "已保存到测试服", "strategies": organized["strategies"]}), nil }, } // strategyIssues 汇总整理结果中的时段衔接问题。 func strategyIssues(organized map[string]any) []string { var out []string sts, _ := organized["strategies"].([]map[string]any) for _, st := range sts { if is, ok := st["issues"].([]string); ok { name, _ := st["seasonName"].(string) day, _ := st["dayName"].(string) for _, i := range is { out = append(out, name+"/"+day+":"+i) } } } return out } // ---- site_info_refresh ---- var SiteInfoRefresh = kit.Def[kit.NoArgs]{ Name: "site_info_refresh", Title: "触发站点信息表更新", Description: "触发 ToolBox 站点信息表的更新任务(从 FWH 平台同步最新站点数据),任务在后台执行。" + "返回是否已触发;同步通常需要数分钟,完成后 site_search 的结果才会更新。这是写操作,执行前会请求确认。", ReadOnly: false, Handler: func(ctx context.Context, _ kit.NoArgs) (*mcp.CallToolResult, error) { if err := services.UpdateSiteInfoDate(); err != nil { return kit.Upstream("ToolBox 站点信息更新", err), nil } return mcp.NewToolResultText("已触发站点信息表更新,任务在后台执行。"), nil }, }