interact_with_process
Send input to running processes and receive responses for local file analysis, data processing, and interactive REPL workflows.
Instructions
Send input to a running process and automatically receive the response.
CRITICAL: THIS IS THE PRIMARY TOOL FOR ALL LOCAL FILE ANALYSIS
For ANY local file analysis (CSV, JSON, data processing), ALWAYS use this instead of the analysis tool.
The analysis tool CANNOT access local files and WILL FAIL - use processes for ALL file-based work.
FILE ANALYSIS PRIORITY ORDER (MANDATORY):
1. ALWAYS FIRST: Use this tool (start_process + interact_with_process) for local data analysis
2. ALTERNATIVE: Use command-line tools (cut, awk, grep) for quick processing
3. NEVER EVER: Use analysis tool for local file access (IT WILL FAIL)
REQUIRED INTERACTIVE WORKFLOW FOR FILE ANALYSIS:
1. Start REPL: start_process("python3 -i")
2. Load libraries: interact_with_process(pid, "import pandas as pd, numpy as np")
3. Read file: interact_with_process(pid, "df = pd.read_csv('/absolute/path/file.csv')")
4. Analyze: interact_with_process(pid, "print(df.describe())")
5. Continue: interact_with_process(pid, "df.groupby('column').size()")
BINARY FILE PROCESSING WORKFLOWS:
Use appropriate Python libraries (PyPDF2, pandas, docx2txt, etc.) or command-line tools for binary file analysis.
SMART DETECTION:
- Automatically waits for REPL prompt (>>>, >, etc.)
- Detects errors and completion states
- Early exit prevents timeout delays
- Clean output formatting (removes prompts)
SUPPORTED REPLs:
- Python: python3 -i (RECOMMENDED for data analysis)
- Node.js: node -i
- R: R
- Julia: julia
- Shell: bash, zsh
- Database: mysql, postgres
PARAMETERS:
- pid: Process ID from start_process
- input: Code/command to execute
- timeout_ms: Max wait (default: 8000ms)
- wait_for_prompt: Auto-wait for response (default: true)
- verbose_timing: Enable detailed performance telemetry (default: false)
Returns execution result with status indicators.
PERFORMANCE DEBUGGING (verbose_timing parameter):
Set verbose_timing: true to get detailed timing information including:
- Exit reason (early_exit_quick_pattern, early_exit_periodic_check, process_finished, timeout, no_wait)
- Total duration and time to first output
- Complete timeline of all output events with timestamps
- Which detection mechanism triggered early exit
Use this to identify slow interactions and optimize detection patterns.
ALWAYS USE FOR: CSV analysis, JSON processing, file statistics, data visualization prep, ANY local file work
NEVER USE ANALYSIS TOOL FOR: Local file access (it cannot read files from disk and WILL FAIL)
This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | ||
| input | Yes | ||
| timeout_ms | No | ||
| wait_for_prompt | No | ||
| verbose_timing | No |
Implementation Reference
- Core handler function that executes the interact_with_process tool logic: parses args, sends input to process PID, waits for prompt/response with smart detection, handles virtual Node sessions, returns formatted output with state info.export async function interactWithProcess(args: unknown): Promise<ServerResult> { const parsed = InteractWithProcessArgsSchema.safeParse(args); if (!parsed.success) { capture('server_interact_with_process_failed', { error: 'Invalid arguments' }); return { content: [{ type: "text", text: `Error: Invalid arguments for interact_with_process: ${parsed.error}` }], isError: true, }; } const { pid, input, timeout_ms = 8000, wait_for_prompt = true, verbose_timing = false } = parsed.data; // Get config for output line limit const config = await configManager.getConfig(); const maxOutputLines = config.fileReadLineLimit ?? 1000; // Check if this is a virtual Node session (node:local) if (virtualNodeSessions.has(pid)) { const session = virtualNodeSessions.get(pid)!; capture('server_interact_with_process_node_fallback', { pid: pid, inputLength: input.length }); // Execute code via temp file approach // Respect per-call timeout if provided, otherwise use session default const effectiveTimeout = timeout_ms ?? session.timeout_ms; return executeNodeCode(input, effectiveTimeout); } // Timing telemetry const startTime = Date.now(); let firstOutputTime: number | undefined; let lastOutputTime: number | undefined; const outputEvents: any[] = []; let exitReason: 'early_exit_quick_pattern' | 'early_exit_periodic_check' | 'process_finished' | 'timeout' | 'no_wait' = 'timeout'; try { capture('server_interact_with_process', { pid: pid, inputLength: input.length }); // Capture output snapshot BEFORE sending input // This handles REPLs where output is appended to the prompt line const outputSnapshot = terminalManager.captureOutputSnapshot(pid); const success = terminalManager.sendInputToProcess(pid, input); if (!success) { return { content: [{ type: "text", text: `Error: Failed to send input to process ${pid}. The process may have exited or doesn't accept input.` }], isError: true, }; } // If not waiting for response, return immediately if (!wait_for_prompt) { exitReason = 'no_wait'; let timingMessage = ''; if (verbose_timing) { const endTime = Date.now(); const timingInfo = { startTime, endTime, totalDurationMs: endTime - startTime, exitReason, firstOutputTime, lastOutputTime, timeToFirstOutputMs: undefined, outputEvents: undefined }; timingMessage = formatTimingInfo(timingInfo); } return { content: [{ type: "text", text: `✅ Input sent to process ${pid}. Use read_process_output to get the response.${timingMessage}` }], }; } // Smart waiting with immediate and periodic detection let output = ""; let processState: ProcessState | undefined; let earlyExit = false; // Quick prompt patterns for immediate detection const quickPromptPatterns = />>>\s*$|>\s*$|\$\s*$|#\s*$/; const waitForResponse = (): Promise<void> => { return new Promise((resolve) => { let resolved = false; let attempts = 0; const pollIntervalMs = 50; // Poll every 50ms for faster response const maxAttempts = Math.ceil(timeout_ms / pollIntervalMs); let interval: NodeJS.Timeout | null = null; let lastOutputLength = 0; // Track output length to detect new output let resolveOnce = () => { if (resolved) return; resolved = true; if (interval) clearInterval(interval); resolve(); }; // Fast-polling check - check every 50ms for quick responses interval = setInterval(() => { if (resolved) return; // Use snapshot-based reading to handle REPL prompt line appending const newOutput = outputSnapshot ? terminalManager.getOutputSinceSnapshot(pid, outputSnapshot) : terminalManager.getNewOutput(pid); if (newOutput && newOutput.length > lastOutputLength) { const now = Date.now(); if (!firstOutputTime) firstOutputTime = now; lastOutputTime = now; if (verbose_timing) { outputEvents.push({ timestamp: now, deltaMs: now - startTime, source: 'periodic_poll', length: newOutput.length - lastOutputLength, snippet: newOutput.slice(lastOutputLength, lastOutputLength + 50).replace(/\n/g, '\\n') }); } output = newOutput; // Replace with full output since snapshot lastOutputLength = newOutput.length; // Analyze current state processState = analyzeProcessState(output, pid); // Exit early if we detect the process is waiting for input if (processState.isWaitingForInput) { earlyExit = true; exitReason = 'early_exit_periodic_check'; if (verbose_timing && outputEvents.length > 0) { outputEvents[outputEvents.length - 1].matchedPattern = 'periodic_check'; } resolveOnce(); return; } // Also exit if process finished if (processState.isFinished) { exitReason = 'process_finished'; resolveOnce(); return; } } attempts++; if (attempts >= maxAttempts) { exitReason = 'timeout'; resolveOnce(); } }, pollIntervalMs); }); }; await waitForResponse(); // Clean and format output let cleanOutput = cleanProcessOutput(output, input); const timeoutReached = !earlyExit && !processState?.isFinished && !processState?.isWaitingForInput; // Apply output line limit to prevent context overflow let truncationMessage = ''; const outputLines = cleanOutput.split('\n'); if (outputLines.length > maxOutputLines) { const truncatedLines = outputLines.slice(0, maxOutputLines); cleanOutput = truncatedLines.join('\n'); const remainingLines = outputLines.length - maxOutputLines; truncationMessage = `\n\n⚠️ Output truncated: showing ${maxOutputLines} of ${outputLines.length} lines (${remainingLines} hidden). Use read_process_output with offset/length for full output.`; } // Determine final state if (!processState) { processState = analyzeProcessState(output, pid); } let statusMessage = ''; if (processState.isWaitingForInput) { statusMessage = `\n🔄 ${formatProcessStateMessage(processState, pid)}`; } else if (processState.isFinished) { statusMessage = `\n✅ ${formatProcessStateMessage(processState, pid)}`; } else if (timeoutReached) { statusMessage = '\n⏱️ Response may be incomplete (timeout reached)'; } // Add timing information if requested let timingMessage = ''; if (verbose_timing) { const endTime = Date.now(); const timingInfo = { startTime, endTime, totalDurationMs: endTime - startTime, exitReason, firstOutputTime, lastOutputTime, timeToFirstOutputMs: firstOutputTime ? firstOutputTime - startTime : undefined, outputEvents: outputEvents.length > 0 ? outputEvents : undefined }; timingMessage = formatTimingInfo(timingInfo); } if (cleanOutput.trim().length === 0 && !timeoutReached) { return { content: [{ type: "text", text: `✅ Input executed in process ${pid}.\n📭 (No output produced)${statusMessage}${timingMessage}` }], }; } // Format response with better structure and consistent emojis let responseText = `✅ Input executed in process ${pid}`; if (cleanOutput && cleanOutput.trim().length > 0) { responseText += `:\n\n📤 Output:\n${cleanOutput}`; } else { responseText += `.\n📭 (No output produced)`; } if (statusMessage) { responseText += `\n\n${statusMessage}`; } if (truncationMessage) { responseText += truncationMessage; } if (timingMessage) { responseText += timingMessage; } return { content: [{ type: "text", text: responseText }], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); capture('server_interact_with_process_error', { error: errorMessage }); return { content: [{ type: "text", text: `Error interacting with process: ${errorMessage}` }], isError: true, }; } }
- src/server.ts:1250-1252 (registration)In the MCP call_tool request handler switch, dispatches 'interact_with_process' calls to the specific handler function.case "interact_with_process": result = await handlers.handleInteractWithProcess(args); break;
- src/server.ts:842-907 (registration)Tool registration in list_tools handler: defines name, description, input schema (from InteractWithProcessArgsSchema), and annotations for the interact_with_process tool.name: "interact_with_process", description: ` Send input to a running process and automatically receive the response. CRITICAL: THIS IS THE PRIMARY TOOL FOR ALL LOCAL FILE ANALYSIS For ANY local file analysis (CSV, JSON, data processing), ALWAYS use this instead of the analysis tool. The analysis tool CANNOT access local files and WILL FAIL - use processes for ALL file-based work. FILE ANALYSIS PRIORITY ORDER (MANDATORY): 1. ALWAYS FIRST: Use this tool (start_process + interact_with_process) for local data analysis 2. ALTERNATIVE: Use command-line tools (cut, awk, grep) for quick processing 3. NEVER EVER: Use analysis tool for local file access (IT WILL FAIL) REQUIRED INTERACTIVE WORKFLOW FOR FILE ANALYSIS: 1. Start REPL: start_process("python3 -i") 2. Load libraries: interact_with_process(pid, "import pandas as pd, numpy as np") 3. Read file: interact_with_process(pid, "df = pd.read_csv('/absolute/path/file.csv')") 4. Analyze: interact_with_process(pid, "print(df.describe())") 5. Continue: interact_with_process(pid, "df.groupby('column').size()") BINARY FILE PROCESSING WORKFLOWS: Use appropriate Python libraries (PyPDF2, pandas, docx2txt, etc.) or command-line tools for binary file analysis. SMART DETECTION: - Automatically waits for REPL prompt (>>>, >, etc.) - Detects errors and completion states - Early exit prevents timeout delays - Clean output formatting (removes prompts) SUPPORTED REPLs: - Python: python3 -i (RECOMMENDED for data analysis) - Node.js: node -i - R: R - Julia: julia - Shell: bash, zsh - Database: mysql, postgres PARAMETERS: - pid: Process ID from start_process - input: Code/command to execute - timeout_ms: Max wait (default: 8000ms) - wait_for_prompt: Auto-wait for response (default: true) - verbose_timing: Enable detailed performance telemetry (default: false) Returns execution result with status indicators. PERFORMANCE DEBUGGING (verbose_timing parameter): Set verbose_timing: true to get detailed timing information including: - Exit reason (early_exit_quick_pattern, early_exit_periodic_check, process_finished, timeout, no_wait) - Total duration and time to first output - Complete timeline of all output events with timestamps - Which detection mechanism triggered early exit Use this to identify slow interactions and optimize detection patterns. ALWAYS USE FOR: CSV analysis, JSON processing, file statistics, data visualization prep, ANY local file work NEVER USE ANALYSIS TOOL FOR: Local file access (it cannot read files from disk and WILL FAIL) ${CMD_PREFIX_DESCRIPTION}`, inputSchema: zodToJsonSchema(InteractWithProcessArgsSchema), annotations: { title: "Send Input to Process", readOnlyHint: false, destructiveHint: true, openWorldHint: true, }, },
- src/tools/schemas.ts:146-152 (schema)Zod schema defining input parameters for interact_with_process: pid (number), input (string), optional timeout_ms, wait_for_prompt, verbose_timing.export const InteractWithProcessArgsSchema = z.object({ pid: z.number(), input: z.string(), timeout_ms: z.number().optional(), wait_for_prompt: z.boolean().optional(), verbose_timing: z.boolean().optional(), });
- src/handlers/terminal-handlers.ts:35-40 (handler)Thin MCP handler wrapper that forwards args directly to the core interactWithProcess function (note: does not parse schema here)./** * Handle interact_with_process command (improved send_input) */ export async function handleInteractWithProcess(args: unknown): Promise<ServerResult> { return interactWithProcess(args); }