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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Ocean
3
+ Copyright (c) 2026
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,85 +1,50 @@
1
- # Claw Xiaowan - MCP Server Plugin for OpenClaw
1
+ # MCP Adapter (OpenClaw Plugin)
2
2
 
3
- OpenClaw plugin for integrating MCP (Model Context Protocol) servers as agent tools.
3
+ Exposes MCP (Model Context Protocol) server tools as native OpenClaw agent tools.
4
4
 
5
- ## Features
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
- - 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
7
+ ## Requirements
16
8
 
17
- ## Installation
9
+ - OpenClaw gateway
10
+ - Node.js 18+
11
+ - MCP servers you want to connect to
18
12
 
19
- ### From npm
13
+ ## Installation
20
14
 
21
15
  ```bash
22
- openclaw plugins install claw-xiaowan
23
- openclaw gateway restart
16
+ openclaw plugins install mcp-adapter
24
17
  ```
25
18
 
26
- ### Local Development
19
+ **Alternative: install from source**
27
20
 
28
21
  ```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
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
- Add to your OpenClaw config file:
28
+ ### 1. Enable the plugin and configure servers
49
29
 
50
- ```json5
30
+ Add to `~/.openclaw/openclaw.json`:
31
+
32
+ ```json
51
33
  {
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
- },
34
+ "plugins": {
35
+ "entries": {
36
+ "mcp-adapter": {
37
+ "enabled": true,
38
+ "config": {
39
+ "servers": [
70
40
  {
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
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
- ## Server Configuration
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
- | 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 |
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
- "id": "filesystem",
121
- "url": "npx -y @modelcontextprotocol/server-filesystem /tmp"
63
+ "tools": {
64
+ "sandbox": {
65
+ "tools": {
66
+ "allow": ["group:runtime", "group:fs", "mcp-adapter"]
67
+ }
68
+ }
69
+ }
122
70
  }
123
71
  ```
124
72
 
125
- **SSE (Server-Sent Events)**
126
- ```json
127
- {
128
- "id": "my-server",
129
- "url": "http://localhost:3000/sse"
130
- }
131
- ```
73
+ ### 3. Restart the gateway
132
74
 
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
- }
75
+ ```bash
76
+ openclaw gateway restart
141
77
  ```
142
78
 
143
- ## Usage
144
-
145
- ### CLI Commands
79
+ ### 4. Verify
146
80
 
147
81
  ```bash
148
- # List configured MCP servers
149
- openclaw mcp --list
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
- ### Agent Tools
86
+ ## Server Configuration
156
87
 
157
- Once configured, MCP tools are available to OpenClaw agents. Tools are automatically named using the pattern:
88
+ ### Stdio transport (spawns a subprocess)
158
89
 
159
- ```
160
- mcp_<server-id>_<tool-name>
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
- For example:
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
- "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
- ]
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
- ## Development
115
+ ## Config Options
193
116
 
194
- ```bash
195
- # Install dependencies
196
- npm install
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
- # Build the plugin
199
- npm run build
122
+ ### Server Options
200
123
 
201
- # Watch for changes during development
202
- npm run dev
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
- # Pack for npm publishing
205
- npm pack
206
- ```
134
+ ## Environment Variable Interpolation
207
135
 
208
- ## Supported MCP Servers
136
+ Use `${VAR_NAME}` in `env` and `headers` values to reference environment variables from `~/.openclaw/.env`:
209
137
 
210
- This plugin works with any MCP-compliant server. Official examples:
138
+ ```json
139
+ {
140
+ "env": {
141
+ "API_KEY": "${MY_SERVICE_API_KEY}"
142
+ }
143
+ }
144
+ ```
211
145
 
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
146
+ ## How It Works
217
147
 
218
- ## Architecture
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
- The plugin consists of three main components:
154
+ ## Example: AgentMail
221
155
 
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
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.0",
4
- "description": "OpenClaw plugin for MCP (Model Context Protocol) server integration",
3
+ "version": "0.1.1",
5
4
  "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
- },
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": ["./src/index.ts"]
20
- },
21
- "dependencies": {
22
- "@modelcontextprotocol/sdk": "^1.0.0"
10
+ "extensions": ["./index.ts"]
23
11
  },
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",
12
+ "files": ["index.ts", "mcp-client.ts", "config.ts", "openclaw.plugin.json", "README.md"],
38
13
  "repository": {
39
14
  "type": "git",
40
- "url": "git+https://github.com/y-shi23/OmniClawPlugin.git"
15
+ "url": "https://github.com/y-shi23/OmniClawPlugin"
41
16
  },
42
- "homepage": "https://github.com/y-shi23/OmniClawPlugin#readme",
43
- "bugs": {
44
- "url": "https://github.com/y-shi23/OmniClawPlugin/issues"
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
@@ -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"}
@@ -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
@@ -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"}
@@ -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
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -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"}
@@ -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
@@ -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
@@ -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"}