How Process Output Pagination Prevents Context Overflow in Desktop Commander MCP
Desktop Commander MCP implements a file-like pagination API that returns only specific slices of process output via offset and length parameters, ensuring the LLM receives bounded data regardless of how much the underlying process prints.
Desktop Commander MCP manages long-running processes through a virtual terminal that streams stdout and stderr without overwhelming the language model. The read_process_output function in src/tools/improved-process-tools.ts implements process output pagination to cap the amount of data returned in any single API call. This prevents context overflow by guaranteeing that even verbose processes transmit only a configurable, token-friendly amount of text per request.
The Pagination Architecture
The pagination system operates as a protective layer between the unbounded process output and the LLM's finite context window. Instead of buffering entire execution logs in memory for the model, the terminal manager exposes a slice-based retrieval mechanism.
Offset and Length Parameters
The read_process_output function accepts an offset parameter that determines the starting position of the returned slice and a length parameter that limits the number of lines. According to the source code in src/tools/improved-process-tools.ts, the function supports three offset modes:
offset: 0– Returns only new output since the last read- Positive integer – Absolute line number from the start of the buffer
- Negative integer – Tail offset that reads from the end of the output (e.g.,
-5returns the last 5 lines)
The implementation reads only the requested range and formats a concise status line indicating the total lines available and the current position.
Configurable Line Limits
When the caller omits the length parameter, the system falls back to the fileReadLineLimit configuration value (defaulting to 1000 lines). This default is enforced in src/tools/improved-process-tools.ts between lines 51-60. The interact_with_process function applies the same limit after sending input, truncating large outputs and prompting the user to call read_process_output for the full log if needed.
Buffer Cap Eviction
To prevent unbounded memory growth, the terminal manager enforces a total buffered output limit via MAX_BUFFERED_OUTPUT_CHARS. When the cap is reached, the earliest lines are evicted from the buffer, and a warning message is appended to the status output (lines 44-50 in src/tools/improved-process-tools.ts). This ensures that long-running processes cannot exhaust server memory while still maintaining recent output availability.
Reading Process Output with Pagination
The following example demonstrates how to start a long-running process and retrieve its output in controlled increments:
// Start a long-running process that prints continuously
import { startProcess, readProcessOutput } from './dist/tools/improved-process-tools.js';
const { pid } = await startProcess({
command: 'node -e "let i=0; setInterval(()=>console.log(`tick${i++}`),200)"',
timeout_ms: 500 // Returns early, process keeps running
});
// Read only new output since the last read (offset = 0)
let result = await readProcessOutput({ pid, timeout_ms: 300 });
console.log(result.content[0].text); // Shows first few "tick" lines
// Get the next chunk of new output
await new Promise(r => setTimeout(r, 400));
result = await readProcessOutput({ pid, timeout_ms: 300 });
console.log(result.content[0].text); // Only lines that appeared after previous read
// Read a specific slice (absolute offset = 5, length = 3)
result = await readProcessOutput({ pid, offset: 5, length: 3, timeout_ms: 1000 });
console.log(result.content[0].text); // Lines 5-7
// Tail-read the last 5 lines of a completed process
result = await readProcessOutput({ pid, offset: -5, timeout_ms: 1000 });
console.log(result.content[0].text); // Final 5 lines
This approach ensures that each API call returns a predictable payload size, protecting the LLM from context overflow while allowing complete access to the process log through multiple pagination requests.
Key Source Files
The pagination system spans several components in the Desktop Commander MCP repository:
src/tools/improved-process-tools.ts– Implementsread_process_outputwith offset/length pagination, default line limits, and buffer-cap warningssrc/handlers/terminal-handlers.ts– Exposes the pagination functions to the server's RPC layertest/test-process-pagination.js– Test suite exercising the pagination API including new-output reads, absolute offsets, tail reads, and length limits
Summary
- Process output pagination in Desktop Commander MCP uses offset and length parameters to return bounded slices of stdout/stderr instead of complete buffers
- The default
fileReadLineLimitof 1000 lines prevents unbounded returns when no length is specified MAX_BUFFERED_OUTPUT_CHARSenforces memory limits by evicting old lines and appending warnings when the buffer cap is reached- Both
read_process_outputandinteract_with_processapply these limits to ensure every API call returns a token-friendly amount of data
Frequently Asked Questions
What is the default line limit for process output in Desktop Commander MCP?
The default line limit is 1000 lines, defined by the fileReadLineLimit configuration value. This applies when calling read_process_output without specifying a length parameter, as implemented in src/tools/improved-process-tools.ts lines 51-60.
How does negative offset work in read_process_output?
A negative offset value enables tail-reading behavior. For example, setting offset: -5 returns the last 5 lines of the buffered output. This functions similarly to the Unix tail command and is useful for checking recent activity in long-running processes without retrieving the entire log.
What happens when the output buffer reaches MAX_BUFFERED_OUTPUT_CHARS?
When the total buffered output hits the MAX_BUFFERED_OUTPUT_CHARS limit, the terminal manager automatically evicts the earliest lines from the buffer to make room for new output. The system appends a warning message to the status line indicating that older content has been dropped, ensuring memory usage remains bounded while preserving recent output.
Can I retrieve the full process output if needed?
Yes, though not in a single request. Because read_process_output supports arbitrary offsets and lengths, you can make multiple calls to retrieve the complete log in chunks. The status line returned with each request indicates the total number of lines available, allowing you to calculate subsequent requests to pull the entire buffer across several pagination calls.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →