diff --git a/.github/workflows/docker-build-fast.yml b/.github/workflows/docker-build-fast.yml index 71cefd9..be13fa3 100644 --- a/.github/workflows/docker-build-fast.yml +++ b/.github/workflows/docker-build-fast.yml @@ -29,9 +29,15 @@ jobs: with: lfs: true + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - + - name: Log in to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3 diff --git a/.github/workflows/docker-build-n8n.yml b/.github/workflows/docker-build-n8n.yml index d7c4b95..36a3953 100644 --- a/.github/workflows/docker-build-n8n.yml +++ b/.github/workflows/docker-build-n8n.yml @@ -55,6 +55,12 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 70a58ad..40f026e 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -71,13 +71,19 @@ jobs: " echo "✅ Synced package.runtime.json to version $VERSION" + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - + - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - + - name: Log in to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3 @@ -85,7 +91,7 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: Extract metadata id: meta uses: docker/metadata-action@v5 @@ -173,13 +179,19 @@ jobs: " echo "✅ Synced package.runtime.json to version $VERSION" + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - + - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - + - name: Log in to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 89890a4..92557d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -441,12 +441,18 @@ jobs: " echo "✅ Synced package.runtime.json to version $VERSION" + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU uses: docker/setup-qemu-action@v3 - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d915dd..4472fcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.41.2] - 2026-03-27 + +### Fixed + +- **MCP initialization floods Claude Desktop with JSON parse errors** (Issues #628, #627, #567): Intercept `process.stdout.write` in stdio mode to redirect non-JSON-RPC output to stderr. Console method suppression alone was insufficient — native modules (better-sqlite3), n8n packages, and third-party code can call `process.stdout.write()` directly, corrupting the JSON-RPC stream. Only writes containing valid JSON-RPC messages (`{"jsonrpc":...}`) are now allowed through stdout; everything else is redirected to stderr. This fixes the flood of "Unexpected token is not valid JSON" warnings on every new chat in Claude Desktop, including leaked `refCount`, `dbPath`, `clientVersion`, `protocolVersion`, and other debug strings. + +Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en + ## [2.41.1] - 2026-03-27 ### Fixed diff --git a/package-lock.json b/package-lock.json index dd33495..8edc6b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "n8n-mcp", - "version": "2.41.1", + "version": "2.41.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "n8n-mcp", - "version": "2.41.1", + "version": "2.41.2", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "1.28.0", diff --git a/package.json b/package.json index 4bf2eb4..6489cc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.41.1", + "version": "2.41.2", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/mcp/stdio-wrapper.ts b/src/mcp/stdio-wrapper.ts index 8dac848..7f578c1 100644 --- a/src/mcp/stdio-wrapper.ts +++ b/src/mcp/stdio-wrapper.ts @@ -39,6 +39,25 @@ console.clear = () => {}; console.count = () => {}; console.countReset = () => {}; +// CRITICAL: Intercept process.stdout.write to prevent non-JSON-RPC output (#628, #627, #567) +// Console suppression alone is insufficient — native modules (better-sqlite3), n8n packages, +// and third-party code can call process.stdout.write() directly, corrupting the JSON-RPC stream. +// Only allow writes that look like JSON-RPC messages; redirect everything else to stderr. +const originalStdoutWrite = process.stdout.write.bind(process.stdout); +const stderrWrite = process.stderr.write.bind(process.stderr); + +process.stdout.write = function (chunk: any, encodingOrCallback?: any, callback?: any): boolean { + const str = typeof chunk === 'string' ? chunk : chunk.toString(); + // JSON-RPC messages are JSON objects with "jsonrpc" field — let those through + // The MCP SDK sends one JSON object per write call + const trimmed = str.trimStart(); + if (trimmed.startsWith('{') && trimmed.includes('"jsonrpc"')) { + return originalStdoutWrite(chunk, encodingOrCallback, callback); + } + // Redirect everything else to stderr so it doesn't corrupt the protocol + return stderrWrite(chunk, encodingOrCallback, callback); +} as typeof process.stdout.write; + // Import and run the server AFTER suppressing output import { N8NDocumentationMCPServer } from './server';