xiaowan 0.1.0 → 0.1.1
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 +1 -1
- package/README.md +107 -169
- package/config.ts +51 -0
- package/index.ts +47 -0
- package/mcp-client.ts +90 -0
- package/openclaw.plugin.json +123 -0
- package/package.json +11 -36
- package/dist/index.d.ts +0 -10
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -13
- package/dist/index.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -38
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -138
- package/dist/mcp-client.js.map +0 -1
- package/dist/mcp-plugin.d.ts +0 -16
- package/dist/mcp-plugin.d.ts.map +0 -1
- package/dist/mcp-plugin.js +0 -79
- package/dist/mcp-plugin.js.map +0 -1
- package/dist/tools.d.ts +0 -28
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -91
- package/dist/tools.js.map +0 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,85 +1,50 @@
|
|
|
1
|
-
#
|
|
1
|
+
# MCP Adapter (OpenClaw Plugin)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Exposes MCP (Model Context Protocol) server tools as native OpenClaw agent tools.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Instead of running MCP servers through a CLI skill, this plugin connects to your MCP servers at startup, discovers their tools, and registers each one as a first-class tool that agents can invoke directly.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Register MCP tools as native OpenClaw agent tools
|
|
9
|
-
- Support for multiple transport types:
|
|
10
|
-
- **Stdio** - Local MCP servers and npx commands
|
|
11
|
-
- **SSE** - Server-Sent Events over HTTP/HTTPS
|
|
12
|
-
- **Streamable HTTP** - HTTP with streaming support and Bearer auth
|
|
13
|
-
- Connection status monitoring with health checks
|
|
14
|
-
- CLI commands for server management
|
|
15
|
-
- Gateway RPC methods for status queries
|
|
7
|
+
## Requirements
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
- OpenClaw gateway
|
|
10
|
+
- Node.js 18+
|
|
11
|
+
- MCP servers you want to connect to
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
## Installation
|
|
20
14
|
|
|
21
15
|
```bash
|
|
22
|
-
openclaw plugins install
|
|
23
|
-
openclaw gateway restart
|
|
16
|
+
openclaw plugins install mcp-adapter
|
|
24
17
|
```
|
|
25
18
|
|
|
26
|
-
|
|
19
|
+
**Alternative: install from source**
|
|
27
20
|
|
|
28
21
|
```bash
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
cd OmniClawPlugin
|
|
32
|
-
|
|
33
|
-
# Install dependencies
|
|
34
|
-
npm install
|
|
35
|
-
|
|
36
|
-
# Build the plugin
|
|
37
|
-
npm run build
|
|
38
|
-
|
|
39
|
-
# Link this plugin to your OpenClaw extensions
|
|
40
|
-
openclaw plugins install -l /path/to/OmniClawPlugin
|
|
41
|
-
|
|
42
|
-
# Restart the gateway
|
|
43
|
-
openclaw gateway restart
|
|
22
|
+
git clone https://github.com/androidStern/openclaw-mcp-adapter.git
|
|
23
|
+
openclaw plugins install ./openclaw-mcp-adapter
|
|
44
24
|
```
|
|
45
25
|
|
|
46
26
|
## Configuration
|
|
47
27
|
|
|
48
|
-
|
|
28
|
+
### 1. Enable the plugin and configure servers
|
|
49
29
|
|
|
50
|
-
|
|
30
|
+
Add to `~/.openclaw/openclaw.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
51
33
|
{
|
|
52
|
-
plugins: {
|
|
53
|
-
entries: {
|
|
54
|
-
"
|
|
55
|
-
enabled: true,
|
|
56
|
-
config: {
|
|
57
|
-
servers: [
|
|
58
|
-
{
|
|
59
|
-
id: "filesystem",
|
|
60
|
-
name: "Filesystem Tools",
|
|
61
|
-
url: "npx -y @modelcontextprotocol/server-filesystem /tmp",
|
|
62
|
-
enabled: true
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
id: "git",
|
|
66
|
-
name: "Git Operations",
|
|
67
|
-
url: "npx -y @modelcontextprotocol/server-git /path/to/repo",
|
|
68
|
-
enabled: true
|
|
69
|
-
},
|
|
34
|
+
"plugins": {
|
|
35
|
+
"entries": {
|
|
36
|
+
"mcp-adapter": {
|
|
37
|
+
"enabled": true,
|
|
38
|
+
"config": {
|
|
39
|
+
"servers": [
|
|
70
40
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
name: "My HTTP Server",
|
|
79
|
-
url: "https://api.example.com/mcp",
|
|
80
|
-
type: "streamablehttp",
|
|
81
|
-
token: "your-bearer-token",
|
|
82
|
-
enabled: true
|
|
41
|
+
"name": "myserver",
|
|
42
|
+
"transport": "stdio",
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "some-mcp-server"],
|
|
45
|
+
"env": {
|
|
46
|
+
"API_KEY": "${MY_API_KEY}"
|
|
47
|
+
}
|
|
83
48
|
}
|
|
84
49
|
]
|
|
85
50
|
}
|
|
@@ -89,146 +54,119 @@ Add to your OpenClaw config file:
|
|
|
89
54
|
}
|
|
90
55
|
```
|
|
91
56
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
### Transport Types
|
|
95
|
-
|
|
96
|
-
The plugin automatically detects the transport type based on the URL or explicit `type` field:
|
|
57
|
+
### 2. Allow for sandboxed agents
|
|
97
58
|
|
|
98
|
-
|
|
99
|
-
|------|-------------|-------------|
|
|
100
|
-
| **Stdio** | Any non-HTTP URL | Local executables and npx commands |
|
|
101
|
-
| **SSE** | `http://` or `https://` | Server-Sent Events transport |
|
|
102
|
-
| **Streamable HTTP** | Explicit `type: "streamablehttp"` | HTTP with Bearer auth and streaming |
|
|
59
|
+
Add `"mcp-adapter"` to your sandbox tool allowlist:
|
|
103
60
|
|
|
104
|
-
### Server Properties
|
|
105
|
-
|
|
106
|
-
| Property | Type | Required | Description |
|
|
107
|
-
|----------|------|----------|-------------|
|
|
108
|
-
| `id` | string | Yes | Unique identifier for the server |
|
|
109
|
-
| `name` | string | No | Display name (defaults to `id`) |
|
|
110
|
-
| `url` | string | Yes | Server URL or command |
|
|
111
|
-
| `type` | string | No | Transport type (`streamablehttp`, others auto-detected) |
|
|
112
|
-
| `token` | string | No | Auth token for Bearer authentication |
|
|
113
|
-
| `enabled` | boolean | No | Enable/disable server (default: `true`) |
|
|
114
|
-
|
|
115
|
-
### Transport Examples
|
|
116
|
-
|
|
117
|
-
**Stdio (Local MCP Server)**
|
|
118
61
|
```json
|
|
119
62
|
{
|
|
120
|
-
"
|
|
121
|
-
|
|
63
|
+
"tools": {
|
|
64
|
+
"sandbox": {
|
|
65
|
+
"tools": {
|
|
66
|
+
"allow": ["group:runtime", "group:fs", "mcp-adapter"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
122
70
|
}
|
|
123
71
|
```
|
|
124
72
|
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
{
|
|
128
|
-
"id": "my-server",
|
|
129
|
-
"url": "http://localhost:3000/sse"
|
|
130
|
-
}
|
|
131
|
-
```
|
|
73
|
+
### 3. Restart the gateway
|
|
132
74
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
"id": "my-http-server",
|
|
137
|
-
"url": "https://api.example.com/mcp",
|
|
138
|
-
"type": "streamablehttp",
|
|
139
|
-
"token": "your-bearer-token"
|
|
140
|
-
}
|
|
75
|
+
```bash
|
|
76
|
+
openclaw gateway restart
|
|
141
77
|
```
|
|
142
78
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
### CLI Commands
|
|
79
|
+
### 4. Verify
|
|
146
80
|
|
|
147
81
|
```bash
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
# Check server status
|
|
152
|
-
openclaw mcp --status
|
|
82
|
+
openclaw plugins list
|
|
83
|
+
# Should show: MCP Adapter | mcp-adapter | loaded
|
|
153
84
|
```
|
|
154
85
|
|
|
155
|
-
|
|
86
|
+
## Server Configuration
|
|
156
87
|
|
|
157
|
-
|
|
88
|
+
### Stdio transport (spawns a subprocess)
|
|
158
89
|
|
|
159
|
-
```
|
|
160
|
-
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"name": "filesystem",
|
|
93
|
+
"transport": "stdio",
|
|
94
|
+
"command": "npx",
|
|
95
|
+
"args": ["-y", "@anthropic/mcp-filesystem", "/path/to/dir"],
|
|
96
|
+
"env": {
|
|
97
|
+
"SOME_VAR": "value"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
161
100
|
```
|
|
162
101
|
|
|
163
|
-
|
|
164
|
-
- `filesystem` server with `read_file` tool → `mcp_filesystem_read_file`
|
|
165
|
-
- `git` server with `clone` tool → `mcp_git_clone`
|
|
102
|
+
### HTTP transport (connects to a running server)
|
|
166
103
|
|
|
167
|
-
Tool names are sanitized (lowercased, special characters replaced with underscores).
|
|
168
|
-
|
|
169
|
-
### Gateway RPC
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
# Get MCP server status via RPC
|
|
173
|
-
openclaw gateway rpc mcp.status
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Returns:
|
|
177
104
|
```json
|
|
178
105
|
{
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"url": "npx -y @modelcontextprotocol/server-filesystem /tmp",
|
|
186
|
-
"connected": true
|
|
187
|
-
}
|
|
188
|
-
]
|
|
106
|
+
"name": "api",
|
|
107
|
+
"transport": "http",
|
|
108
|
+
"url": "http://localhost:3000/mcp",
|
|
109
|
+
"headers": {
|
|
110
|
+
"Authorization": "Bearer ${API_TOKEN}"
|
|
111
|
+
}
|
|
189
112
|
}
|
|
190
113
|
```
|
|
191
114
|
|
|
192
|
-
##
|
|
115
|
+
## Config Options
|
|
193
116
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
117
|
+
| Option | Type | Default | Description |
|
|
118
|
+
|--------|------|---------|-------------|
|
|
119
|
+
| `servers` | array | `[]` | List of MCP servers to connect to |
|
|
120
|
+
| `toolPrefix` | boolean | `true` | Prefix tool names with server name (e.g., `myserver_toolname`) |
|
|
197
121
|
|
|
198
|
-
|
|
199
|
-
npm run build
|
|
122
|
+
### Server Options
|
|
200
123
|
|
|
201
|
-
|
|
202
|
-
|
|
124
|
+
| Option | Type | Required | Description |
|
|
125
|
+
|--------|------|----------|-------------|
|
|
126
|
+
| `name` | string | Yes | Unique name for this server |
|
|
127
|
+
| `transport` | `"stdio"` \| `"http"` | No | Connection type (default: `stdio`) |
|
|
128
|
+
| `command` | string | stdio only | Command to spawn |
|
|
129
|
+
| `args` | string[] | No | Command arguments |
|
|
130
|
+
| `env` | object | No | Environment variables |
|
|
131
|
+
| `url` | string | http only | Server URL |
|
|
132
|
+
| `headers` | object | No | HTTP request headers |
|
|
203
133
|
|
|
204
|
-
|
|
205
|
-
npm pack
|
|
206
|
-
```
|
|
134
|
+
## Environment Variable Interpolation
|
|
207
135
|
|
|
208
|
-
|
|
136
|
+
Use `${VAR_NAME}` in `env` and `headers` values to reference environment variables from `~/.openclaw/.env`:
|
|
209
137
|
|
|
210
|
-
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"env": {
|
|
141
|
+
"API_KEY": "${MY_SERVICE_API_KEY}"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
211
145
|
|
|
212
|
-
|
|
213
|
-
- `@modelcontextprotocol/server-git` - Git operations
|
|
214
|
-
- `@modelcontextprotocol/server-brave-search` - Brave search integration
|
|
215
|
-
- `@modelcontextprotocol/server-postgres` - PostgreSQL database access
|
|
216
|
-
- Custom MCP servers
|
|
146
|
+
## How It Works
|
|
217
147
|
|
|
218
|
-
|
|
148
|
+
1. On gateway startup, the plugin connects to each configured MCP server
|
|
149
|
+
2. Calls `listTools()` to discover available tools
|
|
150
|
+
3. Registers each tool with OpenClaw using its name, description, and JSON Schema
|
|
151
|
+
4. When an agent invokes a tool, the plugin proxies the call to the MCP server
|
|
152
|
+
5. If the connection dies, it automatically reconnects on the next tool call
|
|
219
153
|
|
|
220
|
-
|
|
154
|
+
## Example: AgentMail
|
|
221
155
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"name": "agentmail",
|
|
159
|
+
"transport": "stdio",
|
|
160
|
+
"command": "npx",
|
|
161
|
+
"args": ["-y", "agentmail-mcp"],
|
|
162
|
+
"env": {
|
|
163
|
+
"AGENTMAIL_API_KEY": "${AGENTMAIL_API_KEY}"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This registers tools like `agentmail_create_inbox`, `agentmail_send_email`, etc.
|
|
225
169
|
|
|
226
170
|
## License
|
|
227
171
|
|
|
228
172
|
MIT
|
|
229
|
-
|
|
230
|
-
## Links
|
|
231
|
-
|
|
232
|
-
- [Repository](https://github.com/y-shi23/OmniClawPlugin)
|
|
233
|
-
- [Issues](https://github.com/y-shi23/OmniClawPlugin/issues)
|
|
234
|
-
- [MCP Specification](https://modelcontextprotocol.io/)
|
package/config.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface ServerConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
transport: "stdio" | "http";
|
|
4
|
+
command?: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
url?: string;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface McpAdapterConfig {
|
|
12
|
+
servers: ServerConfig[];
|
|
13
|
+
toolPrefix: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function interpolateEnv(obj: Record<string, string>): Record<string, string> {
|
|
17
|
+
const result: Record<string, string> = {};
|
|
18
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
19
|
+
result[k] = v.replace(/\$\{([^}]+)\}/g, (_, name) => process.env[name] ?? "");
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function parseConfig(raw: unknown): McpAdapterConfig {
|
|
25
|
+
const cfg = (raw ?? {}) as Record<string, unknown>;
|
|
26
|
+
const servers: ServerConfig[] = [];
|
|
27
|
+
|
|
28
|
+
for (const s of (cfg.servers as unknown[]) ?? []) {
|
|
29
|
+
const srv = s as Record<string, unknown>;
|
|
30
|
+
if (!srv.name) throw new Error("Server missing 'name'");
|
|
31
|
+
|
|
32
|
+
const transport = (srv.transport as string) ?? "stdio";
|
|
33
|
+
if (transport === "stdio" && !srv.command) throw new Error(`Server "${srv.name}" missing 'command'`);
|
|
34
|
+
if (transport === "http" && !srv.url) throw new Error(`Server "${srv.name}" missing 'url'`);
|
|
35
|
+
|
|
36
|
+
servers.push({
|
|
37
|
+
name: srv.name as string,
|
|
38
|
+
transport: transport as "stdio" | "http",
|
|
39
|
+
command: srv.command as string | undefined,
|
|
40
|
+
args: srv.args as string[] | undefined,
|
|
41
|
+
env: srv.env ? interpolateEnv(srv.env as Record<string, string>) : undefined,
|
|
42
|
+
url: srv.url as string | undefined,
|
|
43
|
+
headers: srv.headers ? interpolateEnv(srv.headers as Record<string, string>) : undefined,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
servers,
|
|
49
|
+
toolPrefix: cfg.toolPrefix !== false,
|
|
50
|
+
};
|
|
51
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { parseConfig } from "./config.js";
|
|
2
|
+
import { McpClientPool } from "./mcp-client.js";
|
|
3
|
+
|
|
4
|
+
export default async function (api: any) {
|
|
5
|
+
const config = parseConfig(api.pluginConfig);
|
|
6
|
+
|
|
7
|
+
if (config.servers.length === 0) {
|
|
8
|
+
console.log("[mcp-adapter] No servers configured");
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const pool = new McpClientPool();
|
|
13
|
+
|
|
14
|
+
for (const server of config.servers) {
|
|
15
|
+
try {
|
|
16
|
+
console.log(`[mcp-adapter] Connecting to ${server.name}...`);
|
|
17
|
+
await pool.connect(server);
|
|
18
|
+
|
|
19
|
+
const tools = await pool.listTools(server.name);
|
|
20
|
+
console.log(`[mcp-adapter] ${server.name}: found ${tools.length} tools`);
|
|
21
|
+
|
|
22
|
+
for (const tool of tools) {
|
|
23
|
+
const toolName = config.toolPrefix ? `${server.name}_${tool.name}` : tool.name;
|
|
24
|
+
|
|
25
|
+
api.registerTool({
|
|
26
|
+
name: toolName,
|
|
27
|
+
description: tool.description ?? `Tool from ${server.name}`,
|
|
28
|
+
parameters: tool.inputSchema ?? { type: "object", properties: {} },
|
|
29
|
+
async execute(_id: string, params: unknown) {
|
|
30
|
+
const result = await pool.callTool(server.name, tool.name, params);
|
|
31
|
+
const text = result.content
|
|
32
|
+
?.map((c: any) => c.text ?? c.data ?? "")
|
|
33
|
+
.join("\n") ?? "";
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text }],
|
|
36
|
+
isError: result.isError,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log(`[mcp-adapter] Registered: ${toolName}`);
|
|
42
|
+
}
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error(`[mcp-adapter] Failed to connect to ${server.name}:`, err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
package/mcp-client.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
+
import type { ServerConfig } from "./config.js";
|
|
5
|
+
|
|
6
|
+
interface ClientEntry {
|
|
7
|
+
config: ServerConfig;
|
|
8
|
+
client: Client;
|
|
9
|
+
transport: StdioClientTransport | StreamableHTTPClientTransport;
|
|
10
|
+
connected: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class McpClientPool {
|
|
14
|
+
private clients = new Map<string, ClientEntry>();
|
|
15
|
+
|
|
16
|
+
async connect(config: ServerConfig): Promise<Client> {
|
|
17
|
+
const client = new Client({ name: "openclaw-mcp-adapter", version: "0.1.0" });
|
|
18
|
+
const transport = this.createTransport(config);
|
|
19
|
+
|
|
20
|
+
await client.connect(transport);
|
|
21
|
+
|
|
22
|
+
// Watch for stdio process exit
|
|
23
|
+
if (transport instanceof StdioClientTransport) {
|
|
24
|
+
transport.onerror = () => this.markDisconnected(config.name);
|
|
25
|
+
transport.onclose = () => this.markDisconnected(config.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.clients.set(config.name, { config, client, transport, connected: true });
|
|
29
|
+
return client;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private createTransport(config: ServerConfig) {
|
|
33
|
+
if (config.transport === "http") {
|
|
34
|
+
return new StreamableHTTPClientTransport(new URL(config.url!), {
|
|
35
|
+
requestInit: { headers: config.headers },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return new StdioClientTransport({
|
|
39
|
+
command: config.command!,
|
|
40
|
+
args: config.args,
|
|
41
|
+
env: { ...process.env, ...config.env },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async listTools(serverName: string) {
|
|
46
|
+
const entry = this.clients.get(serverName);
|
|
47
|
+
if (!entry) throw new Error(`Unknown server: ${serverName}`);
|
|
48
|
+
const result = await entry.client.listTools();
|
|
49
|
+
return result.tools;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async callTool(serverName: string, toolName: string, args: unknown) {
|
|
53
|
+
const entry = this.clients.get(serverName);
|
|
54
|
+
if (!entry) throw new Error(`Unknown server: ${serverName}`);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
return await entry.client.callTool({ name: toolName, arguments: args as Record<string, unknown> });
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (!entry.connected || this.isConnectionError(err)) {
|
|
60
|
+
await this.reconnect(serverName);
|
|
61
|
+
const newEntry = this.clients.get(serverName)!;
|
|
62
|
+
return await newEntry.client.callTool({ name: toolName, arguments: args as Record<string, unknown> });
|
|
63
|
+
}
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private async reconnect(serverName: string) {
|
|
69
|
+
const entry = this.clients.get(serverName);
|
|
70
|
+
if (!entry) return;
|
|
71
|
+
|
|
72
|
+
try { await entry.transport.close?.(); } catch {}
|
|
73
|
+
await this.connect(entry.config);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private markDisconnected(serverName: string) {
|
|
77
|
+
const entry = this.clients.get(serverName);
|
|
78
|
+
if (entry) entry.connected = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private isConnectionError(err: unknown): boolean {
|
|
82
|
+
const msg = String(err);
|
|
83
|
+
return msg.includes("closed") || msg.includes("ECONNREFUSED") || msg.includes("EPIPE");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getStatus(serverName: string) {
|
|
87
|
+
const entry = this.clients.get(serverName);
|
|
88
|
+
return { connected: entry?.connected ?? false };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openclaw-mcp-adapter",
|
|
3
|
+
"name": "MCP Adapter",
|
|
4
|
+
"description": "Exposes MCP server tools as native OpenClaw agent tools",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"servers": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"description": "List of MCP servers to connect to",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["name"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"name": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Unique name for this server (used as tool prefix)"
|
|
19
|
+
},
|
|
20
|
+
"transport": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"enum": ["stdio", "http"],
|
|
23
|
+
"default": "stdio",
|
|
24
|
+
"description": "Connection type"
|
|
25
|
+
},
|
|
26
|
+
"command": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "For stdio: command to spawn"
|
|
29
|
+
},
|
|
30
|
+
"args": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": { "type": "string" },
|
|
33
|
+
"description": "For stdio: command arguments"
|
|
34
|
+
},
|
|
35
|
+
"env": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"additionalProperties": { "type": "string" },
|
|
38
|
+
"description": "Environment variables (supports ${VAR} interpolation)"
|
|
39
|
+
},
|
|
40
|
+
"url": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "For http: server URL"
|
|
43
|
+
},
|
|
44
|
+
"headers": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": { "type": "string" },
|
|
47
|
+
"description": "For http: request headers (supports ${VAR} interpolation)"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"toolPrefix": {
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"default": true,
|
|
55
|
+
"description": "Prefix tool names with server name"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"uiHints": {
|
|
60
|
+
"servers": {
|
|
61
|
+
"label": "MCP Servers",
|
|
62
|
+
"description": "Configure MCP servers to connect to. Each server will expose its tools as OpenClaw agent tools.",
|
|
63
|
+
"arrayItemLabel": "Server",
|
|
64
|
+
"itemUiHints": {
|
|
65
|
+
"name": {
|
|
66
|
+
"label": "Server Name",
|
|
67
|
+
"placeholder": "e.g., android-vlm, filesystem",
|
|
68
|
+
"description": "A unique identifier for this server. This name will be used as a prefix for all tools from this server."
|
|
69
|
+
},
|
|
70
|
+
"transport": {
|
|
71
|
+
"label": "Transport Type",
|
|
72
|
+
"description": "How to connect to this MCP server",
|
|
73
|
+
"options": [
|
|
74
|
+
{
|
|
75
|
+
"value": "stdio",
|
|
76
|
+
"label": "Standard I/O",
|
|
77
|
+
"hint": "Spawn a child process and communicate via stdin/stdout"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"value": "http",
|
|
81
|
+
"label": "HTTP",
|
|
82
|
+
"hint": "Connect to an HTTP endpoint that exposes MCP protocol"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"command": {
|
|
87
|
+
"label": "Command",
|
|
88
|
+
"placeholder": "npx",
|
|
89
|
+
"description": "The command to spawn (for stdio transport)",
|
|
90
|
+
"dependsOn": { "transport": "stdio" }
|
|
91
|
+
},
|
|
92
|
+
"args": {
|
|
93
|
+
"label": "Arguments",
|
|
94
|
+
"description": "Command arguments (for stdio transport)",
|
|
95
|
+
"dependsOn": { "transport": "stdio" }
|
|
96
|
+
},
|
|
97
|
+
"env": {
|
|
98
|
+
"label": "Environment Variables",
|
|
99
|
+
"description": "Key-value pairs of environment variables to pass to the command (for stdio transport)",
|
|
100
|
+
"dependsOn": { "transport": "stdio" }
|
|
101
|
+
},
|
|
102
|
+
"url": {
|
|
103
|
+
"label": "Server URL",
|
|
104
|
+
"placeholder": "http://localhost:3000/mcp",
|
|
105
|
+
"description": "The MCP server endpoint URL (for http transport)",
|
|
106
|
+
"dependsOn": { "transport": "http" }
|
|
107
|
+
},
|
|
108
|
+
"headers": {
|
|
109
|
+
"label": "Request Headers",
|
|
110
|
+
"description": "HTTP headers to include in requests (for http transport). Common headers: Authorization, Content-Type",
|
|
111
|
+
"dependsOn": { "transport": "http" },
|
|
112
|
+
"objectKeyLabel": "Header Name",
|
|
113
|
+
"objectValueLabel": "Header Value",
|
|
114
|
+
"objectValuePlaceholder": "Value"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"toolPrefix": {
|
|
119
|
+
"label": "Prefix Tool Names",
|
|
120
|
+
"description": "If enabled, tool names will include the server name as a prefix (e.g., 'android-vlm_task' instead of 'task'). Recommended to avoid conflicts."
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
package/package.json
CHANGED
|
@@ -1,46 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xiaowan",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "OpenClaw plugin for MCP (Model Context Protocol) server integration",
|
|
3
|
+
"version": "0.1.1",
|
|
5
4
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"README.md",
|
|
11
|
-
"LICENSE"
|
|
12
|
-
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsc",
|
|
15
|
-
"dev": "tsc --watch",
|
|
16
|
-
"prepack": "npm run build"
|
|
17
|
-
},
|
|
5
|
+
"description": "OpenClaw plugin that exposes MCP server tools as native agent tools",
|
|
6
|
+
"keywords": ["openclaw", "openclaw-plugin", "mcp", "model-context-protocol"],
|
|
7
|
+
"author": "y-shi23",
|
|
8
|
+
"license": "MIT",
|
|
18
9
|
"openclaw": {
|
|
19
|
-
"extensions": ["./
|
|
20
|
-
},
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
10
|
+
"extensions": ["./index.ts"]
|
|
23
11
|
},
|
|
24
|
-
"
|
|
25
|
-
"@types/node": "^20.0.0",
|
|
26
|
-
"openclaw": "latest",
|
|
27
|
-
"typescript": "^5.0.0"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"openclaw",
|
|
31
|
-
"plugin",
|
|
32
|
-
"mcp",
|
|
33
|
-
"model-context-protocol",
|
|
34
|
-
"mcp-server"
|
|
35
|
-
],
|
|
36
|
-
"author": "y-shi23 <https://github.com/y-shi23>",
|
|
37
|
-
"license": "MIT",
|
|
12
|
+
"files": ["index.ts", "mcp-client.ts", "config.ts", "openclaw.plugin.json", "README.md"],
|
|
38
13
|
"repository": {
|
|
39
14
|
"type": "git",
|
|
40
|
-
"url": "
|
|
15
|
+
"url": "https://github.com/y-shi23/OmniClawPlugin"
|
|
41
16
|
},
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
17
|
+
"engines": { "node": ">=18" },
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
45
20
|
}
|
|
46
21
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { McpPlugin } from "./mcp-plugin.js";
|
|
2
|
-
/**
|
|
3
|
-
* MCP Server Plugin for OpenClaw
|
|
4
|
-
*
|
|
5
|
-
* This plugin integrates MCP (Model Context Protocol) servers as OpenClaw agent tools.
|
|
6
|
-
* It allows OpenClaw agents to call MCP tools as if they were native tools.
|
|
7
|
-
*/
|
|
8
|
-
export default function register(api: any): void;
|
|
9
|
-
export { McpPlugin };
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAGxC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { McpPlugin } from "./mcp-plugin.js";
|
|
2
|
-
/**
|
|
3
|
-
* MCP Server Plugin for OpenClaw
|
|
4
|
-
*
|
|
5
|
-
* This plugin integrates MCP (Model Context Protocol) servers as OpenClaw agent tools.
|
|
6
|
-
* It allows OpenClaw agents to call MCP tools as if they were native tools.
|
|
7
|
-
*/
|
|
8
|
-
export default function register(api) {
|
|
9
|
-
const plugin = new McpPlugin(api);
|
|
10
|
-
plugin.register();
|
|
11
|
-
}
|
|
12
|
-
export { McpPlugin };
|
|
13
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAQ;IACvC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,CAAC,QAAQ,EAAE,CAAC;AACpB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/mcp-client.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
/**
|
|
3
|
-
* MCP Client Manager
|
|
4
|
-
*
|
|
5
|
-
* Manages connections to multiple MCP servers
|
|
6
|
-
*/
|
|
7
|
-
export declare class McpClientManager {
|
|
8
|
-
private api;
|
|
9
|
-
private clients;
|
|
10
|
-
private transports;
|
|
11
|
-
constructor(api: any);
|
|
12
|
-
/**
|
|
13
|
-
* Connect to an MCP server
|
|
14
|
-
*/
|
|
15
|
-
connect(serverConfig: any): Promise<Client>;
|
|
16
|
-
/**
|
|
17
|
-
* Disconnect from an MCP server
|
|
18
|
-
*/
|
|
19
|
-
disconnect(serverId: string): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* Check if a server is connected
|
|
22
|
-
*/
|
|
23
|
-
isConnected(serverId: string): Promise<boolean>;
|
|
24
|
-
/**
|
|
25
|
-
* Get a client by server ID
|
|
26
|
-
*/
|
|
27
|
-
getClient(serverId: string): Client | undefined;
|
|
28
|
-
/**
|
|
29
|
-
* Disconnect all servers
|
|
30
|
-
*/
|
|
31
|
-
disconnectAll(): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* Create WebSocket transport (custom implementation)
|
|
34
|
-
* Note: This is a placeholder - actual WebSocket transport implementation may vary
|
|
35
|
-
*/
|
|
36
|
-
private createWebSocketTransport;
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=mcp-client.d.ts.map
|
package/dist/mcp-client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE;;;;GAIG;AACH,qBAAa,gBAAgB;IAIf,OAAO,CAAC,GAAG;IAHvB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA+B;gBAE7B,GAAG,EAAE,GAAG;IAE5B;;OAEG;IACG,OAAO,CAAC,YAAY,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IA+DjD;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjD;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAarD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI/C;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpC;;;OAGG;YACW,wBAAwB;CAMvC"}
|
package/dist/mcp-client.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
-
/**
|
|
6
|
-
* MCP Client Manager
|
|
7
|
-
*
|
|
8
|
-
* Manages connections to multiple MCP servers
|
|
9
|
-
*/
|
|
10
|
-
export class McpClientManager {
|
|
11
|
-
api;
|
|
12
|
-
clients = new Map();
|
|
13
|
-
transports = new Map();
|
|
14
|
-
constructor(api) {
|
|
15
|
-
this.api = api;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Connect to an MCP server
|
|
19
|
-
*/
|
|
20
|
-
async connect(serverConfig) {
|
|
21
|
-
const { id, url, token, type } = serverConfig;
|
|
22
|
-
// Check if already connected
|
|
23
|
-
if (this.clients.has(id)) {
|
|
24
|
-
const existingClient = this.clients.get(id);
|
|
25
|
-
if (await this.isConnected(id)) {
|
|
26
|
-
return existingClient;
|
|
27
|
-
}
|
|
28
|
-
// Clean up disconnected client
|
|
29
|
-
await this.disconnect(id);
|
|
30
|
-
}
|
|
31
|
-
// Create new client
|
|
32
|
-
const client = new Client({
|
|
33
|
-
name: `openclaw-mcp-${id}`,
|
|
34
|
-
version: "1.0.0",
|
|
35
|
-
}, {
|
|
36
|
-
capabilities: {},
|
|
37
|
-
});
|
|
38
|
-
// Create transport based on URL scheme or type
|
|
39
|
-
let transport;
|
|
40
|
-
if (type === "streamablehttp") {
|
|
41
|
-
// Streamable HTTP transport with Bearer auth
|
|
42
|
-
transport = new StreamableHTTPClientTransport(new URL(url), {
|
|
43
|
-
requestInit: {
|
|
44
|
-
headers: {
|
|
45
|
-
"Authorization": `Bearer ${token}`,
|
|
46
|
-
"Content-Type": "application/json"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
else if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
52
|
-
// SSE transport
|
|
53
|
-
transport = new SSEClientTransport(new URL(url));
|
|
54
|
-
}
|
|
55
|
-
else if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
|
56
|
-
// WebSocket transport (requires custom implementation)
|
|
57
|
-
transport = await this.createWebSocketTransport(url, token);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Assume stdio transport for local executables
|
|
61
|
-
transport = new StdioClientTransport({
|
|
62
|
-
command: url,
|
|
63
|
-
args: token ? ["--token", token] : [],
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
this.transports.set(id, transport);
|
|
67
|
-
// Connect
|
|
68
|
-
await client.connect(transport);
|
|
69
|
-
this.clients.set(id, client);
|
|
70
|
-
this.api.logger.info(`Connected to MCP server: ${id}`);
|
|
71
|
-
return client;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Disconnect from an MCP server
|
|
75
|
-
*/
|
|
76
|
-
async disconnect(serverId) {
|
|
77
|
-
const client = this.clients.get(serverId);
|
|
78
|
-
if (client) {
|
|
79
|
-
try {
|
|
80
|
-
await client.close();
|
|
81
|
-
}
|
|
82
|
-
catch (e) {
|
|
83
|
-
this.api.logger.warn(`Error closing MCP client ${serverId}:`, e);
|
|
84
|
-
}
|
|
85
|
-
this.clients.delete(serverId);
|
|
86
|
-
}
|
|
87
|
-
const transport = this.transports.get(serverId);
|
|
88
|
-
if (transport) {
|
|
89
|
-
try {
|
|
90
|
-
await transport.close();
|
|
91
|
-
}
|
|
92
|
-
catch (e) {
|
|
93
|
-
this.api.logger.warn(`Error closing MCP transport ${serverId}:`, e);
|
|
94
|
-
}
|
|
95
|
-
this.transports.delete(serverId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Check if a server is connected
|
|
100
|
-
*/
|
|
101
|
-
async isConnected(serverId) {
|
|
102
|
-
const client = this.clients.get(serverId);
|
|
103
|
-
if (!client)
|
|
104
|
-
return false;
|
|
105
|
-
try {
|
|
106
|
-
// Try to ping the server
|
|
107
|
-
const response = await client.ping();
|
|
108
|
-
return !!response;
|
|
109
|
-
}
|
|
110
|
-
catch (e) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Get a client by server ID
|
|
116
|
-
*/
|
|
117
|
-
getClient(serverId) {
|
|
118
|
-
return this.clients.get(serverId);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Disconnect all servers
|
|
122
|
-
*/
|
|
123
|
-
async disconnectAll() {
|
|
124
|
-
const serverIds = Array.from(this.clients.keys());
|
|
125
|
-
await Promise.all(serverIds.map((id) => this.disconnect(id)));
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Create WebSocket transport (custom implementation)
|
|
129
|
-
* Note: This is a placeholder - actual WebSocket transport implementation may vary
|
|
130
|
-
*/
|
|
131
|
-
async createWebSocketTransport(url, token) {
|
|
132
|
-
// TODO: Implement WebSocket transport
|
|
133
|
-
// The MCP SDK may not have built-in WebSocket support yet
|
|
134
|
-
// This would require a custom transport implementation
|
|
135
|
-
throw new Error("WebSocket transport not yet implemented. Use SSE or stdio.");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
//# sourceMappingURL=mcp-client.js.map
|
package/dist/mcp-client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-plugin.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main MCP Plugin class
|
|
3
|
-
*
|
|
4
|
-
* Manages MCP client connections and tool registration with OpenClaw
|
|
5
|
-
*/
|
|
6
|
-
export declare class McpPlugin {
|
|
7
|
-
private api;
|
|
8
|
-
private clientManager;
|
|
9
|
-
private toolRegistrar;
|
|
10
|
-
constructor(api: any);
|
|
11
|
-
register(): void;
|
|
12
|
-
private getStatus;
|
|
13
|
-
private listServers;
|
|
14
|
-
private showStatus;
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=mcp-plugin.d.ts.map
|
package/dist/mcp-plugin.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-plugin.d.ts","sourceRoot":"","sources":["../src/mcp-plugin.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,qBAAa,SAAS;IAIR,OAAO,CAAC,GAAG;IAHvB,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAgB;gBAEjB,GAAG,EAAE,GAAG;IAK5B,QAAQ;YA+BM,SAAS;YAgBT,WAAW;YAYX,UAAU;CAOzB"}
|
package/dist/mcp-plugin.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { McpClientManager } from "./mcp-client.js";
|
|
2
|
-
import { ToolRegistrar } from "./tools.js";
|
|
3
|
-
/**
|
|
4
|
-
* Main MCP Plugin class
|
|
5
|
-
*
|
|
6
|
-
* Manages MCP client connections and tool registration with OpenClaw
|
|
7
|
-
*/
|
|
8
|
-
export class McpPlugin {
|
|
9
|
-
api;
|
|
10
|
-
clientManager;
|
|
11
|
-
toolRegistrar;
|
|
12
|
-
constructor(api) {
|
|
13
|
-
this.api = api;
|
|
14
|
-
this.clientManager = new McpClientManager(api);
|
|
15
|
-
this.toolRegistrar = new ToolRegistrar(api, this.clientManager);
|
|
16
|
-
}
|
|
17
|
-
register() {
|
|
18
|
-
// Register all MCP servers as tools
|
|
19
|
-
this.toolRegistrar.registerTools();
|
|
20
|
-
// Register gateway RPC method for status
|
|
21
|
-
this.api.registerGatewayMethod("mcp.status", async ({ respond }) => {
|
|
22
|
-
const status = await this.getStatus();
|
|
23
|
-
respond(true, status);
|
|
24
|
-
});
|
|
25
|
-
// Register CLI commands
|
|
26
|
-
this.api.registerCli(({ program }) => {
|
|
27
|
-
program
|
|
28
|
-
.command("mcp")
|
|
29
|
-
.description("Manage MCP servers")
|
|
30
|
-
.option("--list", "List configured MCP servers")
|
|
31
|
-
.option("--status", "Show MCP server status")
|
|
32
|
-
.action(async (options) => {
|
|
33
|
-
if (options.list) {
|
|
34
|
-
await this.listServers();
|
|
35
|
-
}
|
|
36
|
-
else if (options.status) {
|
|
37
|
-
await this.showStatus();
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.log("Use --list or --status");
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}, { commands: ["mcp"] });
|
|
44
|
-
this.api.logger.info("MCP Server plugin registered");
|
|
45
|
-
}
|
|
46
|
-
async getStatus() {
|
|
47
|
-
const config = this.api.config.plugins?.entries?.["xiaowan"]?.config || {};
|
|
48
|
-
const servers = config.servers || [];
|
|
49
|
-
return {
|
|
50
|
-
ok: true,
|
|
51
|
-
servers: servers.map((server) => ({
|
|
52
|
-
id: server.id,
|
|
53
|
-
name: server.name || server.id,
|
|
54
|
-
enabled: server.enabled !== false,
|
|
55
|
-
url: server.url,
|
|
56
|
-
connected: this.clientManager.isConnected(server.id),
|
|
57
|
-
})),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
async listServers() {
|
|
61
|
-
const status = await this.getStatus();
|
|
62
|
-
console.log("\n=== MCP Servers ===");
|
|
63
|
-
status.servers.forEach((server) => {
|
|
64
|
-
const icon = server.enabled ? "✓" : "✗";
|
|
65
|
-
const conn = server.connected ? "connected" : "disconnected";
|
|
66
|
-
console.log(`${icon} ${server.name} (${server.id}) - ${conn}`);
|
|
67
|
-
console.log(` URL: ${server.url}`);
|
|
68
|
-
});
|
|
69
|
-
console.log();
|
|
70
|
-
}
|
|
71
|
-
async showStatus() {
|
|
72
|
-
const status = await this.getStatus();
|
|
73
|
-
console.log("\n=== MCP Status ===");
|
|
74
|
-
console.log(`Total servers: ${status.servers.length}`);
|
|
75
|
-
console.log(`Connected: ${status.servers.filter((s) => s.connected).length}`);
|
|
76
|
-
console.log();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
//# sourceMappingURL=mcp-plugin.js.map
|
package/dist/mcp-plugin.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-plugin.js","sourceRoot":"","sources":["../src/mcp-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { McpClientManager } from "./mcp-client.js";
|
|
2
|
-
/**
|
|
3
|
-
* Tool Registrar
|
|
4
|
-
*
|
|
5
|
-
* Registers MCP tools as OpenClaw agent tools
|
|
6
|
-
*/
|
|
7
|
-
export declare class ToolRegistrar {
|
|
8
|
-
private api;
|
|
9
|
-
private clientManager;
|
|
10
|
-
constructor(api: any, clientManager: McpClientManager);
|
|
11
|
-
/**
|
|
12
|
-
* Register all configured MCP servers as tools
|
|
13
|
-
*/
|
|
14
|
-
registerTools(): Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* Register tools from a single MCP server
|
|
17
|
-
*/
|
|
18
|
-
private registerServerTools;
|
|
19
|
-
/**
|
|
20
|
-
* Register a single MCP tool as an OpenClaw tool
|
|
21
|
-
*/
|
|
22
|
-
private registerMcpTool;
|
|
23
|
-
/**
|
|
24
|
-
* Sanitize tool name to be valid identifier
|
|
25
|
-
*/
|
|
26
|
-
private sanitizeToolName;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=tools.d.ts.map
|
package/dist/tools.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,aAAa;IAEtB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,aAAa;gBADb,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,gBAAgB;IAGzC;;OAEG;IACG,aAAa;IAiBnB;;OAEG;YACW,mBAAmB;IAajC;;OAEG;IACH,OAAO,CAAC,eAAe;IAuCvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAOzB"}
|
package/dist/tools.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool Registrar
|
|
3
|
-
*
|
|
4
|
-
* Registers MCP tools as OpenClaw agent tools
|
|
5
|
-
*/
|
|
6
|
-
export class ToolRegistrar {
|
|
7
|
-
api;
|
|
8
|
-
clientManager;
|
|
9
|
-
constructor(api, clientManager) {
|
|
10
|
-
this.api = api;
|
|
11
|
-
this.clientManager = clientManager;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Register all configured MCP servers as tools
|
|
15
|
-
*/
|
|
16
|
-
async registerTools() {
|
|
17
|
-
const config = this.api.config.plugins?.entries?.["xiaowan"]?.config || {};
|
|
18
|
-
const servers = config.servers || [];
|
|
19
|
-
for (const server of servers) {
|
|
20
|
-
if (server.enabled === false) {
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
await this.registerServerTools(server);
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
this.api.logger.error(`Failed to register tools for MCP server ${server.id}:`, e);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Register tools from a single MCP server
|
|
33
|
-
*/
|
|
34
|
-
async registerServerTools(server) {
|
|
35
|
-
const client = await this.clientManager.connect(server);
|
|
36
|
-
// List available tools from the MCP server
|
|
37
|
-
const toolsResponse = await client.listTools();
|
|
38
|
-
for (const mcpTool of toolsResponse.tools) {
|
|
39
|
-
this.registerMcpTool(server, client, mcpTool);
|
|
40
|
-
}
|
|
41
|
-
this.api.logger.info(`Registered ${toolsResponse.tools.length} tools from MCP server: ${server.id}`);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Register a single MCP tool as an OpenClaw tool
|
|
45
|
-
*/
|
|
46
|
-
registerMcpTool(server, client, mcpTool) {
|
|
47
|
-
const toolId = `mcp_${server.id}_${mcpTool.name}`;
|
|
48
|
-
const toolName = this.sanitizeToolName(mcpTool.name);
|
|
49
|
-
const tool = {
|
|
50
|
-
name: toolName,
|
|
51
|
-
description: mcpTool.description || `MCP tool: ${mcpTool.name} from ${server.name || server.id}`,
|
|
52
|
-
inputSchema: mcpTool.inputSchema,
|
|
53
|
-
handler: async (params) => {
|
|
54
|
-
try {
|
|
55
|
-
// Ensure client is connected
|
|
56
|
-
if (!(await this.clientManager.isConnected(server.id))) {
|
|
57
|
-
await this.clientManager.connect(server);
|
|
58
|
-
}
|
|
59
|
-
// Call the MCP tool
|
|
60
|
-
const response = await client.callTool({
|
|
61
|
-
name: mcpTool.name,
|
|
62
|
-
arguments: params,
|
|
63
|
-
});
|
|
64
|
-
// Format the response for OpenClaw
|
|
65
|
-
return {
|
|
66
|
-
content: response.content,
|
|
67
|
-
isError: response.isError,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
catch (e) {
|
|
71
|
-
this.api.logger.error(`Error calling MCP tool ${toolName}:`, e);
|
|
72
|
-
throw e;
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
// Register the tool with OpenClaw
|
|
77
|
-
this.api.registerTool(tool);
|
|
78
|
-
this.api.logger.debug(`Registered tool: ${toolName}`);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Sanitize tool name to be valid identifier
|
|
82
|
-
*/
|
|
83
|
-
sanitizeToolName(name) {
|
|
84
|
-
return name
|
|
85
|
-
.toLowerCase()
|
|
86
|
-
.replace(/[^a-z0-9_]/g, "_")
|
|
87
|
-
.replace(/_{2,}/g, "_")
|
|
88
|
-
.replace(/^_|_$/g, "");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=tools.js.map
|
package/dist/tools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,aAAa;IAEd;IACA;IAFV,YACU,GAAQ,EACR,aAA+B;QAD/B,QAAG,GAAH,GAAG,CAAK;QACR,kBAAa,GAAb,aAAa,CAAkB;IACtC,CAAC;IAEJ;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;QAC3E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;QAErC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;gBAC7B,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,mBAAmB,CAAC,MAAW;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,2CAA2C;QAC3C,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QAE/C,KAAK,MAAM,OAAO,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC;YAC1C,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,aAAa,CAAC,KAAK,CAAC,MAAM,2BAA2B,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACvG,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,MAAW,EAAE,MAAW,EAAE,OAAY;QAC5D,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAErD,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,aAAa,OAAO,CAAC,IAAI,SAAS,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,EAAE;YAChG,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,OAAO,EAAE,KAAK,EAAE,MAAW,EAAE,EAAE;gBAC7B,IAAI,CAAC;oBACH,6BAA6B;oBAC7B,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;wBACvD,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBAC3C,CAAC;oBAED,oBAAoB;oBACpB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;wBACrC,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,SAAS,EAAE,MAAM;qBAClB,CAAC,CAAC;oBAEH,mCAAmC;oBACnC,OAAO;wBACL,OAAO,EAAE,QAAQ,CAAC,OAAO;wBACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;qBAC1B,CAAC;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC;oBAChE,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;SACF,CAAC;QAEF,kCAAkC;QAClC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,IAAY;QACnC,OAAO,IAAI;aACR,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;aACtB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC3B,CAAC;CACF"}
|