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 totrue; controls whether Chrome runs headless.binPath: Populated from theROD_BROWSER_BINenvironment 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
Cookie Persistence Failures (COOKIES_PATH)
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:
-
Verify the HTTP layer is responsive
curl -s http://localhost:18060/health | jqExpect
{"status":"ok"}. If this fails, checkdocker psfor port mapping and container status. -
Inspect MCP server initialization logs
docker logs xiaohongshu-mcp | grep -i "MCP Server initialized"You should see the log entry from
mcp_server.goconfirming the server started with the official SDK. -
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_BINconfiguration is correct. -
Check cookie file accessibility
docker exec xiaohongshu-mcp cat /app/data/cookies.jsonIf the file is missing, create an empty JSON array on the host:
echo "[]" > ./data/cookies.json docker restart xiaohongshu-mcp -
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"}' -vIf the response contains
IsError:true, immediately checkdocker logsfor the stack trace. The panic recovery inmcp_server.gowill point to the specific handler (e.g.,handlePublishContent) and line number. -
Increase shared memory if Chrome crashes
Add to
docker-compose.yml:services: xiaohongshu-mcp: shm_size: 2gThen 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.
Cookie File Inspection
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
/healthto ensure theAppServerinapp_server.gois responsive before debugging MCP tools. - Validate Chrome availability by checking
ROD_BROWSER_BINinside the container; the Rod library requires this binary to execute login and scraping tools. - Ensure cookie persistence by verifying that
COOKIES_PATHpoints to a writable file inside a mounted volume, allowing login state to survive container restarts. - Check port mapping for
18060indocker-compose.ymlto confirm external clients can reach the/mcpendpoint exposed inroutes.go. - Inspect logs for panic traces when tools return
IsError:true; the recovery wrapper inmcp_server.gologs stack traces that pinpoint failing handlers likehandlePublishContent.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →