Files
komodo-mcp-server/src/tools/resource-stats.ts
T
bot-hermes fe00ed430b feat: expand troubleshooting tools — server_stats, resource_stats, updates, build logs, 8 new execute ops
- New komodo_server_stats: system_information, system_stats, historical_server_stats, server_state, periphery_information, containers_summary, version, core_info
- New komodo_resource_stats: deployment_stats, deployment_container, build_monthly_stats, action_state (9 resource types), concurrency_limit_usage, resource_matching_container
- New komodo_updates: get (full execution logs) and list (recent operations history)
- Expanded komodo_logs: add build resource type (built_contents, remote_contents, remote_error, hashes)
- Expanded komodo_list_detail: terminals, alerts, containers_summary
- Expanded komodo_execute: refresh_server, refresh_server_containers, refresh_stack_cache, refresh_stack_content, remove_orphan_containers, check_stack_for_update, check_deployment_for_update, get_mcp_token
2026-09-08 20:28:53 +00:00

100 lines
3.8 KiB
TypeScript

import { z } from "zod";
import { KomodoClient } from "../komodo-client.js";
import { RESOURCE_STATS_REQUEST_MAP, ACTION_STATE_REQUEST_MAP } from "../types.js";
const ResourceStatType = z.enum([
"deployment_stats",
"deployment_container",
"build_monthly_stats",
"action_state",
"concurrency_limit_usage",
"resource_matching_container",
]);
const ActionStateResourceType = z.enum([
"action", "build", "deployment", "procedure",
"repo", "server", "stack", "swarm", "sync_resource",
]);
export const resourceStatsInputSchema = {
stat_type: ResourceStatType.describe(
"Resource stat to retrieve: deployment_stats (CPU/mem/net usage), deployment_container (container details), build_monthly_stats (build frequency), action_state (is resource currently running), concurrency_limit_usage (active limits), resource_matching_container (reverse-lookup container → resource)."
),
id: z.string().optional().describe("Resource ID or name (required for deployment_stats, deployment_container, build_monthly_stats, action_state)"),
resource_type: ActionStateResourceType.optional().describe("Resource type for action_state (e.g. 'stack', 'deployment', 'build'). Required when stat_type is 'action_state'."),
server: z.string().optional().describe("Server name (required for resource_matching_container)"),
container: z.string().optional().describe("Container name (required for resource_matching_container)"),
};
export async function handleResourceStats(
args: {
stat_type: z.infer<typeof ResourceStatType>;
id?: string;
resource_type?: z.infer<typeof ActionStateResourceType>;
server?: string;
container?: string;
},
client: KomodoClient,
): Promise<{ content: { type: "text"; text: string }[] }> {
const { stat_type, id, resource_type, server, container } = args;
// Handle action_state separately — it dispatches to different endpoints per resource type
if (stat_type === "action_state") {
if (!resource_type) throw new Error(`action_state requires a resource_type (e.g. 'stack', 'deployment', 'build')`);
if (!id) throw new Error(`action_state requires an id`);
const requestName = ACTION_STATE_REQUEST_MAP[resource_type];
if (!requestName) {
throw new Error(`No action state endpoint for resource type: ${resource_type}`);
}
// The param key matches the resource type for most, but sync_resource uses "resource_sync"
const paramKey = resource_type === "sync_resource" ? "resource_sync" : resource_type;
const params: Record<string, unknown> = { [paramKey]: id };
const result = await client.rpc("read", requestName, params);
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
}
const requestName = RESOURCE_STATS_REQUEST_MAP[stat_type];
if (!requestName) {
throw new Error(`Unknown resource stat type: ${stat_type}`);
}
const params: Record<string, unknown> = {};
switch (stat_type) {
case "deployment_stats":
case "deployment_container":
if (!id) throw new Error(`${stat_type} requires an id (deployment name or ID)`);
params.deployment = id;
break;
case "build_monthly_stats":
if (!id) throw new Error(`${stat_type} requires an id (build name or ID)`);
params.build = id;
break;
case "concurrency_limit_usage":
// No params needed
break;
case "resource_matching_container":
if (!server) throw new Error(`resource_matching_container requires a server`);
if (!container) throw new Error(`resource_matching_container requires a container name`);
params.server = server;
params.container = container;
break;
}
const result = await client.rpc("read", requestName, params);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}