From e110845a6b2a7934468be195ae0d41440b309eb7 Mon Sep 17 00:00:00 2001 From: MalishkinMV Date: Fri, 29 May 2026 18:19:20 +0300 Subject: [PATCH] =?UTF-8?q?feat(mcp-server):=20add=20get-node-stat=20tool?= =?UTF-8?q?=20=E2=80=94=20node=20archive=20statistics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exposes the Corezoid archive statistics API as a first-class MCP tool. get-node-stat returns time-series in/out counts per day or hour for any node, using the node_id from the Corezoid UI archive URL (/diagram/{node_id}/archive). Co-Authored-By: Claude Sonnet 4.6 --- README.md | 1 + plugins/corezoid/mcp-server/mcp_handlers.go | 1 + .../corezoid/mcp-server/mcp_handlers_tasks.go | 52 +++++++++++++++++++ plugins/corezoid/mcp-server/mcp_server.go | 1 + plugins/corezoid/mcp-server/tools_registry.go | 34 ++++++++++++ 5 files changed, 89 insertions(+) diff --git a/README.md b/README.md index bac334d..343ac03 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ validation errors, and summarize what each process does. | `run-task` | Send a task to a deployed process | | `list-node-tasks` | List tasks currently sitting in a node | | `list-task-history` | Show task execution history | +| `get-node-stat` | Return time-series in/out statistics for a node | | `delete-task` | Remove a task from a node | | `modify-task` | Update task parameters | | `create-process` | Create a new empty process in a folder | diff --git a/plugins/corezoid/mcp-server/mcp_handlers.go b/plugins/corezoid/mcp-server/mcp_handlers.go index e1afd13..7ba278c 100644 --- a/plugins/corezoid/mcp-server/mcp_handlers.go +++ b/plugins/corezoid/mcp-server/mcp_handlers.go @@ -41,6 +41,7 @@ var toolHandlers = map[string]toolHandler{ // tasks "list-task-history": handleListTaskHistory, "list-node-tasks": handleListNodeTasks, + "get-node-stat": handleGetNodeStat, "modify-task": handleModifyTask, "delete-task": handleDeleteTask, diff --git a/plugins/corezoid/mcp-server/mcp_handlers_tasks.go b/plugins/corezoid/mcp-server/mcp_handlers_tasks.go index 8ea8c02..fb84272 100644 --- a/plugins/corezoid/mcp-server/mcp_handlers_tasks.go +++ b/plugins/corezoid/mcp-server/mcp_handlers_tasks.go @@ -79,6 +79,58 @@ func handleListNodeTasks(ctx context.Context, args map[string]interface{}) (stri return string(data), false } +// handleGetNodeStat returns time-series in/out statistics for a process node +// over a caller-specified time window. The interval parameter controls bucket +// granularity ("day" or "hour", default "day"). +func handleGetNodeStat(ctx context.Context, args map[string]interface{}) (string, bool) { + processID, err := intArg(args, "process_id") + if err != nil { + return "Error: " + err.Error(), true + } + nodeID, err := strArg(args, "node_id") + if err != nil { + return "Error: " + err.Error(), true + } + start, err := intArg(args, "start") + if err != nil { + return "Error: " + err.Error(), true + } + end, err := intArg(args, "end") + if err != nil { + return "Error: " + err.Error(), true + } + interval := "day" + if v, ok := args["interval"].(string); ok && v != "" { + interval = v + } + timezoneOffset := 0 + if n, err := intArg(args, "timezone_offset"); err == nil { + timezoneOffset = n + } + + v := NewValidator(ctx, processID) + ops := []map[string]any{ + { + "obj": "stat", + "type": "show", + "group": "time", + "conv_id": processID, + "node_id": nodeID, + "company_id": v.WorkspaceID, + "start": start, + "end": end, + "interval": interval, + "timezone_offset": timezoneOffset, + }, + } + resp, err := v.req("get_node_stat", ops) + if err != nil { + return fmt.Sprintf("Error: %v", err), true + } + data, _ := json.MarshalIndent(resp, "", " ") + return string(data), false +} + // handleModifyTask updates the data payload of an existing task. Either // task_id or ref must be supplied to identify the task. func handleModifyTask(ctx context.Context, args map[string]interface{}) (string, bool) { diff --git a/plugins/corezoid/mcp-server/mcp_server.go b/plugins/corezoid/mcp-server/mcp_server.go index 99148cf..886585e 100644 --- a/plugins/corezoid/mcp-server/mcp_server.go +++ b/plugins/corezoid/mcp-server/mcp_server.go @@ -235,6 +235,7 @@ func runMCPServer() { ID: req.ID, Result: map[string]interface{}{ "tools": toolRegistry, + }, }) diff --git a/plugins/corezoid/mcp-server/tools_registry.go b/plugins/corezoid/mcp-server/tools_registry.go index 6c0f2b8..ee4b306 100644 --- a/plugins/corezoid/mcp-server/tools_registry.go +++ b/plugins/corezoid/mcp-server/tools_registry.go @@ -407,6 +407,40 @@ var toolRegistry = []mcpTool{ "required": []string{"process_id", "node_id"}, }, }, + { + Name: "get-node-stat", + Description: "Return time-series statistics (in/out counts) for a node over a time range. node_id is the ID shown in the Corezoid UI archive URL (/diagram/{node_id}/archive). ops[0]['data'] contains [{\"date\":\"YYYY-MM-DD\",\"in\":N,\"out\":M}] for non-zero buckets. ops[0]['title'] is the node title.", + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "process_id": map[string]interface{}{ + "type": "integer", + "description": "Corezoid process (conv) ID", + }, + "node_id": map[string]interface{}{ + "type": "string", + "description": "Node ID from the Corezoid UI archive URL", + }, + "start": map[string]interface{}{ + "type": "integer", + "description": "Unix timestamp — start of the period", + }, + "end": map[string]interface{}{ + "type": "integer", + "description": "Unix timestamp — end of the period", + }, + "interval": map[string]interface{}{ + "type": "string", + "description": "Aggregation bucket: 'day' or 'hour' (default: 'day')", + }, + "timezone_offset": map[string]interface{}{ + "type": "integer", + "description": "UTC offset in minutes, negative westward (e.g. -180 for UTC+3, default: 0)", + }, + }, + "required": []string{"process_id", "node_id", "start", "end"}, + }, + }, { Name: "modify-task", Description: "Modify an existing task's data. The task will continue from the node where it was paused with the updated data. At least one of task_id or ref must be provided.",