/** * SSH Snapshot Tool * Instant system state snapshot */ import { CallToolRequest, Tool } from '@modelcontextprotocol/sdk/types.js'; import { type ToolResult } from '../utils/tool-result.js'; /** * Snapshot Tool */ export declare class SnapshotTool { private executor; constructor(); /** * Get tool description for MCP */ getTool(): Tool; /** * Handle tool call */ handleCall(request: CallToolRequest): Promise; /** * How many snapshot reads run over the connection at once. * * A burst of ten instant commands drops connections on dropbear: some * channels come back with exit code 255, empty output and no error text. * The transport retries the drop, but the queue exists to avoid firing that * burst at the server in the first place. OpenSSH servers hold up under ten * concurrent reads without loss. */ private static readonly READ_CONCURRENCY; /** Tail of the read queue: the next one waits for a slot to free up */ private readSlots; /** * Read a value from the server. * * The snapshot consists of independent reads: one failing must not cancel * the rest, so a fallback value is returned instead of an exception. Every * snapshot command is read-only, so retrying on a dropped connection is safe. */ private read; /** Let work through once concurrent reads drop below the limit */ private withSlot; /** * Get timestamp */ private getTimestamp; /** * Get hostname */ private getHostname; /** * Get uptime */ private getUptime; /** * Get service status */ private getServices; /** Answers by which systemctl reports that the systemd bus is not answering it */ private static readonly SYSTEMD_SILENT; /** * Get CPU information */ private getCPU; /** * CPU usage from `top`'s summary line: computed from idle time, because the * idle share is present in both formats. `null` means no such line was found. */ private static parseCpuUsage; /** * Get Memory information */ private getMemory; /** Suffix multipliers for `free -h`: both `Gi` from coreutils and `G` from BusyBox are powers of 1024 */ private static readonly SIZE_FACTOR; /** * A size with a suffix, in bytes. Without converting to a common unit, * `506Mi` and `3.8Gi` would be divided as plain 506 and 3.8, and the report * would announce a wildly wrong percentage of memory used. */ private static parseSize; /** * Get Disk information * * The volume type is needed to filter out kernel-internal filesystems: * filtering by device name (`^/dev/`) would drop the root filesystem from * the view wherever it sits on overlay — that is, in any container. */ private getDisk; /** * Get Docker information */ private getDocker; /** * Get Network information */ private getNetwork; /** * Get recent errors */ private getRecentErrors; /** * Determine service by port */ private getServiceByPort; /** * Format snapshot for output */ private formatSnapshot; }