Skip to main content
Glama

ABSD DevOps MCP Server

by anthonybir
system.ts6.66 kB
import { z } from 'zod'; import { spawn } from 'node:child_process'; import { platform } from 'node:os'; import { wrapError } from '../../utils/errors.js'; import type { Logger } from '../../utils/logger.js'; import type { ToolResult } from '../../types/config.js'; // ============================================================================ // LIST_PROCESSES // ============================================================================ const ListProcessesSchema = z.object({}); interface ProcessInfo { pid: number; name: string; cpu?: string; memory?: string; } /** * Parse process list output based on platform * Windows PowerShell: Get-Process returns CSV-like format * macOS/Linux: ps returns space-separated format */ function parseProcessList(output: string, osPlatform: string): ProcessInfo[] { const lines = output.trim().split('\n'); const processes: ProcessInfo[] = []; if (osPlatform === 'win32') { // Windows PowerShell output format: PID,ProcessName,CPU,WorkingSet // Skip header line for (let i = 1; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; const parts = line.split(','); if (parts.length >= 2) { const pid = parseInt(parts[0], 10); if (!isNaN(pid)) { processes.push({ pid, name: parts[1], cpu: parts[2] || '0', memory: parts[3] ? (parseInt(parts[3]) / 1024 / 1024).toFixed(1) + 'M' : '0M', }); } } } } else { // macOS/Linux ps output format // Skip header line for (let i = 1; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; const parts = line.split(/\s+/); if (parts.length >= 4) { const pid = parseInt(parts[0], 10); if (!isNaN(pid)) { processes.push({ pid, cpu: parts[1], memory: parts[2], name: parts.slice(3).join(' '), }); } } } } return processes; } export async function listProcessesTool( logger: Logger ): Promise<ToolResult> { try { const osPlatform = platform(); let command: string; let args: string[]; if (osPlatform === 'win32') { // Windows PowerShell with CSV output command = 'powershell.exe'; args = [ '-NoProfile', '-Command', 'Get-Process | Select-Object Id,ProcessName,CPU,WorkingSet | ConvertTo-Csv -NoTypeInformation', ]; } else { // macOS/Linux command = 'ps'; args = ['aux']; } const proc = spawn(command, args); let output = ''; let errorOutput = ''; proc.stdout?.on('data', (chunk: Buffer) => { output += chunk.toString('utf-8'); }); proc.stderr?.on('data', (chunk: Buffer) => { errorOutput += chunk.toString('utf-8'); }); const exitCode = await new Promise<number>((resolve) => { proc.on('exit', (code) => resolve(code ?? 1)); proc.on('error', () => resolve(1)); }); if (exitCode !== 0) { throw new Error(`Failed to list processes: ${errorOutput}`); } const processes = parseProcessList(output, osPlatform); logger.info({ tool: 'list_processes', count: processes.length, platform: osPlatform, }, 'Processes listed'); // Format output const processList = processes .slice(0, 100) // Limit to first 100 for readability .map(p => `[${p.pid}] ${p.name} | CPU: ${p.cpu || 'N/A'}% | Memory: ${p.memory || 'N/A'}`) .join('\n'); return { content: [{ type: 'text', text: `Running Processes (showing first 100 of ${processes.length}): ${processList} Platform: ${osPlatform}`, }], }; } catch (error) { const mcpError = wrapError(error, 'list_processes'); logger.error({ error: mcpError }, 'list_processes failed'); return { content: [{ type: 'text', text: `Error: ${mcpError.message}`, }], }; } } export const listProcessesToolDefinition = { name: 'list_processes', description: 'List all running system processes with PID, name, CPU usage, and memory usage.', inputSchema: ListProcessesSchema, }; // ============================================================================ // KILL_PROCESS // ============================================================================ const KillProcessSchema = z.object({ pid: z.number().int().positive().describe('Process ID to kill'), confirmToken: z.string().optional().describe('Confirmation token (PID as string) to prevent accidental kills'), }); export type KillProcessArgs = z.infer<typeof KillProcessSchema>; export async function killProcessTool( args: KillProcessArgs, logger: Logger ): Promise<ToolResult> { try { // Validate confirmation token if (!args.confirmToken || args.confirmToken !== String(args.pid)) { return { content: [{ type: 'text', text: `Error: Confirmation token required. To kill process ${args.pid}, set confirmToken to "${args.pid}"`, }], }; } const osPlatform = platform(); let command: string; let cmdArgs: string[]; if (osPlatform === 'win32') { // Windows command = 'taskkill'; cmdArgs = ['/F', '/PID', String(args.pid)]; } else { // macOS/Linux command = 'kill'; cmdArgs = ['-9', String(args.pid)]; } const proc = spawn(command, cmdArgs); let errorOutput = ''; proc.stderr?.on('data', (chunk: Buffer) => { errorOutput += chunk.toString('utf-8'); }); const exitCode = await new Promise<number>((resolve) => { proc.on('exit', (code) => resolve(code ?? 1)); proc.on('error', () => resolve(1)); }); if (exitCode !== 0) { throw new Error(`Failed to kill process: ${errorOutput}`); } logger.info({ tool: 'kill_process', pid: args.pid, platform: osPlatform, }, 'Process killed'); return { content: [{ type: 'text', text: `Process ${args.pid} killed successfully`, }], }; } catch (error) { const mcpError = wrapError(error, 'kill_process'); logger.error({ error: mcpError, args }, 'kill_process failed'); return { content: [{ type: 'text', text: `Error: ${mcpError.message}`, }], }; } } export const killProcessToolDefinition = { name: 'kill_process', description: 'Kill a system process by PID. Requires confirmation token (PID as string) to prevent accidental kills. Use list_processes to find PIDs.', inputSchema: KillProcessSchema, };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/anthonybir/ABSD_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server