OpenClaw Setup
OpenClaw agents access MCP servers through the mcporter CLI skill. This guide covers connecting an OpenClaw agent to Gatelet in both unsandboxed (host) and sandboxed (Docker) modes.
OpenClaw agents don’t have native MCP support — they use mcporter (an OpenClaw skill, not a plugin) via the exec tool to call MCP servers.
Prerequisites
Section titled “Prerequisites”- OpenClaw installed (
openclaw --version) - Gatelet running with a published port
- Node.js installed
Common setup
Section titled “Common setup”These steps apply to both unsandboxed and sandboxed agents.
Install mcporter globally
Section titled “Install mcporter globally”npm install -g mcporterVerify the skill is ready:
openclaw skills info mcporter# Should show: ✓ ReadyEnable the mcporter skill
Section titled “Enable the mcporter skill”openclaw config set skills.entries.mcporter.enabled trueOr manually add to ~/.openclaw/openclaw.json under skills.entries:
"mcporter": { "enabled": true }Create the mcporter config
Section titled “Create the mcporter config”mcporter looks for a project-level config at ./config/mcporter.json (relative to the working directory). Create it:
mkdir -p ./configCreate ./config/mcporter.json:
{ "mcpServers": { "gatelet": { "description": "Gatelet MCP proxy", "baseUrl": "http://localhost:4000/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } }}You can override the config path with mcporter --config /path/to/config.json.
Verify
Section titled “Verify”mcporter config listmcporter call gatelet.calendar_list_calendarsUnsandboxed agents (host)
Section titled “Unsandboxed agents (host)”If your OpenClaw agent runs directly on the host (no Docker sandbox), the common setup above is all you need. mcporter is already on PATH and can reach Gatelet at localhost.
Sandboxed agents (Docker)
Section titled “Sandboxed agents (Docker)”If your agent runs inside a Docker sandbox, additional steps are needed to make mcporter and its config available inside the container.
Architecture
Section titled “Architecture”Telegram/etc --> OpenClaw Gateway (:18789) | v Docker Sandbox (agent) | v mcporter CLI (exec tool) | v Gatelet MCP proxy (host.docker.internal:4000) | v Google Calendar, Gmail, etc.Additional prerequisites
Section titled “Additional prerequisites”- Docker running
- Node.js available in the sandbox Docker image
Place config in the workspace
Section titled “Place config in the workspace”The sandbox container mounts ~/.openclaw/workspace as /workspace. mcporter looks for a project-level config at /workspace/config/mcporter.json inside the container.
mkdir -p ~/.openclaw/workspace/configCreate ~/.openclaw/workspace/config/mcporter.json:
{ "mcpServers": { "gatelet": { "description": "Gatelet MCP proxy", "baseUrl": "http://host.docker.internal:4000/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } }}Copy mcporter into the workspace
Section titled “Copy mcporter into the workspace”Sandbox security blocks bind mounts from outside ~/.openclaw/workspace. Copy the mcporter package into the workspace:
cp -r "$(npm root -g)/mcporter" ~/.openclaw/workspace/.mcporter-binConfigure the Docker sandbox
Section titled “Configure the Docker sandbox”Add the following to ~/.openclaw/openclaw.json under agents.defaults.sandbox.docker:
{ "binds": [ "<WORKSPACE>/.mcporter-bin:/opt/mcporter:ro" ], "setupCommand": "mkdir -p /workspace/bin && ln -sf /opt/mcporter/dist/cli.js /workspace/bin/mcporter", "env": { "PATH": "/workspace/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" }}Replace <WORKSPACE> with your actual workspace path (e.g. /Users/you/.openclaw/workspace or /home/you/.openclaw/workspace).
Why each piece:
binds— mounts the mcporter package read-only into/opt/mcporterinside the containersetupCommand— creates a symlink somcporteris on PATH (can’t use/usr/local/binbecause root fs is read-only; can’t use/tmpbecause tmpfs wipes it)env.PATH— prepends/workspace/binso the agent can findmcporter
Recreate sandbox containers
Section titled “Recreate sandbox containers”Existing containers don’t pick up new bind mounts. Recreate them:
openclaw sandbox recreate --allNew containers will be created automatically on next agent message.
Verify from inside the sandbox
Section titled “Verify from inside the sandbox”# Find the containerdocker ps --filter "name=openclaw-sbx" --format "{{.Names}}"
# Verify mcporter worksdocker exec <CONTAINER_NAME> /workspace/bin/mcporter config list
# Test a tool calldocker exec <CONTAINER_NAME> /workspace/bin/mcporter call \ --http-url "http://host.docker.internal:4000/mcp" \ --allow-http --name gatelet \ calendar_list_calendarsThen message your bot and ask it to use mcporter to call gatelet tools.
Troubleshooting
Section titled “Troubleshooting”| Issue | Cause | Fix |
|---|---|---|
source is outside allowed roots | Bind mount path not inside workspace | Copy files into ~/.openclaw/workspace/ |
Read-only file system | Container root fs is read-only | Use /workspace/bin for symlinks, not /usr/local/bin |
No local servers match | mcporter can’t find config | Put config at ./config/mcporter.json (host) or <workspace>/config/mcporter.json (sandbox) |
getaddrinfo ENOTFOUND gatelet | Hostname not resolvable from container | Use host.docker.internal:PORT (macOS/Windows) or 172.17.0.1:PORT (Linux) |
Not Acceptable error | Server requires streamable-http Accept header | mcporter handles this automatically with baseUrl config |
| Symlink wiped after container start | Symlink was in /tmp (tmpfs) | Use /workspace/bin instead |
HOME=/ inside container | Container user has no home dir | Use project-level config at /workspace/config/mcporter.json |
| Agent doesn’t know about mcporter | Skill not enabled or not installed | Run npm install -g mcporter + enable skill in config |
Updating mcporter
Section titled “Updating mcporter”When mcporter gets a new version:
npm update -g mcporterIf using sandboxed agents, also update the workspace copy:
cp -r "$(npm root -g)/mcporter" ~/.openclaw/workspace/.mcporter-binopenclaw sandbox recreate --allAdding more MCP servers
Section titled “Adding more MCP servers”Add entries to your mcporter.json:
{ "mcpServers": { "gatelet": { "description": "Gatelet MCP proxy", "baseUrl": "http://localhost:4000/mcp", "headers": { "Authorization": "Bearer YOUR_TOKEN" } }, "another-server": { "description": "Another MCP server", "baseUrl": "https://mcp.example.com/mcp" } }}No restart needed — mcporter reads the config on each invocation.