Skip to main content
Glama

read_process_output

Read-only

Read output from running processes with pagination controls to monitor execution results, detect completion states, and manage verbose output efficiently.

Instructions

                    Read output from a running process with file-like pagination support.
                    
                    Supports partial output reading with offset and length parameters (like read_file):
                    - 'offset' (start line, default: 0)
                      * offset=0: Read NEW output since last read (default, like old behavior)
                      * Positive: Read from absolute line position
                      * Negative: Read last N lines from end (tail behavior)
                    - 'length' (max lines to read, default: configurable via 'fileReadLineLimit' setting)
                    
                    Examples:
                    - offset: 0, length: 100     → First 100 NEW lines since last read
                    - offset: 0                  → All new lines (respects config limit)
                    - offset: 500, length: 50    → Lines 500-549 (absolute position)
                    - offset: -20                → Last 20 lines (tail)
                    - offset: -50, length: 10    → Start 50 from end, read 10 lines
                    
                    OUTPUT PROTECTION:
                    - Uses same fileReadLineLimit as read_file (default: 1000 lines)
                    - Returns status like: [Reading 100 lines from line 0 (total: 5000 lines, 4900 remaining)]
                    - Prevents context overflow from verbose processes
                    
                    SMART FEATURES:
                    - For offset=0, waits up to timeout_ms for new output to arrive
                    - Detects REPL prompts and process completion
                    - Shows process state (waiting for input, finished, etc.)
                    
                    DETECTION STATES:
                    Process waiting for input (ready for interact_with_process)
                    Process finished execution
                    Timeout reached (may still be running)

                    This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pidYes
timeout_msNo
offsetNo
lengthNo
verbose_timingNo

Implementation Reference

  • Core handler function that parses arguments, reads paginated output from process via terminalManager.readOutputPaginated(pid, offset, length), handles waiting for new output, adds status messages, process state detection, and timing info.
    export async function readProcessOutput(args: unknown): Promise<ServerResult> {
      const parsed = ReadProcessOutputArgsSchema.safeParse(args);
      if (!parsed.success) {
        return {
          content: [{ type: "text", text: `Error: Invalid arguments for read_process_output: ${parsed.error}` }],
          isError: true,
        };
      }
    
      // Get default line limit from config
      const config = await configManager.getConfig();
      const defaultLength = config.fileReadLineLimit ?? 1000;
    
      const { 
        pid, 
        timeout_ms = 5000, 
        offset = 0,                    // 0 = from last read, positive = absolute, negative = tail
        length = defaultLength,        // Default from config, same as file reading
        verbose_timing = false 
      } = parsed.data;
    
      // Timing telemetry
      const startTime = Date.now();
    
      // For active sessions with no new output yet, optionally wait for output
      const session = terminalManager.getSession(pid);
      if (session && offset === 0) {
        // Wait for new output to arrive (only for "new output" reads, not absolute/tail)
        const waitForOutput = (): Promise<void> => {
          return new Promise((resolve) => {
            // Check if there's already new output
            const currentLines = terminalManager.getOutputLineCount(pid) || 0;
            if (currentLines > session.lastReadIndex) {
              resolve();
              return;
            }
    
            let resolved = false;
            let interval: NodeJS.Timeout | null = null;
            let timeout: NodeJS.Timeout | null = null;
    
            const cleanup = () => {
              if (interval) clearInterval(interval);
              if (timeout) clearTimeout(timeout);
            };
    
            const resolveOnce = () => {
              if (resolved) return;
              resolved = true;
              cleanup();
              resolve();
            };
    
            // Poll for new output
            interval = setInterval(() => {
              const newLineCount = terminalManager.getOutputLineCount(pid) || 0;
              if (newLineCount > session.lastReadIndex) {
                resolveOnce();
              }
            }, 50);
    
            // Timeout
            timeout = setTimeout(() => {
              resolveOnce();
            }, timeout_ms);
          });
        };
    
        await waitForOutput();
      }
    
      // Read output with pagination
      const result = terminalManager.readOutputPaginated(pid, offset, length);
      
      if (!result) {
        return {
          content: [{ type: "text", text: `No session found for PID ${pid}` }],
          isError: true,
        };
      }
    
      // Join lines back into string
      const output = result.lines.join('\n');
    
      // Generate status message similar to file reading
      let statusMessage = '';
      if (offset < 0) {
        // Tail read - match file reading format for consistency
        statusMessage = `[Reading last ${result.readCount} lines (total: ${result.totalLines} lines)]`;
      } else if (offset === 0) {
        // "New output" read
        if (result.remaining > 0) {
          statusMessage = `[Reading ${result.readCount} new lines from line ${result.readFrom} (total: ${result.totalLines} lines, ${result.remaining} remaining)]`;
        } else {
          statusMessage = `[Reading ${result.readCount} new lines (total: ${result.totalLines} lines)]`;
        }
      } else {
        // Absolute position read
        statusMessage = `[Reading ${result.readCount} lines from line ${result.readFrom} (total: ${result.totalLines} lines, ${result.remaining} remaining)]`;
      }
    
      // Add process state info
      let processStateMessage = '';
      if (result.isComplete) {
        const runtimeStr = result.runtimeMs !== undefined 
          ? ` (runtime: ${(result.runtimeMs / 1000).toFixed(2)}s)` 
          : '';
        processStateMessage = `\n✅ Process completed with exit code ${result.exitCode}${runtimeStr}`;
      } else if (session) {
        // Analyze state for running processes
        const fullOutput = session.outputLines.join('\n');
        const processState = analyzeProcessState(fullOutput, pid);
        if (processState.isWaitingForInput) {
          processStateMessage = `\n🔄 ${formatProcessStateMessage(processState, pid)}`;
        }
      }
    
      // Add timing information if requested
      let timingMessage = '';
      if (verbose_timing) {
        const endTime = Date.now();
        timingMessage = `\n\n📊 Timing: ${endTime - startTime}ms`;
      }
    
      const responseText = output || '(No output in requested range)';
    
      return {
        content: [{
          type: "text",
          text: `${statusMessage}\n\n${responseText}${processStateMessage}${timingMessage}`
        }],
      };
    }
  • Zod schema defining input parameters for read_process_output: pid (required), timeout_ms, offset, length, verbose_timing.
    export const ReadProcessOutputArgsSchema = z.object({
      pid: z.number(),
      timeout_ms: z.number().optional(),
      offset: z.number().optional(),   // Line offset: 0=from last read, positive=absolute, negative=tail
      length: z.number().optional(),   // Max lines to return (default from config.fileReadLineLimit)
      verbose_timing: z.boolean().optional(),
    });
  • src/server.ts:801-840 (registration)
    Tool registration in list_tools handler: defines name, description, inputSchema from ReadProcessOutputArgsSchema, and annotations.
        name: "read_process_output",
        description: `
                Read output from a running process with file-like pagination support.
                
                Supports partial output reading with offset and length parameters (like read_file):
                - 'offset' (start line, default: 0)
                  * offset=0: Read NEW output since last read (default, like old behavior)
                  * Positive: Read from absolute line position
                  * Negative: Read last N lines from end (tail behavior)
                - 'length' (max lines to read, default: configurable via 'fileReadLineLimit' setting)
                
                Examples:
                - offset: 0, length: 100     → First 100 NEW lines since last read
                - offset: 0                  → All new lines (respects config limit)
                - offset: 500, length: 50    → Lines 500-549 (absolute position)
                - offset: -20                → Last 20 lines (tail)
                - offset: -50, length: 10    → Start 50 from end, read 10 lines
                
                OUTPUT PROTECTION:
                - Uses same fileReadLineLimit as read_file (default: 1000 lines)
                - Returns status like: [Reading 100 lines from line 0 (total: 5000 lines, 4900 remaining)]
                - Prevents context overflow from verbose processes
                
                SMART FEATURES:
                - For offset=0, waits up to timeout_ms for new output to arrive
                - Detects REPL prompts and process completion
                - Shows process state (waiting for input, finished, etc.)
                
                DETECTION STATES:
                Process waiting for input (ready for interact_with_process)
                Process finished execution
                Timeout reached (may still be running)
    
                ${CMD_PREFIX_DESCRIPTION}`,
        inputSchema: zodToJsonSchema(ReadProcessOutputArgsSchema),
        annotations: {
            title: "Read Process Output",
            readOnlyHint: true,
        },
    },
  • Dispatch in call_tool handler: routes 'read_process_output' calls to handlers.handleReadProcessOutput
    case "read_process_output":
        result = await handlers.handleReadProcessOutput(args);
        break;
  • Thin wrapper handler that parses args with schema and delegates to readProcessOutput from tools.
    /**
     * Handle read_process_output command (improved read_output)
     */
    export async function handleReadProcessOutput(args: unknown): Promise<ServerResult> {
        const parsed = ReadProcessOutputArgsSchema.parse(args);
        return readProcessOutput(parsed);
    }
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds significant behavioral context beyond the readOnlyHint annotation, including output protection mechanisms (fileReadLineLimit, status returns), smart features (timeout handling, REPL prompt detection), and detection states (process waiting, finished, timeout). It does not contradict the readOnlyHint annotation, as reading output aligns with a read-only operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with sections for features, examples, and states, but it includes some redundant phrasing (e.g., 'This command can be referenced as...') that could be trimmed. Most sentences earn their place by adding value, though it is slightly verbose in parts.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (5 parameters, 0% schema coverage, no output schema) and lack of annotations beyond readOnlyHint, the description is highly complete. It covers purpose, usage, parameters, behavioral traits, and output handling, providing sufficient context for an agent to use the tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description fully compensates by detailing the semantics of offset and length parameters with examples, explaining pid as the process identifier, and mentioning timeout_ms and verbose_timing. It adds meaning beyond the bare schema, clarifying default behaviors and usage scenarios.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as 'Read output from a running process with file-like pagination support.' It specifies the verb ('Read'), resource ('output from a running process'), and distinguishes it from siblings like read_file by emphasizing process-specific features such as waiting for new output and detecting process states.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool, such as reading from a running process with pagination, and implies alternatives by referencing 'like read_file' and mentioning interact_with_process for processes waiting for input. However, it does not explicitly state when not to use it or name all relevant sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/wonderwhy-er/ClaudeComputerCommander'

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