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

> Troubleshoot MCP connection issues in Docker. Resolve problems with health endpoints, ROD_BROWSER_BIN, COOKIES_PATH volumes, and port mappings for a stable MCP setup.

- Repository: [zy/xiaohongshu-mcp](https://github.com/xpzouying/xiaohongshu-mcp)
- Tags: how-to-guide
- Published: 2026-03-09

---

**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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/routes.go) file mounts the MCP handler at `/mcp` using Gin:

```go
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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/app_server.go) provides a lightweight check that bypasses the browser entirely.

### Browser Automation Dependencies (configs/browser.go)

The [`configs/browser.go`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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:**

```bash
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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main//app/data/cookies.json) in [`docker-compose.yml`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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:**

```bash
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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/app_server.go) and exposed in the `Dockerfile` (`EXPOSE 18060`). If [`docker-compose.yml`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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:**

```bash
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**
   
   ```bash
   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**
   
   ```bash
   docker logs xiaohongshu-mcp | grep -i "MCP Server initialized"
   ```

   
   You should see the log entry from [`mcp_server.go`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/mcp_server.go) confirming the server started with the official SDK.

3. **Validate the Chrome binary path**
   
   ```bash
   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**
   
   ```bash
   docker exec xiaohongshu-mcp cat /app/data/cookies.json
   ```

   
   If the file is missing, create an empty JSON array on the host:
   
   ```bash
   echo "[]" > ./data/cookies.json
   docker restart xiaohongshu-mcp
   ```

5. **Execute a single MCP tool with verbose output**
   
   ```bash
   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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/docker-compose.yml):
   
   ```yaml
   services:
     xiaohongshu-mcp:
       shm_size: 2g
   ```

   
   Then rebuild:
   
   ```bash
   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:

```bash
#!/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:

```bash
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:

```bash
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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/docker-compose.yml) to confirm external clients can reach the `/mcp` endpoint exposed in [`routes.go`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/routes.go).
- **Inspect logs for panic traces** when tools return `IsError:true`; the recovery wrapper in [`mcp_server.go`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main//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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/app_server.go) and exposed in the `Dockerfile` (`EXPOSE 18060`). The [`docker-compose.yml`](https://github.com/xpzouying/xiaohongshu-mcp/blob/main/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.