openclaw-mcp 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +18 -1
- package/docs/assets/claude-ai-demo.gif +0 -0
- package/docs/deployment.md +106 -0
- package/docs/installation.md +4 -0
- package/docs/logging.md +102 -0
- package/docs/threat-model.md +116 -0
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Tomáš Grasl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,8 +4,18 @@
|
|
|
4
4
|
[](https://github.com/freema/openclaw-mcp/actions/workflows/ci.yml)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
+
<a href="https://glama.ai/mcp/servers/@freema/openclaw-mcp">
|
|
8
|
+
<img width="380" height="200" src="https://glama.ai/mcp/servers/@freema/openclaw-mcp/badge" />
|
|
9
|
+
</a>
|
|
10
|
+
|
|
7
11
|
🦞 Model Context Protocol (MCP) server for [OpenClaw](https://github.com/openclaw/openclaw) AI assistant integration.
|
|
8
12
|
|
|
13
|
+
## Demo
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<img src="docs/assets/claude-ai-demo.gif" alt="OpenClaw MCP in Claude.ai" width="720" />
|
|
17
|
+
</p>
|
|
18
|
+
|
|
9
19
|
## Why I Built This
|
|
10
20
|
|
|
11
21
|
Hey! I created this MCP server because I didn't want to rely solely on messaging channels to communicate with OpenClaw. What really excites me is the ability to connect OpenClaw to the Claude web UI. Essentially, my chat can delegate tasks to my Claw bot, which then handles everything else — like spinning up Claude Code to fix issues for me.
|
|
@@ -41,10 +51,13 @@ Add to your Claude Desktop config:
|
|
|
41
51
|
|
|
42
52
|
```bash
|
|
43
53
|
AUTH_ENABLED=true MCP_CLIENT_ID=openclaw MCP_CLIENT_SECRET=your-secret \
|
|
54
|
+
MCP_ISSUER_URL=https://mcp.your-domain.com \
|
|
44
55
|
CORS_ORIGINS=https://claude.ai OPENCLAW_GATEWAY_TOKEN=your-gateway-token \
|
|
45
56
|
npx openclaw-mcp --transport sse --port 3000
|
|
46
57
|
```
|
|
47
58
|
|
|
59
|
+
> **Important:** When running behind a reverse proxy (Caddy, nginx, etc.), you **must** set `MCP_ISSUER_URL` (or `--issuer-url`) to your public HTTPS URL. Without this, OAuth metadata will advertise `http://localhost:3000` and clients will fail to authenticate.
|
|
60
|
+
|
|
48
61
|
Then in Claude.ai add a custom connector with your `MCP_CLIENT_ID` and `MCP_CLIENT_SECRET`.
|
|
49
62
|
|
|
50
63
|
See [Installation Guide](docs/installation.md) for details.
|
|
@@ -124,7 +137,11 @@ See [Configuration](docs/configuration.md) for all security options.
|
|
|
124
137
|
## Requirements
|
|
125
138
|
|
|
126
139
|
- Node.js ≥ 20
|
|
127
|
-
- OpenClaw gateway running
|
|
140
|
+
- OpenClaw gateway running with HTTP API enabled:
|
|
141
|
+
```json5
|
|
142
|
+
// openclaw.json
|
|
143
|
+
{ "gateway": { "http": { "endpoints": { "chatCompletions": { "enabled": true } } } } }
|
|
144
|
+
```
|
|
128
145
|
|
|
129
146
|
## License
|
|
130
147
|
|
|
Binary file
|
package/docs/deployment.md
CHANGED
|
@@ -20,6 +20,8 @@ services:
|
|
|
20
20
|
- AUTH_ENABLED=${AUTH_ENABLED:-true}
|
|
21
21
|
- MCP_CLIENT_ID=${MCP_CLIENT_ID:-openclaw}
|
|
22
22
|
- MCP_CLIENT_SECRET=${MCP_CLIENT_SECRET:-}
|
|
23
|
+
- MCP_ISSUER_URL=${MCP_ISSUER_URL:-}
|
|
24
|
+
- MCP_REDIRECT_URIS=${MCP_REDIRECT_URIS:-}
|
|
23
25
|
- CORS_ORIGINS=${CORS_ORIGINS:-https://claude.ai}
|
|
24
26
|
- NODE_ENV=production
|
|
25
27
|
extra_hosts:
|
|
@@ -49,6 +51,9 @@ MCP_CLIENT_SECRET=your-client-secret
|
|
|
49
51
|
# Enable OAuth (required for production SSE)
|
|
50
52
|
AUTH_ENABLED=true
|
|
51
53
|
|
|
54
|
+
# Public URL (required when behind a reverse proxy)
|
|
55
|
+
MCP_ISSUER_URL=https://mcp.your-domain.com
|
|
56
|
+
|
|
52
57
|
# Allowed CORS origins
|
|
53
58
|
CORS_ORIGINS=https://claude.ai
|
|
54
59
|
```
|
|
@@ -76,3 +81,104 @@ docker compose up -d
|
|
|
76
81
|
- [ ] `OPENCLAW_GATEWAY_TOKEN` set for gateway authentication
|
|
77
82
|
- [ ] Dynamic client registration is disabled (default — no `/register` endpoint)
|
|
78
83
|
- [ ] Container runs read-only with no-new-privileges
|
|
84
|
+
|
|
85
|
+
## Reverse Proxy (HTTPS)
|
|
86
|
+
|
|
87
|
+
The MCP bridge must be served over HTTPS for production use. Use a reverse proxy that handles TLS termination.
|
|
88
|
+
|
|
89
|
+
> **Important:** You **must** set `MCP_ISSUER_URL` to your public HTTPS URL. Without this, OAuth metadata endpoints will advertise `http://localhost:3000` and MCP clients (including Claude.ai) will fail to authenticate with the error: `Protected resource http://localhost:3000/mcp does not match expected https://your-domain.com/mcp`.
|
|
90
|
+
|
|
91
|
+
### Caddy (recommended)
|
|
92
|
+
|
|
93
|
+
Caddy automatically provisions Let's Encrypt certificates.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
mcp.your-domain.com {
|
|
97
|
+
reverse_proxy openclaw-mcp:3000
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Add to your `docker-compose.yml`:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
services:
|
|
105
|
+
caddy:
|
|
106
|
+
image: caddy:2-alpine
|
|
107
|
+
restart: unless-stopped
|
|
108
|
+
ports:
|
|
109
|
+
- "80:80"
|
|
110
|
+
- "443:443"
|
|
111
|
+
- "443:443/udp"
|
|
112
|
+
volumes:
|
|
113
|
+
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
114
|
+
- caddy-data:/data
|
|
115
|
+
- caddy-config:/config
|
|
116
|
+
|
|
117
|
+
mcp-bridge:
|
|
118
|
+
# ... (same as above, but remove the ports section)
|
|
119
|
+
expose:
|
|
120
|
+
- "3000"
|
|
121
|
+
environment:
|
|
122
|
+
- MCP_ISSUER_URL=https://mcp.your-domain.com
|
|
123
|
+
# ... other env vars
|
|
124
|
+
|
|
125
|
+
volumes:
|
|
126
|
+
caddy-data:
|
|
127
|
+
caddy-config:
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### nginx
|
|
131
|
+
|
|
132
|
+
```nginx
|
|
133
|
+
server {
|
|
134
|
+
listen 443 ssl http2;
|
|
135
|
+
server_name mcp.your-domain.com;
|
|
136
|
+
|
|
137
|
+
ssl_certificate /path/to/cert.pem;
|
|
138
|
+
ssl_certificate_key /path/to/key.pem;
|
|
139
|
+
|
|
140
|
+
location / {
|
|
141
|
+
proxy_pass http://localhost:3000;
|
|
142
|
+
proxy_http_version 1.1;
|
|
143
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
144
|
+
proxy_set_header Connection "upgrade";
|
|
145
|
+
proxy_set_header Host $host;
|
|
146
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## OpenClaw Gateway Prerequisites
|
|
152
|
+
|
|
153
|
+
The MCP bridge communicates with the OpenClaw gateway via its OpenAI-compatible HTTP API (`/v1/chat/completions`). This endpoint is **disabled by default** — you must enable it in your OpenClaw config:
|
|
154
|
+
|
|
155
|
+
```json5
|
|
156
|
+
// openclaw.json
|
|
157
|
+
{
|
|
158
|
+
"gateway": {
|
|
159
|
+
"http": {
|
|
160
|
+
"endpoints": {
|
|
161
|
+
"chatCompletions": {
|
|
162
|
+
"enabled": true
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Without this, the MCP bridge will receive `405 Method Not Allowed` from the gateway.
|
|
171
|
+
|
|
172
|
+
## Troubleshooting
|
|
173
|
+
|
|
174
|
+
### `405 Method Not Allowed` from gateway
|
|
175
|
+
|
|
176
|
+
The OpenClaw gateway's HTTP chat completions endpoint is disabled by default. Enable it in `openclaw.json` — see [Gateway Prerequisites](#openclaw-gateway-prerequisites) above.
|
|
177
|
+
|
|
178
|
+
### `Protected resource http://localhost:3000/mcp does not match expected https://...`
|
|
179
|
+
|
|
180
|
+
You're running behind a reverse proxy but haven't set `MCP_ISSUER_URL`. The OAuth metadata endpoints are advertising `http://localhost:3000` instead of your public HTTPS URL. Set `MCP_ISSUER_URL` to your public URL (e.g., `https://mcp.your-domain.com`) or pass `--issuer-url` on the CLI.
|
|
181
|
+
|
|
182
|
+
### `fetch failed` / MCP bridge can't reach gateway
|
|
183
|
+
|
|
184
|
+
When both services run in Docker, the MCP bridge must connect via the Docker network hostname (e.g., `http://openclaw-gateway:18789`), not `localhost`. Make sure both containers are on the same Docker network.
|
package/docs/installation.md
CHANGED
|
@@ -97,6 +97,10 @@ Options:
|
|
|
97
97
|
--auth Enable OAuth [default: false]
|
|
98
98
|
--client-id MCP OAuth client ID [env: MCP_CLIENT_ID]
|
|
99
99
|
--client-secret MCP OAuth client secret [env: MCP_CLIENT_SECRET]
|
|
100
|
+
--issuer-url OAuth issuer URL [env: MCP_ISSUER_URL]
|
|
101
|
+
--redirect-uris Allowed redirect URIs [env: MCP_REDIRECT_URIS]
|
|
100
102
|
--version Show version number
|
|
101
103
|
--help Show help
|
|
102
104
|
```
|
|
105
|
+
|
|
106
|
+
> **Note:** `--issuer-url` is required when running behind a reverse proxy (Caddy, nginx, etc.) so that OAuth metadata endpoints return the correct public HTTPS URL instead of `http://localhost:3000`.
|
package/docs/logging.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Logging
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The MCP server logs operational events to **stderr** using the `[openclaw-mcp]` prefix. Stderr is used (instead of stdout) because the stdio MCP transport uses stdout for protocol messages.
|
|
6
|
+
|
|
7
|
+
## Log Levels
|
|
8
|
+
|
|
9
|
+
| Level | Prefix | When |
|
|
10
|
+
|-------|--------|------|
|
|
11
|
+
| Info | `[openclaw-mcp]` | Normal operations — startup, connections, shutdown |
|
|
12
|
+
| Error | `[openclaw-mcp] ERROR:` | Failures — connection errors, invalid config, fatal errors |
|
|
13
|
+
| Debug | `[openclaw-mcp] DEBUG:` | Verbose output — only when `DEBUG=true` or `NODE_ENV=development` |
|
|
14
|
+
|
|
15
|
+
## What Gets Logged
|
|
16
|
+
|
|
17
|
+
### Startup
|
|
18
|
+
|
|
19
|
+
- Server name and version
|
|
20
|
+
- OpenClaw gateway URL (host only, no tokens)
|
|
21
|
+
- Transport type (stdio or SSE)
|
|
22
|
+
- Whether a gateway token is configured (yes/no, not the token itself)
|
|
23
|
+
- OAuth client ID (when auth is enabled)
|
|
24
|
+
- Listening address and port (SSE mode)
|
|
25
|
+
- CORS origins configuration
|
|
26
|
+
|
|
27
|
+
### Connections (SSE/HTTP transport)
|
|
28
|
+
|
|
29
|
+
- SSE session connected/disconnected (with session ID)
|
|
30
|
+
- Streamable HTTP session initialized/closed (with session ID)
|
|
31
|
+
|
|
32
|
+
### Errors
|
|
33
|
+
|
|
34
|
+
- Gateway connection failures
|
|
35
|
+
- Request timeouts
|
|
36
|
+
- Invalid client configuration (missing secrets, bad client ID format)
|
|
37
|
+
- Session errors
|
|
38
|
+
|
|
39
|
+
### What Is NOT Logged
|
|
40
|
+
|
|
41
|
+
- **Message content** — user messages and OpenClaw responses are never logged
|
|
42
|
+
- **Authentication tokens** — Bearer tokens, client secrets, gateway tokens
|
|
43
|
+
- **Request/response bodies** — only error messages, not full payloads
|
|
44
|
+
- **User-identifiable information** — no IPs, user agents, or personal data
|
|
45
|
+
|
|
46
|
+
## Sensitive Data Redaction
|
|
47
|
+
|
|
48
|
+
The logger automatically redacts patterns that look like credentials:
|
|
49
|
+
|
|
50
|
+
- `Bearer <token>` -> `[REDACTED]`
|
|
51
|
+
- `api_key=<value>` -> `[REDACTED]`
|
|
52
|
+
- `token=<value>` -> `[REDACTED]`
|
|
53
|
+
- `secret=<value>` -> `[REDACTED]`
|
|
54
|
+
- `password=<value>` -> `[REDACTED]`
|
|
55
|
+
|
|
56
|
+
This is a safety net — the code avoids logging sensitive values in the first place, but the redaction layer catches accidental exposure.
|
|
57
|
+
|
|
58
|
+
## Log Destination
|
|
59
|
+
|
|
60
|
+
| Transport | Destination | Notes |
|
|
61
|
+
|-----------|-------------|-------|
|
|
62
|
+
| stdio | stderr | Cannot use stdout (reserved for MCP protocol) |
|
|
63
|
+
| SSE/HTTP | stderr | Same format, same destination |
|
|
64
|
+
| Docker | `docker logs openclaw-mcp` | stderr is captured by Docker's log driver |
|
|
65
|
+
|
|
66
|
+
## Docker Log Management
|
|
67
|
+
|
|
68
|
+
When running in Docker, logs are managed by the Docker log driver:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# View logs
|
|
72
|
+
docker logs openclaw-mcp
|
|
73
|
+
|
|
74
|
+
# Follow logs
|
|
75
|
+
docker logs -f openclaw-mcp
|
|
76
|
+
|
|
77
|
+
# Last 100 lines
|
|
78
|
+
docker logs --tail 100 openclaw-mcp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
To configure log rotation in `docker-compose.yml`:
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
services:
|
|
85
|
+
mcp-bridge:
|
|
86
|
+
logging:
|
|
87
|
+
driver: json-file
|
|
88
|
+
options:
|
|
89
|
+
max-size: "10m"
|
|
90
|
+
max-file: "3"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Enabling Debug Logs
|
|
94
|
+
|
|
95
|
+
Set either environment variable:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
DEBUG=true # Explicit debug flag
|
|
99
|
+
NODE_ENV=development # Development mode
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Debug logs include additional operational detail but still never log message content or credentials.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Threat Model
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
Claude (Desktop / Claude.ai)
|
|
7
|
+
|
|
|
8
|
+
| MCP Protocol (stdio or SSE/Streamable HTTP)
|
|
9
|
+
v
|
|
10
|
+
OpenClaw MCP Server (this project)
|
|
11
|
+
|
|
|
12
|
+
| OpenAI-compatible REST API (POST /v1/chat/completions)
|
|
13
|
+
v
|
|
14
|
+
OpenClaw Gateway (user-controlled)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The MCP server is a **stateless proxy** — it translates MCP tool calls into OpenAI-compatible API requests and returns the response. It does not execute code, access the filesystem, or modify any external state on its own.
|
|
18
|
+
|
|
19
|
+
## What Claude Can Do (via MCP tools)
|
|
20
|
+
|
|
21
|
+
| Tool | Action | Side Effects |
|
|
22
|
+
|------|--------|--------------|
|
|
23
|
+
| `openclaw_chat` | Send a text message to OpenClaw, receive a text response | None — read-only query |
|
|
24
|
+
| `openclaw_status` | Check if the OpenClaw gateway is reachable | None — health check only |
|
|
25
|
+
| `openclaw_chat_async` | Queue a message for async processing, receive a task ID | Creates an in-memory task |
|
|
26
|
+
| `openclaw_task_status` | Check the status of an async task by ID | None — read-only |
|
|
27
|
+
| `openclaw_task_list` | List all async tasks and their statuses | None — read-only |
|
|
28
|
+
| `openclaw_task_cancel` | Cancel a pending async task by ID | Removes an in-memory task |
|
|
29
|
+
|
|
30
|
+
**Key point:** All tools either read data or send text messages to OpenClaw. The MCP server itself has **no write access** to any filesystem, database, or external service beyond the OpenClaw gateway.
|
|
31
|
+
|
|
32
|
+
## What Claude Cannot Do
|
|
33
|
+
|
|
34
|
+
- **Execute shell commands** — the server has no shell execution capability
|
|
35
|
+
- **Read or write files** — no filesystem access (Docker enforces `read_only: true`)
|
|
36
|
+
- **Access the network** — can only reach the configured OpenClaw gateway URL
|
|
37
|
+
- **Modify server configuration** — environment variables are set at startup, not changeable at runtime
|
|
38
|
+
- **Bypass authentication** — OAuth tokens are validated per-request when auth is enabled
|
|
39
|
+
- **Access other users' sessions** — sessions are isolated by MCP session ID
|
|
40
|
+
|
|
41
|
+
## Trust Boundaries
|
|
42
|
+
|
|
43
|
+
### Boundary 1: Claude <-> MCP Server
|
|
44
|
+
|
|
45
|
+
- **stdio transport (local):** Trusted — communication stays on the local machine. No authentication required.
|
|
46
|
+
- **SSE/HTTP transport (remote):** Untrusted network — requires OAuth 2.1 authentication, HTTPS (via reverse proxy), and CORS restrictions.
|
|
47
|
+
|
|
48
|
+
### Boundary 2: MCP Server <-> OpenClaw Gateway
|
|
49
|
+
|
|
50
|
+
- The MCP server authenticates to the gateway using a Bearer token (`OPENCLAW_GATEWAY_TOKEN`).
|
|
51
|
+
- The server validates the gateway URL at startup and blocks requests to private IP ranges (SSRF protection).
|
|
52
|
+
- Responses from the gateway are size-limited (10 MB max) and parsed as JSON — no raw pass-through.
|
|
53
|
+
|
|
54
|
+
### Boundary 3: User <-> Claude
|
|
55
|
+
|
|
56
|
+
- Claude decides which MCP tools to call and with what arguments. The MCP server validates all tool inputs (string length, type, format) but **cannot control Claude's intent**.
|
|
57
|
+
- If OpenClaw can perform actions with real-world consequences (e.g., sending emails, modifying data), those consequences are ultimately triggered by Claude's tool calls through the gateway.
|
|
58
|
+
|
|
59
|
+
## Attack Surfaces
|
|
60
|
+
|
|
61
|
+
### 1. Malicious MCP Tool Input
|
|
62
|
+
|
|
63
|
+
**Risk:** Crafted tool arguments could exploit the OpenClaw gateway.
|
|
64
|
+
|
|
65
|
+
**Mitigations:**
|
|
66
|
+
- All tool inputs are validated: type checks, string length limits, control character rejection
|
|
67
|
+
- The MCP server does not interpret message content — it passes validated strings to the gateway
|
|
68
|
+
|
|
69
|
+
### 2. Compromised OpenClaw Gateway
|
|
70
|
+
|
|
71
|
+
**Risk:** A compromised gateway could return malicious responses.
|
|
72
|
+
|
|
73
|
+
**Mitigations:**
|
|
74
|
+
- Response size limit (10 MB) prevents memory exhaustion
|
|
75
|
+
- Responses are parsed as JSON — no script execution
|
|
76
|
+
- Error messages from the gateway are sanitized before being returned to Claude
|
|
77
|
+
|
|
78
|
+
### 3. Network-Level Attacks (SSE transport)
|
|
79
|
+
|
|
80
|
+
**Risk:** Man-in-the-middle, replay attacks, unauthorized access.
|
|
81
|
+
|
|
82
|
+
**Mitigations:**
|
|
83
|
+
- OAuth 2.1 with client credentials (required for production)
|
|
84
|
+
- HTTPS via reverse proxy (Caddy or nginx)
|
|
85
|
+
- CORS restricted to configured origins (default: `https://claude.ai`)
|
|
86
|
+
- DNS rebinding protection via MCP SDK's Express middleware
|
|
87
|
+
|
|
88
|
+
### 4. Server-Side Request Forgery (SSRF)
|
|
89
|
+
|
|
90
|
+
**Risk:** Attacker could trick the server into making requests to internal services.
|
|
91
|
+
|
|
92
|
+
**Mitigations:**
|
|
93
|
+
- Only one outbound destination: the configured `OPENCLAW_URL`
|
|
94
|
+
- Private IP ranges are blocked at the client level
|
|
95
|
+
- URL is set at startup via environment variable, not controllable via tool input
|
|
96
|
+
|
|
97
|
+
### 5. Denial of Service
|
|
98
|
+
|
|
99
|
+
**Risk:** Resource exhaustion through excessive requests or large payloads.
|
|
100
|
+
|
|
101
|
+
**Mitigations:**
|
|
102
|
+
- Request timeout: 30 seconds per gateway call
|
|
103
|
+
- Response size limit: 10 MB
|
|
104
|
+
- Docker memory limit: 256 MB (configurable)
|
|
105
|
+
- Async task queue is in-memory with bounded processing
|
|
106
|
+
|
|
107
|
+
## Production Recommendations
|
|
108
|
+
|
|
109
|
+
If you expose this server beyond localhost:
|
|
110
|
+
|
|
111
|
+
1. **Enable OAuth 2.1** — set `AUTH_ENABLED=true` with strong client credentials
|
|
112
|
+
2. **Use HTTPS** — terminate TLS at a reverse proxy (Caddy recommended)
|
|
113
|
+
3. **Restrict CORS** — set `CORS_ORIGINS=https://claude.ai` (or your specific origin)
|
|
114
|
+
4. **Run in Docker** — use the provided `docker-compose.yml` with `read_only` and `no-new-privileges`
|
|
115
|
+
5. **Review gateway permissions** — the MCP server is only as safe as what the OpenClaw gateway allows. If OpenClaw can perform destructive actions, consider adding tool allowlists and human approval on the gateway side
|
|
116
|
+
6. **Monitor logs** — see [Logging](./logging.md) for what gets logged and where
|
package/package.json
CHANGED