How to Debug MCP Connection Issues in Docker: A Complete Guide for Xiaohongshu-MCP

To debug MCP connection issues in Docker, verify the health endpoint at /health, ensure the ROD_BROWSER_BIN environment variable points to a valid Chrome binary, confirm the COOKIES_PATH volume is writable, and check that port 18060 is correctly mapped between host and container.

The xpzouying/xiaohongshu-mcp repository implements a Model Context Protocol (MCP) server that exposes 13 tools for automating Xiaohongshu (Little Red Book) operations. When you debug MCP connection issues in Docker, you are typically troubleshooting the thin wrapper layer between the HTTP transport, the Rod browser automation library, and the file system persistence. This guide walks through the exact diagnostic steps using the actual source architecture.

Understanding the MCP Architecture in Xiaohongshu-MCP

The MCP Server Layer (mcp_server.go)

In mcp_server.go, the server initializes using the official Go SDK (github.com/modelcontextprotocol/go-sdk/mcp). The registerTools function registers 13 tools—including login, publish, and search—that forward requests to XiaohongshuService handlers like handlePublishContent and handleSearchFeeds.

Each tool execution is wrapped with panic recovery. If a tool returns IsError: true, the error originates from either the browser layer or the service handler, not the MCP protocol itself.

HTTP Routing and Endpoints (routes.go)

The routes.go file mounts the MCP handler at /mcp using Gin:

router.Any("/mcp", gin.WrapH(mcpHandler))
router.Any("/mcp/*path", gin.WrapH(mcpHandler))

This endpoint accepts both JSON-RPC and streaming calls via mcp.NewStreamableHTTPHandler. The separate /health endpoint in app_server.go provides a lightweight check that bypasses the browser entirely.

Browser Automation Dependencies (configs/browser.go)

The configs/browser.go file defines two critical settings:

  • useHeadless: Defaults to true; controls whether Chrome runs headless.
  • binPath: Populated from the ROD_BROWSER_BIN environment variable.

When running in Docker, these settings determine whether the Rod library can launch Chrome to execute login flows and content scraping.

Common MCP Connection Issues in Docker Environments

Chrome Binary Not Found (ROD_BROWSER_BIN)

The Dockerfile sets ENV ROD_BROWSER_BIN=/usr/bin/google-chrome, and docker-compose.yml passes this variable to the container. If the binary is missing or the path is incorrect, any tool requiring browser automation—such as get_login_qrcode—will panic.

Verification command:

docker exec xiaohongshu-mcp /usr/bin/google-chrome --version

The COOKIES_PATH environment variable defaults to /app/data/cookies.json in docker-compose.yml. The MCP tools read and write this file to maintain login state between restarts. If the volume mount is read-only or the directory does not exist, check_login_status will always return "not logged in."

Verification command:

docker exec xiaohongshu-mcp ls -l /app/data/cookies.json

Port Mapping and Network Connectivity

The MCP server listens on port 18060 as defined in app_server.go and exposed in the Dockerfile (EXPOSE 18060). If docker-compose.yml does not map the port ("18060:18060"), or if a firewall blocks the host port, external MCP clients will receive "connection refused" errors.

Verification command:

curl -s http://localhost:18060/health

File System Permission Errors

The Dockerfile applies chmod 777 /app/images to ensure the container can write downloaded media. If the host-mounted directories (./data and ./images) lack write permissions, image upload tools will fail silently or return 500 errors.

Step-by-Step Debugging Workflow

Follow this sequence to isolate the root cause when you debug MCP connection issues in Docker:

  1. Verify the HTTP layer is responsive

    curl -s http://localhost:18060/health | jq

    Expect {"status":"ok"}. If this fails, check docker ps for port mapping and container status.

  2. Inspect MCP server initialization logs

    docker logs xiaohongshu-mcp | grep -i "MCP Server initialized"

    You should see the log entry from mcp_server.go confirming the server started with the official SDK.

  3. Validate the Chrome binary path

    docker exec xiaohongshu-mcp which google-chrome
    docker exec xiaohongshu-mcp google-chrome --headless --disable-gpu --dump-dom "https://www.google.com"

    If the second command returns HTML, the ROD_BROWSER_BIN configuration is correct.

  4. Check cookie file accessibility

    docker exec xiaohongshu-mcp cat /app/data/cookies.json

    If the file is missing, create an empty JSON array on the host:

    echo "[]" > ./data/cookies.json
    docker restart xiaohongshu-mcp
  5. Execute a single MCP tool with verbose output

    curl -X POST http://localhost:18060/mcp \
      -H "Content-Type: application/json" \
      -d '{"tool":"check_login_status"}' -v

    If the response contains IsError:true, immediately check docker logs for the stack trace. The panic recovery in mcp_server.go will point to the specific handler (e.g., handlePublishContent) and line number.

  6. Increase shared memory if Chrome crashes

    Add to docker-compose.yml:

    services:
      xiaohongshu-mcp:
        shm_size: 2g

    Then rebuild:

    docker compose up -d --force-recreate

