Files
n8n-mcp/docs/DOCKER_FIX_IMPLEMENTATION.md
czlonkowski 75952f94ca fix: Docker stdio communication for Claude Desktop compatibility
Fixed the initialization timeout issue with minimal changes:

1. Added stdout flush after server connection to combat Docker buffering
2. Fixed docker-entrypoint.sh to not output to stdout in stdio mode
3. Added process.stdin.resume() to keep server alive
4. Added IS_DOCKER environment variable for future use
5. Updated README to prioritize Docker with correct -i flag configuration

The core issue was Docker's block buffering preventing immediate JSON-RPC
responses. The -i flag maintains stdin connection, and explicit flushing
ensures responses reach Claude Desktop immediately.

Also fixed "Shutting down..." message that was breaking JSON-RPC protocol
by redirecting it to stderr in stdio mode.

Docker is now the recommended installation method as originally intended.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 00:30:54 +02:00

4.3 KiB

Docker stdio Fix Implementation Plan for n8n-MCP

Based on community research and successful MCP Docker deployments, here's a streamlined fix for the initialization timeout issue.

Root Cause

Docker treats container stdout as a pipe (not TTY), causing block buffering. The MCP server's JSON-RPC responses sit in the buffer instead of being immediately sent to Claude Desktop, causing a 60-second timeout.

Implementation Steps

Step 1: Test Simple Interactive Mode

First, verify if just using -i flag solves the issue:

Update README.md:

{
  "mcpServers": {
    "n8n-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",  // Interactive mode - keeps stdin open
        "--rm",
        "-e", "MCP_MODE=stdio",
        "-e", "LOG_LEVEL=error", 
        "-e", "DISABLE_CONSOLE_OUTPUT=true",
        "ghcr.io/czlonkowski/n8n-mcp:latest"
      ]
    }
  }
}

Test command:

echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05"},"id":1}' | \
  docker run -i --rm \
    -e MCP_MODE=stdio \
    -e LOG_LEVEL=error \
    -e DISABLE_CONSOLE_OUTPUT=true \
    ghcr.io/czlonkowski/n8n-mcp:latest

Expected: Should receive a JSON response immediately.

Step 2: Add Explicit Stdout Flushing (If Needed)

If Step 1 doesn't work, add minimal flushing to the Node.js server:

File: src/mcp/server-update.ts

Update the run() method:

async run(): Promise<void> {
  await this.ensureInitialized();
  
  const transport = new StdioServerTransport();
  await this.server.connect(transport);
  
  // Ensure stdout is not buffered in Docker
  if (!process.stdout.isTTY && process.env.IS_DOCKER) {
    // Force unbuffered stdout
    process.stdout.write('');
  }
  
  logger.info('n8n Documentation MCP Server running on stdio transport');
  
  // Keep process alive
  process.stdin.resume();
}

File: Dockerfile

Add environment variable:

ENV IS_DOCKER=true

Step 3: System-Level Unbuffering (Last Resort)

Only if Steps 1-2 fail, implement stdbuf wrapper:

File: docker-entrypoint.sh

#!/bin/sh
# Force line buffering for stdio communication
exec stdbuf -oL -eL node /app/dist/mcp/index.js

File: Dockerfile

# Add stdbuf utility
RUN apk add --no-cache coreutils

# Copy and setup entrypoint
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

ENTRYPOINT ["/docker-entrypoint.sh"]

Testing Protocol

1. Local Docker Test

# Build test image
docker build -t n8n-mcp:test .

# Test with echo pipe
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05"},"id":1}' | \
  docker run -i --rm n8n-mcp:test | head -1

# Should see immediate JSON response

2. Claude Desktop Test

  1. Update claude_desktop_config.json with new configuration
  2. Restart Claude Desktop
  3. Check Developer tab for "running" status
  4. Test a simple MCP command

3. Debug if Needed

# Run with stderr output for debugging
docker run -i --rm \
  -e MCP_MODE=stdio \
  -e LOG_LEVEL=debug \
  ghcr.io/czlonkowski/n8n-mcp:latest 2>debug.log

Success Criteria

  • No timeout errors in Claude Desktop logs
  • MCP tools are accessible immediately
  • No "Shutting down..." messages in stdout
  • Simple -i flag configuration works

Rollout Plan

  1. Test locally with simple -i flag first
  2. Update Docker image only if code changes needed
  3. Update README with working configuration
  4. Community announcement with simple Docker instructions

Key Insights from Research

  • Most MCP Docker deployments work with just -i flag
  • Complex solutions often unnecessary
  • Node.js typically doesn't need explicit unbuffering (unlike Python with -u)
  • Claude Desktop only supports stdio for local servers (not HTTP)
  • Proper testing can quickly identify if buffering is the actual issue

What NOT to Do

  • Don't add TTY flag (-t) - it's for terminal UI, not needed for MCP
  • Don't implement complex multi-phase solutions
  • Don't switch to HTTP transport (Claude Desktop doesn't support it locally)
  • Don't modify MCP protocol handling
  • Don't add unnecessary wrapper scripts unless proven necessary

The solution should be as simple as possible - likely just the -i flag in the Docker command.