xiaowan 0.1.0
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 +234 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-client.d.ts +38 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +138 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp-plugin.d.ts +16 -0
- package/dist/mcp-plugin.d.ts.map +1 -0
- package/dist/mcp-plugin.js +79 -0
- package/dist/mcp-plugin.js.map +1 -0
- package/dist/tools.d.ts +28 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +91 -0
- package/dist/tools.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ocean
|
|
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
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Claw Xiaowan - MCP Server Plugin for OpenClaw
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin for integrating MCP (Model Context Protocol) servers as agent tools.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Connect to multiple MCP servers simultaneously
|
|
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
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### From npm
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
openclaw plugins install claw-xiaowan
|
|
23
|
+
openclaw gateway restart
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Local Development
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Clone the repository
|
|
30
|
+
git clone https://github.com/y-shi23/OmniClawPlugin.git
|
|
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
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
Add to your OpenClaw config file:
|
|
49
|
+
|
|
50
|
+
```json5
|
|
51
|
+
{
|
|
52
|
+
plugins: {
|
|
53
|
+
entries: {
|
|
54
|
+
"xiaowan": {
|
|
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
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "my-sse-server",
|
|
72
|
+
name: "My SSE Server",
|
|
73
|
+
url: "http://localhost:3000/sse",
|
|
74
|
+
enabled: true
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "my-http-server",
|
|
78
|
+
name: "My HTTP Server",
|
|
79
|
+
url: "https://api.example.com/mcp",
|
|
80
|
+
type: "streamablehttp",
|
|
81
|
+
token: "your-bearer-token",
|
|
82
|
+
enabled: true
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Server Configuration
|
|
93
|
+
|
|
94
|
+
### Transport Types
|
|
95
|
+
|
|
96
|
+
The plugin automatically detects the transport type based on the URL or explicit `type` field:
|
|
97
|
+
|
|
98
|
+
| Type | URL Pattern | Description |
|
|
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 |
|
|
103
|
+
|
|
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
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"id": "filesystem",
|
|
121
|
+
"url": "npx -y @modelcontextprotocol/server-filesystem /tmp"
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**SSE (Server-Sent Events)**
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"id": "my-server",
|
|
129
|
+
"url": "http://localhost:3000/sse"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Streamable HTTP with Bearer Auth**
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"id": "my-http-server",
|
|
137
|
+
"url": "https://api.example.com/mcp",
|
|
138
|
+
"type": "streamablehttp",
|
|
139
|
+
"token": "your-bearer-token"
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
### CLI Commands
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# List configured MCP servers
|
|
149
|
+
openclaw mcp --list
|
|
150
|
+
|
|
151
|
+
# Check server status
|
|
152
|
+
openclaw mcp --status
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Agent Tools
|
|
156
|
+
|
|
157
|
+
Once configured, MCP tools are available to OpenClaw agents. Tools are automatically named using the pattern:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
mcp_<server-id>_<tool-name>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For example:
|
|
164
|
+
- `filesystem` server with `read_file` tool → `mcp_filesystem_read_file`
|
|
165
|
+
- `git` server with `clone` tool → `mcp_git_clone`
|
|
166
|
+
|
|
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
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"ok": true,
|
|
180
|
+
"servers": [
|
|
181
|
+
{
|
|
182
|
+
"id": "filesystem",
|
|
183
|
+
"name": "Filesystem Tools",
|
|
184
|
+
"enabled": true,
|
|
185
|
+
"url": "npx -y @modelcontextprotocol/server-filesystem /tmp",
|
|
186
|
+
"connected": true
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Install dependencies
|
|
196
|
+
npm install
|
|
197
|
+
|
|
198
|
+
# Build the plugin
|
|
199
|
+
npm run build
|
|
200
|
+
|
|
201
|
+
# Watch for changes during development
|
|
202
|
+
npm run dev
|
|
203
|
+
|
|
204
|
+
# Pack for npm publishing
|
|
205
|
+
npm pack
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Supported MCP Servers
|
|
209
|
+
|
|
210
|
+
This plugin works with any MCP-compliant server. Official examples:
|
|
211
|
+
|
|
212
|
+
- `@modelcontextprotocol/server-filesystem` - Filesystem operations
|
|
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
|
|
217
|
+
|
|
218
|
+
## Architecture
|
|
219
|
+
|
|
220
|
+
The plugin consists of three main components:
|
|
221
|
+
|
|
222
|
+
1. **McpClientManager** - Manages connections to MCP servers with support for multiple transports
|
|
223
|
+
2. **ToolRegistrar** - Registers MCP tools as OpenClaw agent tools
|
|
224
|
+
3. **McpPlugin** - Main plugin class that wires everything together
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
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/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-plugin.js","sourceRoot":"","sources":["../src/mcp-plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xiaowan",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenClaw plugin for MCP (Model Context Protocol) server integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"prepack": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"openclaw": {
|
|
19
|
+
"extensions": ["./src/index.ts"]
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
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",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/y-shi23/OmniClawPlugin.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/y-shi23/OmniClawPlugin#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/y-shi23/OmniClawPlugin/issues"
|
|
45
|
+
}
|
|
46
|
+
}
|