Skip to main content
Glama
ooples

MCP Console Automation Server

RACE_CONDITION_SOLUTION_PLAN.md13.5 kB
# Race Condition Solution Plan ## Production-Ready Implementation for Console Automation MCP **Version:** 1.0 **Date:** 2025-09-27 **Status:** Implementation Ready --- ## Executive Summary After comprehensive analysis using sequential thinking MCP and reviewing all 34 console tools, the race condition in console automation is **not an architectural problem** but a **documentation and guidance issue**. **Key Finding:** The system already has three production-ready execution patterns that properly handle command completion. The race condition occurs because error messages guide users to low-level interactive APIs (`console_send_input` + `console_get_output`) instead of the proper high-level APIs. **Solution Complexity:** Low (documentation fixes) **Solution Impact:** High (eliminates race condition entirely) --- ## Root Cause Analysis ### The Problem Users experience race conditions when: 1. `console_execute_command` times out 2. Error message (lines 1402, 1461 in `src/mcp/server.ts`) suggests: *"use console_send_input and console_wait_for_output instead"* 3. Users follow this guidance and create the pattern: ```typescript await sendInput(sessionId, "long-command\n"); const output = await getOutput(sessionId); // Race condition - command not finished! ``` ### Why This Happens The error messages at lines 1402 and 1461 incorrectly suggest using `console_send_input` + `console_wait_for_output` as a replacement for `console_execute_command`: ```typescript // CURRENT ERROR MESSAGE (INCORRECT): if (error.message.includes('timeout') || error.message.includes('timed out')) { suggestion = '\n\nTip: This command timed out. For long-running commands, use console_create_session to create a persistent session, then use console_send_input and console_wait_for_output instead of console_execute_command. This allows better control over long-running processes.'; } ``` **Problem:** `sendInput` and `waitForOutput` are designed for **interactive shell scenarios** (SSH prompts, interactive CLIs), NOT for command execution. They don't wait for command completion automatically. --- ## Current Architecture (Already Correct) The system **already has** three production-ready execution patterns: ### 1. Synchronous Execution with Proper Polling **Tool:** `console_execute_command` **Implementation:** `ConsoleManager.executeCommandInSession()` (lines 993-1052) **How it works:** - Starts command execution tracking - Sends command to session - **Polls every 100ms** until command completes or timeout - Returns output with exit code and status **Use case:** Commands that complete within timeout (default 120s) ### 2. Streaming Execution for Large Outputs **Tools:** `console_create_session({streaming: true})` + `console_get_stream` **Implementation:** `StreamManager` (757 lines, production-ready) **How it works:** - Real-time EventEmitter-based output capture - Configurable chunking (512B - 4KB) - Server-side filtering to reduce data transfer - Rolling buffer with retention policies - **Solves 25k token limit problem** **Use case:** Long-running commands with large outputs (>25k tokens) **Documentation:** `docs/ENHANCED_STREAMING_API.md`, `docs/INTEGRATION_GUIDE.md` ### 3. Background Job Queue for Async Execution **Tools:** `console_execute_async` + 8 job management tools **Implementation:** `SessionManager` background job system **How it works:** - Priority-based job queue (1-10 priority levels) - Concurrency control (max 5 concurrent jobs) - Full lifecycle management (pending → running → completed/failed) - Event-driven notifications (`jobOutput`, `jobCompleted`, `jobError`) - Separate stdout/stderr capture with sequence numbers **Use case:** Truly async operations, batch processing, parallel execution **Documentation:** `BACKGROUND_JOBS_DOCUMENTATION.md` --- ## The Wrong Pattern (Current Problem) ### Low-Level Interactive APIs (Misused) **Tools:** `console_send_input` + `console_get_output` / `console_wait_for_output` **Intended use case:** Interactive shell scenarios: - SSH login prompts - Interactive CLI tools requiring user input - Waiting for specific shell prompts **Why they cause race conditions:** - `sendInput` sends text but doesn't wait - `getOutput` retrieves whatever is in buffer at that moment - `waitForOutput` waits for a PATTERN (like a prompt), not command completion - No automatic command completion detection **Current problem:** Error messages guide users to this pattern as a replacement for `execute_command` --- ## Solution: Documentation and Guidance Fixes ### Change 1: Fix Error Messages **File:** `src/mcp/server.ts` **Lines:** 1402, 1461 **Replace:** ```typescript suggestion = '\n\nTip: This command timed out. For long-running commands, use console_create_session to create a persistent session, then use console_send_input and console_wait_for_output instead of console_execute_command. This allows better control over long-running processes.'; ``` **With:** ```typescript suggestion = `\n\nTip: This command timed out. For long-running commands, use one of these approaches: 1. Increase timeout: Use console_execute_command with a longer timeout parameter Example: { command: "long-task", timeout: 300000 } // 5 minutes 2. Streaming session (for large outputs): Use console_create_session with streaming Example: { command: "long-task", streaming: true } Then use console_get_stream to retrieve output in chunks 3. Background job (for async execution): Use console_execute_async Then monitor with console_get_job_status and console_get_job_output See documentation for detailed examples of each pattern.`; ``` ### Change 2: Update Tool Descriptions **File:** `src/mcp/server.ts` **Line 313 - console_send_input:** ```typescript description: 'Send text input to a console session. WARNING: This is for interactive shells only (SSH prompts, interactive CLIs). For command execution, use console_execute_command or console_execute_async which handle completion automatically.' ``` **Line 401 - console_wait_for_output:** ```typescript description: 'Wait for specific output pattern in console (e.g., shell prompts). For command completion, use console_execute_command which waits automatically, or use streaming/background jobs for long-running commands.' ``` ### Change 3: Create Usage Patterns Documentation **File:** `docs/USAGE_PATTERNS.md` (NEW) **Contents:** - Decision tree: When to use each execution pattern - Complete examples for each pattern - Anti-patterns section with race condition explanation - Migration guide from incorrect to correct patterns ### Change 4: Update Integration Guide **File:** `docs/INTEGRATION_GUIDE.md` **Add section:** "Common Mistakes and Anti-Patterns" - Explicitly warn against sendInput/getOutput for command execution - Show race condition example - Show correct alternatives --- ## Implementation Steps ### Phase 1: Error Message Fixes (Critical) **Priority:** HIGH **Effort:** 1 hour **Files:** `src/mcp/server.ts` (lines 1402, 1461) 1. Update both error message suggestions with correct guidance 2. Add examples for each execution pattern 3. Test timeout scenarios to verify new messages appear ### Phase 2: Tool Description Updates **Priority:** HIGH **Effort:** 30 minutes **Files:** `src/mcp/server.ts` (lines 313, 401) 1. Add warnings to `console_send_input` description 2. Add warnings to `console_wait_for_output` description 3. Clarify intended use cases ### Phase 3: Create USAGE_PATTERNS.md **Priority:** HIGH **Effort:** 2-3 hours **Files:** `docs/USAGE_PATTERNS.md` (new) **Structure:** ```markdown # Console Automation Usage Patterns ## Quick Decision Tree [When to use which execution pattern] ## Pattern 1: Synchronous Execution [Complete example with execute_command] ## Pattern 2: Streaming Execution [Complete example with streaming session] ## Pattern 3: Background Jobs [Complete example with async execution] ## Anti-Patterns ### ❌ Race Condition: sendInput + getOutput [Explanation and correct alternatives] ## Migration Guide [How to fix existing code] ``` ### Phase 4: Update Integration Guide **Priority:** MEDIUM **Effort:** 1 hour **Files:** `docs/INTEGRATION_GUIDE.md` Add "Common Mistakes" section with: - Race condition anti-pattern - Visual diagram showing the problem - Links to correct patterns ### Phase 5: Add Examples **Priority:** MEDIUM **Effort:** 2 hours **Files:** `examples/` directory (new) Create example files: - `correct-patterns.ts` - Shows all three correct patterns - `common-mistakes.ts` - Shows anti-patterns with comments - `migration-examples.ts` - Before/after comparisons --- ## Testing Strategy ### Test 1: Error Message Verification ```bash # Trigger timeout scenario node dist/mcp/server.js # Call execute_command with 1ms timeout # Verify new error message appears with correct guidance ``` ### Test 2: Tool Description Check ```bash # Verify tool descriptions in MCP server # Check that warnings appear in sendInput and waitForOutput descriptions ``` ### Test 3: Pattern Validation Create test suite that validates: - ✅ execute_command properly waits for completion - ✅ Streaming session handles large outputs - ✅ Background jobs track lifecycle correctly - ❌ sendInput + getOutput creates race condition (demonstrate the problem) ### Test 4: Documentation Review - All three correct patterns documented - Anti-patterns clearly marked - Migration guide tested with real code examples --- ## Success Criteria 1. **No misleading guidance:** Error messages guide users to correct APIs 2. **Clear warnings:** Low-level APIs have warnings about proper usage 3. **Complete documentation:** Decision tree and examples for all patterns 4. **Zero race conditions:** Users following documentation won't hit race condition 5. **Easy migration:** Existing users can easily fix their code --- ## Migration Guide for Existing Users ### If you're currently using sendInput + getOutput: **Before (Race Condition):** ```typescript await sendInput(sessionId, "long-command\n"); const output = await getOutput(sessionId); // May not be complete! ``` **After Option 1 (Synchronous with longer timeout):** ```typescript const result = await executeCommand({ sessionId, command: "long-command", timeout: 300000 // 5 minutes }); console.log(result.output); // Guaranteed complete ``` **After Option 2 (Streaming for large outputs):** ```typescript const session = await createSession({ command: "long-command", streaming: true }); const stream = await getStream({ sessionId: session.sessionId, maxLines: 50 // Safe chunk size }); // Paginate through all output while (stream.hasMore) { // Process stream.chunks stream = await getStream({ sessionId: session.sessionId, since: stream.nextSequenceId }); } ``` **After Option 3 (Background job for async):** ```typescript const job = await executeAsync({ command: "long-command", options: { sessionId, timeout: 600000 } }); // Poll for completion let status; do { await sleep(1000); status = await getJobStatus(job.jobId); } while (status.job.status === 'running'); const output = await getJobOutput(job.jobId); ``` --- ## Risk Assessment ### Risks: LOW **Why low risk:** - No architectural changes required - Existing code continues to work - Only fixing guidance/documentation - All proper APIs already exist and are tested **Mitigation:** - Preserve backward compatibility - Keep old APIs functional (just better documented) - Provide clear migration path - Comprehensive testing of documentation accuracy --- ## Timeline **Total Effort:** 6-8 hours - Phase 1 (Error messages): 1 hour - Phase 2 (Tool descriptions): 30 minutes - Phase 3 (USAGE_PATTERNS.md): 2-3 hours - Phase 4 (Integration guide update): 1 hour - Phase 5 (Examples): 2 hours - Testing and validation: 1 hour **Recommended approach:** Implement in order (Phase 1 → Phase 5) to immediately stop new users from hitting the problem. --- ## Future Enhancements (Optional) ### 1. Smart Timeout Detection Add heuristic to detect likely timeouts and suggest appropriate pattern: - Command starts with `npm install` → suggest longer timeout - Command includes `train` or `build` → suggest background job - Expected large output → suggest streaming ### 2. Interactive Mode Detection Auto-detect when session needs interactive input vs command execution: - Prompt detection triggers interactive mode - Command execution triggers proper waiting ### 3. Runtime Warnings Add runtime detection: ```typescript if (sendInputCalledRecently && getOutputCalled) { console.warn('Potential race condition detected. Consider using execute_command instead.'); } ``` --- ## Conclusion The race condition in console automation MCP is **fully solvable** with documentation and guidance fixes. The underlying architecture is already production-ready with three proper execution patterns: 1. ✅ Synchronous execution with polling 2. ✅ Streaming for large outputs (25k+ tokens) 3. ✅ Background jobs for async execution The solution requires **no architectural changes**, only: - 2 error message updates - 2 tool description warnings - 1 new documentation file - Updated integration guide - Example code **Impact:** Eliminates race condition entirely by preventing users from using the wrong pattern. **Effort:** 6-8 hours total **Risk:** Low (documentation-only changes) This is a production-ready plan that can be implemented immediately.

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/ooples/mcp-console-automation'

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