Diagnostic Scripts and Code Examples

Health Check Verification

Use this script to confirm the MCP server is reachable before testing tools:

#!/usr/bin/env bash
set -euo pipefail

URL=${1:-http://localhost:18060/health}
if curl -s "$URL" | grep -q '"status":"ok"'; then
  echo "✅ MCP server reachable"
else
  echo "❌ Health check failed – inspect container logs"
  docker logs xiaohongshu-mcp | tail -n 20
fi

Chrome Binary Validation

Test whether the Rod browser automation can launch Chrome inside the container:

docker exec -it xiaohongshu-mcp /usr/bin/google-chrome \
  --headless --disable-gpu --remote-debugging-port=9222 \
  "https://www.xiaohongshu.com"

If Chrome starts and prints JSON containing the page title, the browser layer is healthy.

Verify that the login state persists across restarts:

docker exec -it xiaohongshu-mcp sh -c '
  echo "=== Cookie file status ==="
  ls -l /app/data/cookies.json
  echo "=== Content (sanitized) ==="
  cat /app/data/cookies.json | jq ".[] | {name, domain}"
'

If the file is missing or empty, the check_login_status tool will always report "not logged in."

Summary

  • Verify the HTTP layer first by calling /health to ensure the AppServer in app_server.go is responsive before debugging MCP tools.
  • Validate Chrome availability by checking ROD_BROWSER_BIN inside the container; the Rod library requires this binary to execute login and scraping tools.
  • Ensure cookie persistence by verifying that COOKIES_PATH points to a writable file inside a mounted volume, allowing login state to survive container restarts.
  • Check port mapping for 18060 in docker-compose.yml to confirm external clients can reach the /mcp endpoint exposed in routes.go.
  • Inspect logs for panic traces when tools return IsError:true; the recovery wrapper in mcp_server.go logs stack traces that pinpoint failing handlers like handlePublishContent.

Frequently Asked Questions

Why does my MCP server return 500 errors in Docker?

500 errors indicate a panic inside a tool handler, typically caused by a missing Chrome binary or an unreadable cookie file. Check docker logs xiaohongshu-mcp for logrus.WithError entries originating from mcp_server.go. If you see errors about image decoding or browser launch failures, verify that ROD_BROWSER_BIN points to a valid Chrome executable and that /app/data is writable.

How do I verify Chrome is installed correctly in the container?

Execute docker exec xiaohongshu-mcp /usr/bin/google-chrome --version to confirm the binary exists. For a functional test, run docker exec xiaohongshu-mcp google-chrome --headless --disable-gpu --dump-dom "https://www.google.com". If this returns HTML content, the Rod browser automation layer will function correctly for MCP tools that require web scraping or login flows.

Why is the login state not persisting between container restarts?

The check_login_status tool reads from the file specified by COOKIES_PATH (default /app/data/cookies.json). If this file is missing or the volume is not mounted, the container starts with an empty session. Verify persistence by running docker exec xiaohongshu-mcp cat /app/data/cookies.json; you should see a JSON array. If the file is empty or inaccessible, ensure your docker-compose.yml mounts ./data:/app/data and that the host directory has write permissions.

What port does the Xiaohongshu-MCP server use by default?

The server listens on port 18060, as defined in app_server.go and exposed in the Dockerfile (EXPOSE 18060). The docker-compose.yml maps this to the host via "18060:18060". You can verify connectivity by running curl http://localhost:18060/health, which should return {"status":"ok"} without invoking the browser layer.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →