package tools import ( "context" "sort" "strconv" "strings" "time" "github.com/mark3labs/mcp-go/mcp" "fwh-toolbox-server/agentmcp/kit" "fwh-toolbox-server/domain" "fwh-toolbox-server/repositories" ) // ---- mqtt_log_search ---- type mqttLogSearchArgs struct { SN string `json:"sn" jsonschema:"站点 SN(aGate 序列号)"` CmdType string `json:"cmdType" jsonschema:"MQTT 命令类型,如 0(连接中断)、101(登录)、105(心跳)、107(参数更新)、201、211 等"` From string `json:"from" jsonschema:"开始时间,yyyy-MM-dd HH:mm:ss"` To string `json:"to" jsonschema:"结束时间,同上;与开始时间相差不超过 7 天"` Limit int `json:"limit,omitempty" jsonschema:"最多返回条数,1~300,默认 50"` } // MqttRow mqtt_log_search 的精简行 type MqttRow struct { LogTime string `json:"logTime"` // 设备时间 Time string `json:"time,omitempty"` // UTC 时间 Cmd string `json:"cmd,omitempty"` Data string `json:"data,omitempty"` // 原始报文,超过 1500 字截断 } var MqttLogSearch = kit.Def[mqttLogSearchArgs]{ Name: "mqtt_log_search", Title: "查询站点 MQTT 日志", Description: "查询单个站点在一段时间内某类 MQTT 命令的日志(FWH 平台),按时间倒序。" + "返回字段:logTime(设备时间)、time(UTC)、cmd、data(原始报文 JSON,超过 1500 字截断)。报文较大,建议缩小时间范围、减少 limit。", ReadOnly: true, Handler: func(ctx context.Context, a mqttLogSearchArgs) (*mcp.CallToolResult, error) { sn, err := kit.Required("sn", a.SN) if err != nil { return kit.Fail(err), nil } cmd, err := kit.Required("cmdType", a.CmdType) if err != nil { return kit.Fail(err), nil } from, to, err := kit.ParseRange(a.From, a.To, 7*24*time.Hour) if err != nil { return kit.Fail(err), nil } items, err := repositories.QueryMqttLogListOnTimeRange(sn, domain.MqttCmdType(cmd), from, to) if err != nil { return kit.Upstream("FWH 平台 MQTT 日志接口", err), nil } rows := make([]MqttRow, 0, len(items)) for _, it := range items { rows = append(rows, MqttRow{ LogTime: it.LogTime, Time: it.Time, Cmd: strings.TrimSpace(it.CmdType + " " + it.CmdName), Data: clip(it.LogData, 1500), }) } sort.SliceStable(rows, func(i, j int) bool { return rows[i].LogTime > rows[j].LogTime }) return kit.List(rows, -1, kit.Limit(a.Limit, 50, 300), "结果已截断,请缩短时间范围"), nil }, } // ---- ems_log_records ---- type emsLogRecordsArgs struct { SN string `json:"sn" jsonschema:"站点 SN(aGate 序列号)"` Date string `json:"date,omitempty" jsonschema:"日志日期 yyyy-MM-dd,不填查询全部"` LogType int `json:"logType,omitempty" jsonschema:"日志类型,默认 0(全部),取值以 FWH 平台定义为准"` } var EmsLogRecords = kit.Def[emsLogRecordsArgs]{ Name: "ems_log_records", Title: "查询 EMS 日志召唤记录", Description: "查询站点最近的 EMS 日志召唤记录(FWH 平台)。返回字段:id、fileName、callTime(召唤时间)、completeTime、status(1 成功、0 召唤中、-1 失败)、fileUrl、linkId(SN)。" + "没有召唤记录时返回提示。", ReadOnly: true, Handler: func(ctx context.Context, a emsLogRecordsArgs) (*mcp.CallToolResult, error) { sn, err := kit.Required("sn", a.SN) if err != nil { return kit.Fail(err), nil } date := "" if d, err := kit.ParseDate("date", a.Date, true); err != nil { return kit.Fail(err), nil } else if d != nil { date = d.Format(kit.DateLayout) } rec, err := repositories.QueryEmsLogCallRecord(sn, date, a.LogType) if err != nil { // 上游在"没有召唤日志"时也返回 error,这里按无数据处理;原始错误只写日志 return kit.Empty("未找到 EMS 日志召唤记录(" + kit.UpstreamText("FWH 平台 EMS 日志接口", err) + ")。"), nil } return kit.Object(rec), nil }, } // ---- update_log_system ---- type updateLogSystemArgs struct { SN string `json:"sn" jsonschema:"站点 SN(aGate 序列号)"` OrderID string `json:"orderId,omitempty" jsonschema:"升级单 ID(列表中的 id),填写时返回该升级单在本站点的明细"` Limit int `json:"limit,omitempty" jsonschema:"最多返回条数,1~200,默认 50"` } var UpdateLogSystem = kit.Def[updateLogSystemArgs]{ Name: "update_log_system", Title: "查询系统升级记录", Description: "查询站点的系统(固件)升级记录(FWH 平台)。不填 orderId 时返回升级单列表:id、orderNo(升级单号)、name、upgradeType、upgradeTime(UTC)、upgradeNum 等;" + "填 orderId 时返回该升级单在本站点各设备的升级明细(版本、状态、时间等,以实际返回为准)。", ReadOnly: true, Handler: func(ctx context.Context, a updateLogSystemArgs) (*mcp.CallToolResult, error) { sn, err := kit.Required("sn", a.SN) if err != nil { return kit.Fail(err), nil } limit := kit.Limit(a.Limit, 50, 200) if id := strings.TrimSpace(a.OrderID); id != "" { orderID, err := strconv.ParseInt(id, 10, 64) if err != nil { return kit.Failf("参数 orderId 必须是数字:%s", id), nil } items, err := repositories.QuerySystemUpdateLogDetail(orderID, sn) if err != nil { return kit.Upstream("FWH 平台升级记录接口", err), nil } return kit.List(items, -1, limit, ""), nil } items, err := repositories.QuerySystemUpdateLog(sn) if err != nil { return kit.Upstream("FWH 平台升级记录接口", err), nil } return kit.List(items, -1, limit, ""), nil }, } // ---- update_log_ahub ---- type updateLogAhubArgs struct { SN string `json:"sn" jsonschema:"站点 SN(aGate 序列号)"` Limit int `json:"limit,omitempty" jsonschema:"最多返回条数,1~200,默认 50"` } var UpdateLogAhub = kit.Def[updateLogAhubArgs]{ Name: "update_log_ahub", Title: "查询 aHub 升级记录", Description: "查询站点下 aHub(PowerLink)的升级记录(FWH 平台),返回升级时间、版本、状态等(以实际返回为准)。", ReadOnly: true, Handler: func(ctx context.Context, a updateLogAhubArgs) (*mcp.CallToolResult, error) { sn, err := kit.Required("sn", a.SN) if err != nil { return kit.Fail(err), nil } items, err := repositories.QueryAHubUpdateLog(sn) if err != nil { return kit.Upstream("FWH 平台 aHub 升级记录接口", err), nil } return kit.List(items, -1, kit.Limit(a.Limit, 50, 200), ""), nil }, }