Skill: lunarpulse/openclaw-mcp-plugin (version 0.1.1)

--- name: mcp-integration description: Use Model Context Protocol servers to access external tools and data sources. Enable AI agents to discover and execute tools from configured MCP servers (legal databases, APIs, database connectors, weather services, etc.). license: MIT --- # MCP Integration Usage Guide ## Overview Use the MCP integration plugin to discover and execute tools provided by external MCP servers. This skill enables you to access legal databases, query APIs, search databases, and integrate with any service that provides an MCP interface. The plugin provides a unified `mcp` tool with two actions: - `list` - Discover available tools from all connected servers - `call` - Execute a specific tool with parameters --- # Process ## 🔍 Phase 1: Tool Discovery ### 1.1 Check Available Tools **Always start by listing available tools** to see what MCP servers are connected and what capabilities they provide. **Action:** ``` { tool: "mcp", args: { action: "list" } } ``` **Response structure:** ```json [ { "id": "server:toolname", "server": "server-name", "name": "tool-name", "description": "What this tool does", "inputSchema": { "type": "object", "properties": {...}, "required": [...] } } ] ``` ### 1.2 Understand Tool Schemas For each tool, examine: - **id**: Format is `"server:toolname"` - split on `:` to get server and tool names - **description**: Understand what the tool does - **inputSchema**: JSON Schema defining parameters - `properties`: Available parameters with types and descriptions - `required`: Array of mandatory parameter names ### 1.3 Match Tools to User Requests Common tool naming patterns: - `search_*` - Find or search operations (e.g., `search_statute`, `search_users`) - `get_*` - Retrieve specific data (e.g., `get_statute_full_text`, `get_weather`) - `query` - Execute queries (e.g., `database:query`) - `analyze_*` - Analysis operations (e.g., `analyze_law`) - `resolve_*` - Resolve references (e.g., `resolve_citation`) --- ## 🎯 Phase 2: Tool Execution ### 2.1 Validate Parameters Before calling a tool: 1. Identify all required parameters from `inputSchema.required` 2. Verify parameter types match schema (string, number, boolean, array, object) 3. Check for constraints (minimum, maximum, enum values, patterns) 4. Ensure you have necessary information from the user ### 2.2 Construct Tool Call **Action:** ``` { tool: "mcp", args: { action: "call", server: "<server-name>", tool: "<tool-name>", args: { // Tool-specific parameters from inputSchema } } } ``` **Example - Korean legal search:** ``` { tool: "mcp", args: { action: "call", server: "kr-legal", tool: "search_statute", args: { query: "연장근로 수당", limit: 5 } } } ``` ### 2.3 Parse Response Tool responses follow this structure: ```json { "content": [ { "type": "text", "text": "JSON string or text result" } ], "isError": false } ``` For JSON responses: ```javascript const data = JSON.parse(response.content[0].text); // Access data.result, data.results, or direct properties ``` --- ## 🔄 Phase 3: Multi-Step Workflows ### 3.1 Chain Tool Calls For complex requests, execute multiple tools in sequence: **Example - Legal research workflow:** 1. **Search** - `search_statute` to find relevant laws 2. **Retrieve** - `get_statute_full_text` for complete text 3. **Analyze** - `analyze_law` for interpretation 4. **Precedents** - `search_case_law` for related cases Each step uses output from the previous step to inform the next call. ### 3.2 Maintain Context Between tool calls: - Extract relevant information from each response - Use extracted data as parameters for subsequent calls - Build up understanding progressively - Present synthesized results to user --- ## ⚠ Phase 4: Error Handling ### 4.1 Common Errors **"Tool not found: server:toolname"** - Cause: Server not connected or tool doesn't exist - Solution: Run `action: "list"` to verify available tools - Check spelling of server and tool names **"Invalid arguments for tool"** - Cause: Missing required parameter or wrong type - Solution: Review `inputSchema` from list response - Ensure all required parameters provided with correct types **"Server connection failed"** - Cause: MCP server not running or unreachable - Solution: Inform user service is temporarily unavailable - Suggest alternatives if possible ### 4.2 Error Response Format Errors return: ```json { "content": [{"type": "text", "text": "Error: message"}], "isError": true } ``` **Handle gracefully:** - Explain what went wrong clearly - Don't expose technical implementation details - Suggest next steps or alternatives - Don't retry excessively --- # Complete Example ## User Request: "Find Korean laws about overtime pay" ### Step 1: Discover tools ``` {tool: "mcp", args: {action: "list"}} ``` Response shows `kr-legal:search_statute` with: - Required: `query` (string) - Optional: `limit` (number), `category` (string) ### Step 2: Execute search ``` { tool: "mcp", args: { action: "call", server: "kr-legal", tool: "search_statute", args: { query: "연장근로 수당", category: "노동법", limit: 5 } } } ``` ### Step 3: Parse and present ```javascript const data = JSON.parse(response.content[0].text); // Present data.results to user ``` **User-facing response:** ``` Found 5 Korean statutes about overtime pay: 1. 근로기준법 제56조 (연장·야간 및 휴일 근로) - Overtime work requires 50% premium 2. 근로기준법 제50조 (근로시간) - Standard working hours: 40 hours per week Would you like me to retrieve the full text of any statute? ``` --- # Quick Reference ## List Tools ``` {tool: "mcp", args: {action: "list"}} ``` ## Call Tool ``` { tool: "mcp", args: { action: "call", server: "server-name", tool: "tool-name", args: {param1: "value1"} } } ``` ## Essential Patterns **Tool ID parsing:** `"server:toolname"` → split on `:` for server and tool names **Parameter validation:** Check `inputSchema.required` and `inputSchema.properties[param].type` **Response parsing:** `JSON.parse(response.content[0].text)` for JSON responses **Error detection:** Check `response.isError === true` --- # Reference Documentation ## Core Documentation - **Plugin README**: [README.md](README.md) - Installation and configuration - **Real Example**: [REAL_EXAMPLE_KR_LEGAL.md](docs/REAL_EXAMPLE_KR_LEGAL.md) - Working kr-legal setup - **API Reference**: [API.md](docs/API.md) - Technical API details - **Configuration**: [CONFIGURATION.md](docs/CONFIGURATION.md) - Server configuration guide - **Troubleshooting**: [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) - Common issues and solutions ## Usage Examples - **Examples Collection**: [EXAMPLES.md](docs/EXAMPLES.md) - 13 real-world examples including: - Legal research workflows - Database queries - Weather service integration - Multi-step complex workflows - Error handling patterns --- **Remember:** Always start with `action: "list"` when uncertain about available tools.

path: README.md
content: # OpenClaw MCP Integration Plugin

**Model Context Protocol (MCP) integration for OpenClaw** - Connect to MCP servers and use their tools seamlessly within OpenClaw.

## 🎯 Overview

This plugin enables OpenClaw to connect to any MCP (Model Context Protocol) server and expose its tools to AI agents. It implements the MCP Streamable HTTP transport specification and provides a unified interface for calling external MCP tools.

> ✅ **Real Working Example:** See [REAL_EXAMPLE_KR_LEGAL.md](docs/REAL_EXAMPLE_KR_LEGAL.md) for a complete, tested configuration with kr-legal-search (no API key required!).

### Key Features

✅ **HTTP/SSE Transport** - Full support for MCP Streamable HTTP with Server-Sent Events  
✅ **Dynamic Tool Discovery** - Automatically discovers and registers tools from MCP servers  
✅ **Multi-Server Support** - Connect to multiple MCP servers simultaneously  
✅ **Unified Interface** - All MCP tools accessible through a single `mcp` tool  
✅ **Error Handling** - Robust error handling and logging  

## 📋 Prerequisites

- **OpenClaw**: Version 2026.1.0 or higher
- **Node.js**: 18.0.0 or higher
- **MCP Server**: Any MCP-compliant server with HTTP transport

## 🚀 Installation

### Method 1: Via OpenClaw Extensions

```bash
# Clone into OpenClaw extensions directory
cd ~/.openclaw/extensions/
git clone https://github.com/yourorg/mcp-integration.git

# Install dependencies
cd mcp-integration
npm install

# Restart OpenClaw
openclaw gateway restart
```

### Method 2: Manual Installation

```bash
# Clone repository
git clone https://github.com/yourorg/mcp-integration.git
cd mcp-integration

# Install dependencies
npm install

# Link to OpenClaw
ln -s $(pwd) ~/.openclaw/extensions/mcp-integration

# Restart OpenClaw
openclaw gateway restart
```

## ⚙️ Configuration

### Basic Configuration

Add to `~/.openclaw/openclaw.json`:

```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "enabled": true,
          "servers": {
            "example-server": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3000/mcp"
            }
          }
        }
      }
    }
  }
}
```

### Configuration Schema

```typescript
{
  enabled: boolean;              // Enable/disable plugin (default: true)
  servers: {
    [serverName: string]: {
      enabled: boolean;          // Enable/disable this server (default: true)
      transport: "http";         // Transport type (currently only http supported)
      url: string;               // Server URL (e.g., "http://localhost:3000/mcp")
    }
  }
}
```

### Multiple Servers Example

```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "enabled": true,
          "servers": {
            "kr-legal": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3000/mcp"
            },
            "database": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3001/mcp"
            },
            "weather": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3002/mcp"
            }
          }
        }
      }
    }
  }
}
```

## 🛠️ Usage

### The `mcp` Tool

Once configured, the plugin registers a single `mcp` tool that provides access to all connected MCP servers.

#### List Available Tools

**In OpenClaw chat:**
```
User: List all MCP tools

AI: I'll check what MCP tools are available.

[Uses tool: mcp with action=list]

Available MCP tools:
- kr-legal:search_statute - Search Korean statutes
- kr-legal:search_case_law - Search court decisions
- database:query - Execute database query
- weather:get_forecast - Get weather forecast
```

**Tool call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "list"
  }
}
```

**Response:**
```json
[
  {
    "id": "kr-legal:search_statute",
    "server": "kr-legal",
    "name": "search_statute",
    "description": "Search Korean statutes and regulations",
    "inputSchema": {
      "type": "object",
      "properties": {
        "query": { "type": "string" },
        "limit": { "type": "number" }
      },
      "required": ["query"]
    }
  },
  {
    "id": "database:query",
    "server": "database",
    "name": "query",
    "description": "Execute SQL query",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": { "type": "string" }
      },
      "required": ["sql"]
    }
  }
]
```

#### Call an MCP Tool

**In OpenClaw chat:**
```
User: Search for Korean labor law

AI: I'll search Korean legal statutes for labor law.

[Uses tool: mcp with action=call, server=kr-legal, tool=search_statute]

Found 15 statutes related to labor law...
```

**Tool call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute",
    "args": {
      "query": "노동법",
      "limit": 5
    }
  }
}
```

**Response:**
```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"results\":[{\"title\":\"근로기준법\",\"statute_id\":\"0065\",...}]}"
    }
  ]
}
```

## 🏗️ Architecture

### Component Diagram

```
┌─────────────────────────────────────────────┐
│           OpenClaw Core                     │
│  ┌───────────────────────────────────────┐  │
│  │  Agent (main/admin/chat)              │  │
│  └────────────────┬──────────────────────┘  │
│                   │                          │
│                   ▼                          │
│  ┌───────────────────────────────────────┐  │
│  │  Tool System                          │  │
│  │  - Calls mcp tool                     │  │
│  └────────────────┬──────────────────────┘  │
└───────────────────┼──────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────┐
│      MCP Integration Plugin                 │
│  ┌───────────────────────────────────────┐  │
│  │  MCPManager                           │  │
│  │  - Manages connections                │  │
│  │  - Routes tool calls                  │  │
│  │  - Lists available tools              │  │
│  └────────────┬──────────────────────────┘  │
│               │                             │
│  ┌────────────┴──────────────┐              │
│  │                           │              │
│  ▼                           ▼              │
│  Client 1                  Client 2         │
│  (kr-legal)                (database)       │
└──┼────────────────────────────┼─────────────┘
   │                            │
   ▼                            ▼
┌─────────────┐          ┌─────────────┐
│ MCP Server  │          │ MCP Server  │
│ (HTTP/SSE)  │          │ (HTTP/SSE)  │
└─────────────┘          └─────────────┘
```

### Class Structure

```typescript
class MCPManager {
  clients: Map<string, { client, transport }>;
  tools: Map<string, { server, tool, client }>;
  
  async connectServer(name: string, config: ServerConfig): Promise<Tool[]>;
  async callTool(serverName: string, toolName: string, args: any): Promise<any>;
  listTools(): ToolInfo[];
  async disconnect(): Promise<void>;
}

class StreamableHTTPClientTransport {
  constructor(url: string, options?: TransportOptions);
  
  async start(): Promise<void>;
  async send(message: JSONRPCRequest): Promise<JSONRPCResponse>;
  async close(): Promise<void>;
  
  onmessage?: (message: JSONRPCMessage) => void;
  onerror?: (error: Error) => void;
  onclose?: () => void;
}
```

## 🔄 Request Flow

### Tool Call Sequence

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant ToolSystem
    participant MCPPlugin
    participant MCPClient
    participant MCPServer

    User->>Agent: "Search for labor law"
    Agent->>ToolSystem: mcp(action=call, server=kr-legal, tool=search_statute)
    ToolSystem->>MCPPlugin: execute(params)
    MCPPlugin->>MCPClient: callTool(search_statute, {query: "노동법"})
    MCPClient->>MCPServer: POST /mcp {method: tools/call, params: {...}}
    MCPServer-->>MCPClient: {result: {...}}
    MCPClient-->>MCPPlugin: {content: [...]}
    MCPPlugin-->>ToolSystem: {content: [...]}
    ToolSystem-->>Agent: Tool result
    Agent-->>User: "Found 15 statutes..."
```

## 📊 HTTP Transport Implementation

### Streamable HTTP Specification

This plugin implements the MCP Streamable HTTP transport:

**POST Request** (Client to Server):
```http
POST /mcp HTTP/1.1
Content-Type: application/json
mcp-session-id: session-123

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_statute",
    "arguments": {"query": "민법"}
  }
}
```

**GET SSE Stream** (Server to Client, optional):
```http
GET /mcp HTTP/1.1
Accept: text/event-stream
mcp-session-id: session-123

# Server can send:
event: message
data: {"jsonrpc":"2.0","id":1,"result":{...}}
```

### Session Management

- Session ID is generated on first connection
- Persisted across requests via `mcp-session-id` header
- Allows server to maintain state

## 🔧 Development

### Project Structure

```
mcp-integration/
├── src/
│   ├── index.js             # Main plugin entry point
│   └── http-transport.js    # HTTP/SSE transport implementation
├── config/
│   └── openclaw.plugin.json # Plugin metadata and config schema
├── package.json             # npm dependencies
└── README.md                # This file
```

### Key Files

**index.js**
- Exports OpenClaw plugin registration function
- Implements MCPManager class
- Registers the `mcp` tool
- Handles server connections and tool routing

**http-transport.js**
- Implements `StreamableHTTPClientTransport` class
- Handles HTTP POST requests
- Manages SSE stream for server messages
- Implements MCP transport interface

**openclaw.plugin.json**
- Plugin metadata (id, name, version)
- Configuration schema
- OpenClaw version requirements

### Adding Debug Logging

Enable debug mode in transport:

```javascript
const transport = new StreamableHTTPClientTransport(url, { debug: true });
```

This logs:
- Connection establishment
- Request/response details
- SSE stream events
- Error conditions

## 🧪 Testing

### Test Connection

```bash
# Start a test MCP server
node test-server.js

# In OpenClaw chat
User: List MCP tools

AI: [Shows available tools from test server]
```

### Manual Tool Call

```bash
# Using OpenClaw CLI (if available)
openclaw tool call mcp '{"action":"list"}'

openclaw tool call mcp '{
  "action": "call",
  "server": "test",
  "tool": "echo",
  "args": {"message": "Hello MCP!"}
}'
```

### Test MCP Server

```javascript
// test-server.js
import express from 'express';

const app = express();
app.use(express.json());

app.post('/mcp', (req, res) => {
  const { method, params } = req.body;
  
  if (method === 'tools/list') {
    res.json({
      jsonrpc: '2.0',
      id: req.body.id,
      result: {
        tools: [
          {
            name: 'echo',
            description: 'Echo back a message',
            inputSchema: {
              type: 'object',
              properties: {
                message: { type: 'string' }
              }
            }
          }
        ]
      }
    });
  } else if (method === 'tools/call') {
    res.json({
      jsonrpc: '2.0',
      id: req.body.id,
      result: {
        content: [
          { type: 'text', text: `Echo: ${params.arguments.message}` }
        ]
      }
    });
  }
});

app.listen(3000, () => console.log('Test MCP server on :3000'));
```

## 🐛 Troubleshooting

### Plugin Not Loading

**Check:**
```bash
openclaw status
# Look for plugin errors

openclaw logs | grep MCP
# Check MCP-specific logs
```

**Solution:**
```bash
# Verify plugin directory
ls -la ~/.openclaw/extensions/mcp-integration/

# Check dependencies
cd ~/.openclaw/extensions/mcp-integration/
npm install

# Restart gateway
openclaw gateway restart
```

### Server Connection Failed

**Error:**
```
[MCP] Failed to connect to kr-legal: fetch failed
```

**Solutions:**

1. **Check server is running:**
   ```bash
   curl http://localhost:3000/mcp
   ```

2. **Verify URL in config:**
   ```bash
   cat ~/.openclaw/openclaw.json | jq '.plugins.entries["mcp-integration"].config.servers'
   ```

3. **Check firewall:**
   ```bash
   # Allow local connections
   sudo ufw allow from 127.0.0.1
   ```

### Tool Not Found

**Error:**
```
Error: Tool not found: kr-legal:search_statute
```

**Solutions:**

1. **List available tools:**
   ```json
   {"tool": "mcp", "args": {"action": "list"}}
   ```

2. **Check server connection:**
   ```bash
   openclaw logs | grep "Connected to kr-legal"
   ```

3. **Reconnect servers:**
   ```bash
   openclaw gateway restart
   ```

## 📚 Examples

### Example 1: Weather Service

**Configuration:**
```json
{
  "servers": {
    "weather": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3000/mcp"
    }
  }
}
```

**Usage:**
```
User: What's the weather in Seoul?

AI: I'll check the weather forecast.

[Uses: mcp(action=call, server=weather, tool=get_forecast, args={city: "Seoul"})]

The weather in Seoul is currently 15°C, partly cloudy...
```

### Example 2: Database Query

**Configuration:**
```json
{
  "servers": {
    "database": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3001/mcp"
    }
  }
}
```

**Usage:**
```
User: Show me recent orders from the database

AI: I'll query the database for recent orders.

[Uses: mcp(action=call, server=database, tool=query, args={
  sql: "SELECT * FROM orders ORDER BY created_at DESC LIMIT 10"
})]

Here are the 10 most recent orders...
```

## 🔒 Security Considerations

### Server Validation

- Only connect to trusted MCP servers
- Use HTTPS for production deployments
- Validate server certificates

### Tool Permissions

Consider limiting tool access per agent:
```json
{
  "agents": {
    "main": {
      "tools": {
        "allowlist": ["mcp"]
      }
    },
    "chat": {
      "tools": {
        "denylist": ["mcp"]  // Disable MCP in public chat
      }
    }
  }
}
```

### Input Validation

All tool arguments are passed through to MCP servers. Ensure:
- MCP servers validate inputs
- Sensitive operations require confirmation
- Rate limiting is implemented

## 🚀 Future Enhancements

- [ ] stdio transport support
- [ ] Resource support (MCP resources)
- [ ] Prompt support (MCP prompts)
- [ ] Tool caching
- [ ] Connection pooling
- [ ] Retry logic
- [ ] Health checks
- [ ] Metrics and monitoring

## 📖 References

- [Model Context Protocol Specification](https://spec.modelcontextprotocol.io/)
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
- [OpenClaw Plugin Development](https://docs.openclaw.ai/plugins)

## 📄 License

MIT

## 🤝 Contributing

Contributions welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request

## 💬 Support

- **Issues**: [GitHub Issues](https://github.com/yourorg/mcp-integration/issues)
- **Discord**: OpenClaw Community #plugins
- **Email**: [REDACTED_SECRET]

---

**Version:** 0.1.0  
**Last Updated:** 2026-02-01  
**Author:** Lob 🦞


path: config/openclaw.plugin.json
content: {
  "id": "mcp-integration",
  "name": "MCP Integration",
  "version": "0.1.0",
  "description": "Model Context Protocol (MCP) integration - connect to MCP servers and use their tools",
  "author": "Lob",
  "license": "MIT",
  "openclaw": {
    "minVersion": "2026.1.0"
  },
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "enabled": {
        "type": "boolean",
        "default": true
      },
      "servers": {
        "type": "object",
        "description": "MCP servers to connect to",
        "additionalProperties": {
          "type": "object",
          "properties": {
            "enabled": {
              "type": "boolean",
              "default": true
            },
            "transport": {
              "type": "string",
              "enum": ["http", "stdio"],
              "description": "Transport type"
            },
            "url": {
              "type": "string",
              "description": "HTTP URL (for http transport)"
            },
            "command": {
              "type": "string",
              "description": "Command to spawn (for stdio transport)"
            },
            "args": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Command arguments (for stdio transport)"
            },
            "env": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "Environment variables (for stdio transport)"
            }
          }
        }
      }
    }
  }
}


path: docs/API.md
content: # API Reference

Complete API documentation for the MCP Integration plugin.

## 🛠️ The `mcp` Tool

The plugin exposes a single tool called `mcp` that provides access to all connected MCP servers.

### Tool Schema

```typescript
{
  name: "mcp",
  description: "Call MCP (Model Context Protocol) server tools",
  parameters: {
    type: "object",
    properties: {
      action: {
        type: "string",
        enum: ["list", "call"],
        description: "Action to perform"
      },
      server: {
        type: "string",
        description: "MCP server name (required for call)"
      },
      tool: {
        type: "string",
        description: "Tool name (required for call)"
      },
      args: {
        type: "object",
        description: "Tool arguments (optional for call)"
      }
    },
    required: ["action"]
  }
}
```

## 📊 Actions

### 1. List Tools (`action: "list"`)

Get a list of all available tools from all connected MCP servers.

#### Request

```json
{
  "tool": "mcp",
  "args": {
    "action": "list"
  }
}
```

#### Response

```json
{
  "content": [
    {
      "type": "text",
      "text": "[
        {
          \"id\": \"kr-legal:search_statute\",
          \"server\": \"kr-legal\",
          \"name\": \"search_statute\",
          \"description\": \"Search Korean statutes\",
          \"inputSchema\": {
            \"type\": \"object\",
            \"properties\": {
              \"query\": {\"type\": \"string\"},
              \"limit\": {\"type\": \"number\"}
            },
            \"required\": [\"query\"]
          }
        },
        {
          \"id\": \"database:query\",
          \"server\": \"database\",
          \"name\": \"query\",
          \"description\": \"Execute database query\",
          \"inputSchema\": {...}
        }
      ]"
    }
  ]
}
```

#### Tool Info Structure

```typescript
interface ToolInfo {
  id: string;              // Format: "server:toolName"
  server: string;          // Server name
  name: string;            // Tool name
  description: string;     // Tool description
  inputSchema: JSONSchema; // JSON Schema for arguments
}
```

#### Example Usage

**OpenClaw Chat:**
```
User: What MCP tools are available?

AI: Let me check the available MCP tools.

[Calls: mcp(action=list)]

Available MCP tools:
- kr-legal:search_statute - Search Korean statutes
- kr-legal:search_case_law - Search court decisions
- database:query - Execute SQL queries
- weather:get_forecast - Get weather forecast
```

### 2. Call Tool (`action: "call"`)

Execute a specific tool on an MCP server.

#### Request

```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute",
    "args": {
      "query": "민법",
      "limit": 5
    }
  }
}
```

#### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `action` | string | Yes | Must be "call" |
| `server` | string | Yes | Name of MCP server (from config) |
| `tool` | string | Yes | Name of tool to call |
| `args` | object | No | Arguments to pass to tool |

#### Response

```json
{
  "content": [
    {
      "type": "text",
      "text": "{
        \"result\": {
          \"results\": [
            {
              \"title\": \"민법\",
              \"statute_id\": \"0001\",
              ...
            }
          ]
        }
      }"
    }
  ]
}
```

#### Error Response

```json
{
  "content": [
    {
      "type": "text",
      "text": "Error: Tool not found: kr-legal:invalid_tool"
    }
  ],
  "isError": true
}
```

#### Example Usage

**OpenClaw Chat:**
```
User: Search for Korean civil law

AI: I'll search Korean statutes for civil law.

[Calls: mcp(
  action=call,
  server=kr-legal,
  tool=search_statute,
  args={query: "민법", limit: 5}
)]

Found 5 statutes related to civil law:
1. 민법 (Civil Code) - Statute #0001
2. 민법 시행령 (Civil Code Enforcement Decree)
...
```

## 🔌 MCPManager Class

Internal class that manages MCP server connections. Not directly accessible from agents.

### Methods

#### `connectServer(name, config)`

Connect to an MCP server.

```typescript
async connectServer(
  name: string,
  config: ServerConfig
): Promise<Tool[]>
```

**Parameters:**
- `name`: Server name
- `config`: Server configuration object

**Returns:**
- Array of tools provided by the server

**Throws:**
- Error if connection fails

**Example:**
```javascript
const tools = await mcpManager.connectServer('kr-legal', {
  enabled: true,
  transport: 'http',
  url: 'http://localhost:3000/mcp'
});
// Returns: [{name: 'search_statute', ...}, ...]
```

#### `callTool(serverName, toolName, args)`

Call a tool on a specific server.

```typescript
async callTool(
  serverName: string,
  toolName: string,
  args: object = {}
): Promise<ToolResult>
```

**Parameters:**
- `serverName`: Name of MCP server
- `toolName`: Name of tool to call
- `args`: Tool arguments (optional)

**Returns:**
- Tool execution result

**Throws:**
- Error if tool not found
- Error if tool execution fails

**Example:**
```javascript
const result = await mcpManager.callTool(
  'kr-legal',
  'search_statute',
  { query: '민법', limit: 5 }
);
// Returns: {content: [{type: 'text', text: '...'}]}
```

#### `listTools()`

Get all available tools from all servers.

```typescript
listTools(): ToolInfo[]
```

**Returns:**
- Array of tool information objects

**Example:**
```javascript
const tools = mcpManager.listTools();
// Returns: [
//   {id: 'kr-legal:search_statute', server: 'kr-legal', name: 'search_statute', ...},
//   {id: 'database:query', server: 'database', name: 'query', ...}
// ]
```

#### `disconnect()`

Disconnect from all MCP servers.

```typescript
async disconnect(): Promise<void>
```

**Example:**
```javascript
await mcpManager.disconnect();
// All servers disconnected
```

## 🌐 StreamableHTTPClientTransport Class

Implements MCP Streamable HTTP transport specification.

### Constructor

```typescript
constructor(url: string | URL, options?: TransportOptions)
```

**Parameters:**
```typescript
interface TransportOptions {
  sessionId?: string;  // Optional session ID
  debug?: boolean;     // Enable debug logging
}
```

**Example:**
```javascript
const transport = new StreamableHTTPClientTransport(
  'http://localhost:3000/mcp',
  { debug: true }
);
```

### Methods

#### `start()`

Start the transport.

```typescript
async start(): Promise<void>
```

#### `send(message)`

Send a JSON-RPC message to the server.

```typescript
async send(message: JSONRPCRequest): Promise<JSONRPCResponse>
```

**Example:**
```javascript
const response = await transport.send({
  jsonrpc: '2.0',
  id: 1,
  method: 'tools/list',
  params: {}
});
```

#### `close()`

Close the transport.

```typescript
async close(): Promise<void>
```

### Event Handlers

```typescript
transport.onmessage = (message: JSONRPCMessage) => {
  // Handle incoming message
};

transport.onerror = (error: Error) => {
  // Handle error
};

transport.onclose = () => {
  // Handle connection close
};
```

## 📡 JSON-RPC Protocol

### Request Format

```typescript
{
  jsonrpc: "2.0",
  id: number | string,
  method: string,
  params?: object
}
```

### Response Format

```typescript
{
  jsonrpc: "2.0",
  id: number | string,
  result?: any,
  error?: {
    code: number,
    message: string,
    data?: any
  }
}
```

### Standard Methods

#### `tools/list`

List available tools.

**Request:**
```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
```

**Response:**
```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "search_statute",
        "description": "Search Korean statutes",
        "inputSchema": {...}
      }
    ]
  }
}
```

#### `tools/call`

Execute a tool.

**Request:**
```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search_statute",
    "arguments": {
      "query": "민법",
      "limit": 5
    }
  }
}
```

**Response:**
```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "..."
      }
    ]
  }
}
```

## 🔗 Related Documentation

- [Main README](../README.md)
- [Configuration Guide](CONFIGURATION.md)
- [Usage Examples](EXAMPLES.md)

---

**API Version:** 0.1.0  
**MCP SDK Version:** 0.5.0  
**Last Updated:** 2026-02-01


path: docs/CONFIGURATION.md
content: # Configuration Guide

Complete guide to configuring the MCP Integration plugin for OpenClaw.

## 📋 Configuration File Location

The plugin is configured in OpenClaw's main configuration file:

```
~/.openclaw/openclaw.json
```

## 🔧 Basic Configuration

### Minimal Configuration

```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "enabled": true,
          "servers": {
            "my-server": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3000/mcp"
            }
          }
        }
      }
    }
  }
}
```

### Full Configuration Example

```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "enabled": true,
          "servers": {
            "kr-legal": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3000/mcp",
              "timeout": 30000,
              "retries": 3
            },
            "database": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3001/mcp"
            },
            "weather": {
              "enabled": false,
              "transport": "http",
              "url": "http://localhost:3002/mcp"
            }
          }
        }
      }
    }
  }
}
```

## 📊 Configuration Schema

### Root Configuration

```typescript
{
  enabled: boolean;              // Enable/disable entire plugin
  servers: {
    [serverName: string]: ServerConfig;
  }
}
```

### Server Configuration

```typescript
{
  enabled: boolean;              // Enable/disable this server
  transport: "http";             // Transport type
  url: string;                   // Server URL
  timeout?: number;              // Request timeout in ms (default: 30000)
  retries?: number;              // Retry attempts (default: 0)
}
```

## 🌍 Environment Variables

MCP servers often require environment variables for API keys or configuration.

### Setting Environment Variables

**Option 1: In openclaw.json**
```json
{
  "env": {
    "KR_LEGAL_API_KEY": "your-api-key-here"
  },
  "plugins": {
    "entries": {
      "mcp-integration": {
        "config": {
          "servers": {
            "kr-legal": {
              "url": "http://localhost:3000/mcp"
            }
          }
        }
      }
    }
  }
}
```

**Option 2: System environment**
```bash
# In ~/.bashrc or ~/.zshrc
export KR_LEGAL_API_KEY="your-api-key-here"

# Then reference in server
```

**Option 3: .env file**
```bash
# ~/.openclaw/.env
KR_LEGAL_API_KEY=your-api-key-here
```

```json
{
  "envFile": "/home/user/.openclaw/.env",
  "plugins": { ... }
}
```

## 🎭 Per-Agent Configuration

Enable MCP tools for specific agents only:

```json
{
  "agents": {
    "main": {
      "tools": {
        "allowlist": ["mcp"]
      }
    },
    "chat": {
      "tools": {
        "denylist": ["mcp"]
      }
    }
  },
  "plugins": {
    "entries": {
      "mcp-integration": { ... }
    }
  }
}
```

## 🔄 Multiple Server Configurations

### Example: Different Services

```json
{
  "servers": {
    "legal": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3000/mcp"
    },
    "database": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3001/mcp"
    },
    "weather": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3002/mcp"
    },
    "calendar": {
      "enabled": true,
      "transport": "http",
      "url": "http://localhost:3003/mcp"
    }
  }
}
```

### Example: Development vs Production

**Development:**
```json
{
  "servers": {
    "test-server": {
      "enabled": true,
      "url": "http://localhost:3000/mcp"
    }
  }
}
```

**Production:**
```json
{
  "servers": {
    "prod-server": {
      "enabled": true,
      "url": "https://mcp.example.com/mcp"
    }
  }
}
```

## 🔐 Secure Configuration

### HTTPS Connections

Always use HTTPS in production:

```json
{
  "servers": {
    "secure-server": {
      "enabled": true,
      "transport": "http",
      "url": "https://secure.example.com/mcp"
    }
  }
}
```

### API Key Management

**Best Practice:**
```json
{
  "env": {
    "MCP_API_KEY": "${MCP_API_KEY}"
  }
}
```

Then set in environment:
```bash
export MCP_API_KEY="secret-key-here"
```

**Never commit:**
```json
{
  "env": {
    "MCP_API_KEY": "sk-1234567890abcdef"  // ❌ BAD - exposed in git
  }
}
```

## 🧪 Testing Configuration

### Validate JSON

```bash
# Check syntax
cat ~/.openclaw/openclaw.json | jq .

# Validate specific plugin config
cat ~/.openclaw/openclaw.json | jq '.plugins.entries["mcp-integration"]'
```

### Test Server Connection

```bash
# Test URL is accessible
curl http://localhost:3000/mcp

# Test with JSON-RPC request
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
  }'
```

### Verify Plugin Loaded

```bash
# Check OpenClaw logs
openclaw logs | grep MCP

# Expected output:
# [MCP] Plugin registered
# [MCP] Starting...
# [MCP] Connecting to kr-legal at http://localhost:3000/mcp
# [MCP] Connected to kr-legal: 5 tools available
# [MCP] Started
```

## 🔄 Reload Configuration

### Apply Changes

```bash
# Method 1: Full restart
openclaw gateway restart

# Method 2: Reload config (if supported)
openclaw config reload
```

### Check Status

```bash
# Verify plugin status
openclaw status

# Check specific plugin
openclaw plugins status mcp-integration
```

## 🐛 Troubleshooting Configuration

### Common Issues

**Issue 1: Plugin not loading**
```bash
# Check file exists
ls -la ~/.openclaw/extensions/mcp-integration/

# Check config syntax
cat ~/.openclaw/openclaw.json | jq '.plugins.entries["mcp-integration"]'
```

**Issue 2: Server not connecting**
```bash
# Test URL
curl http://localhost:3000/mcp

# Check logs
openclaw logs | grep "Failed to connect"
```

**Issue 3: Invalid configuration**
```bash
# Validate against schema
# The plugin will log validation errors on startup
openclaw logs | grep "config"
```

## 📋 Configuration Checklist

Before deploying:

- [ ] Valid JSON syntax
- [ ] All required fields present
- [ ] URLs are accessible
- [ ] API keys set securely (environment variables)
- [ ] HTTPS used in production
- [ ] Appropriate timeouts set
- [ ] Test connection to each server
- [ ] Gateway restarted after changes
- [ ] Logs checked for errors

## 🔗 Related Documentation

- [Main README](../README.md)
- [API Reference](API.md)
- [Troubleshooting Guide](TROUBLESHOOTING.md)

---

**Tips:**
- Start with minimal configuration
- Test each server individually
- Use environment variables for secrets
- Monitor logs after configuration changes
- Keep backups of working configurations


path: docs/EXAMPLES.md
content: # Usage Examples

Practical examples of using the MCP Integration plugin with OpenClaw.

## 📚 Table of Contents

1. [Basic Usage](#basic-usage)
2. [Legal Research](#legal-research)
3. [Database Queries](#database-queries)
4. [Weather Service](#weather-service)
5. [Multi-Step Workflows](#multi-step-workflows)
6. [Error Handling](#error-handling)

## 🎯 Basic Usage

### Example 1: List All Available Tools

**User:** "What MCP tools do I have access to?"

**OpenClaw Agent:**
```
I'll check what MCP tools are available.

[Tool: mcp]
Action: list
```

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "list"
  }
}
```

**Agent Response:**
```
Available MCP tools:

Legal Services (kr-legal):
• search_statute - Search Korean statutes and regulations
• search_case_law - Search court decisions and precedents
• resolve_citation - Resolve legal citations to full text

Database (database):
• query - Execute SQL queries
• schema - Get database schema

Weather (weather):
• get_forecast - Get weather forecast
• get_current - Get current weather conditions
```

### Example 2: Call a Simple Tool

**User:** "Get the weather for Seoul"

**OpenClaw Agent:**
```
I'll check the weather in Seoul.

[Tool: mcp]
Action: call
Server: weather
Tool: get_current
Arguments: {city: "Seoul"}
```

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "weather",
    "tool": "get_current",
    "args": {
      "city": "Seoul"
    }
  }
}
```

**Agent Response:**
```
Current weather in Seoul:
• Temperature: 15°C
• Conditions: Partly cloudy
• Humidity: 65%
• Wind: 12 km/h NW
```

## ⚖️ Legal Research

### Example 3: Search Korean Statutes

**User:** "Find Korean laws about unfair dismissal"

**Agent Workflow:**
```
I'll search Korean legal statutes for unfair dismissal.

[Tool: mcp]
Action: call
Server: kr-legal
Tool: search_statute
Arguments: {query: "부당해고", category: "노동법", limit: 5}
```

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute",
    "args": {
      "query": "부당해고",
      "category": "노동법",
      "limit": 5
    }
  }
}
```

**Agent Response:**
```
Found 5 statutes related to unfair dismissal:

1. 근로기준법 제23조 (해고 등의 제한)
   - Enacted: 1953-05-10
   - Last amended: 2023-01-01
   - Summary: 정당한 이유 없는 해고, 휴직, 정직 등을 금지

2. 근로기준법 제26조 (해고의 예고)
   - Summary: 해고 시 30일 전 예고 또는 30일분 통상임금 지급

3. 노동조합 및 노동관계조정법 제81조 (부당해고 등의 구제신청)
   - Summary: 부당해고 등의 경우 노동위원회에 구제 신청 가능

Would you like me to get the full text of any of these statutes?
```

### Example 4: Get Full Statute Text

**User:** "Yes, show me the full text of 근로기준법 제23조"

**Agent Workflow:**
```
I'll retrieve the full text of 근로기준법 제23조.

[Tool: mcp]
Action: call
Server: kr-legal
Tool: get_statute_full_text
Arguments: {statute_id: "0065", article: 23}
```

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "get_statute_full_text",
    "args": {
      "statute_id": "0065",
      "article": 23
    }
  }
}
```

**Agent Response:**
```
근로기준법 제23조 (해고 등의 제한)

① 사용자는 근로자에게 정당한 이유 없이 해고, 휴직, 정직, 전직, 감봉, 그 밖의 징벌을 하지 못한다.

② 사용자는 근로자가 업무상 부상 또는 질병의 요양을 위하여 휴업한 기간과 그 후 30일 동안 또는 산전·산후의 여성이 이 법에 따라 휴업한 기간과 그 후 30일 동안은 해고하지 못한다. 다만, 사용자가 제84조에 따라 일시보상을 하였을 경우 또는 사업을 계속할 수 없게 된 경우에는 그러하지 아니하다.

Related provisions:
• 제24조 (경영상 이유에 의한 해고의 제한)
• 제26조 (해고의 예고)
• 제27조 (해고사유 등의 서면통지)
```

### Example 5: Search Case Law

**User:** "Find Supreme Court cases about unfair dismissal from the last 3 years"

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_case_law",
    "args": {
      "query": "부당해고",
      "court": "supreme",
      "date_from": "2021-01-01",
      "limit": 5
    }
  }
}
```

## 💾 Database Queries

### Example 6: Query Database

**User:** "Show me the latest 10 orders from the database"

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "database",
    "tool": "query",
    "args": {
      "sql": "SELECT * FROM orders ORDER BY created_at DESC LIMIT 10"
    }
  }
}
```

**Agent Response:**
```
Latest 10 orders:

| Order ID | Customer | Amount  | Status    | Date       |
|----------|----------|---------|-----------|------------|
| ORD-1234 | John Doe | $150.00 | Completed | 2026-02-01 |
| ORD-1233 | Jane Doe | $89.99  | Pending   | 2026-01-31 |
...
```

### Example 7: Get Database Schema

**User:** "What tables are in the database?"

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "database",
    "tool": "schema",
    "args": {}
  }
}
```

## 🌦️ Weather Service

### Example 8: Weather Forecast

**User:** "What's the 7-day forecast for Tokyo?"

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "weather",
    "tool": "get_forecast",
    "args": {
      "city": "Tokyo",
      "days": 7
    }
  }
}
```

**Agent Response:**
```
7-day forecast for Tokyo:

Mon Feb 3: ☀️ Sunny, 12°C / 5°C
Tue Feb 4: ⛅ Partly cloudy, 14°C / 7°C
Wed Feb 5: 🌧️ Rain, 11°C / 6°C
Thu Feb 6: ☁️ Cloudy, 10°C / 4°C
Fri Feb 7: ☀️ Sunny, 13°C / 5°C
Sat Feb 8: ⛅ Partly cloudy, 15°C / 8°C
Sun Feb 9: ☀️ Sunny, 16°C / 9°C
```

## 🔄 Multi-Step Workflows

### Example 9: Legal Research + Analysis

**User:** "Research Korean labor law about overtime pay and explain how it applies to my situation"

**Agent Workflow:**

**Step 1: Search statutes**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute",
    "args": {
      "query": "연장근로 수당",
      "category": "노동법"
    }
  }
}
```

**Step 2: Get detailed analysis**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "analyze_law",
    "args": {
      "statute_or_case": "근로기준법 제56조",
      "analysis_type": "practical",
      "context": "야간근무 및 연장근무 수당 계산"
    }
  }
}
```

**Step 3: Find related cases**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_case_law",
    "args": {
      "query": "연장근무 수당",
      "court": "supreme",
      "limit": 3
    }
  }
}
```

**Agent Response:**
```
Korean Labor Law on Overtime Pay - Comprehensive Analysis

Legal Basis:
근로기준법 제56조 (연장·야간 및 휴일 근로)

Key Points:
1. Overtime (beyond 40 hrs/week): +50% premium
2. Night work (10PM-6AM): +50% premium
3. Holiday work: +50% premium
4. Overlapping premiums stack (e.g., night + overtime = +100%)

Your Situation:
[Analysis based on context provided...]

Relevant Precedents:
1. Supreme Court 2019다67890 - Overtime pay calculation
2. Supreme Court 2018da54321 - Night work premium requirements
3. Supreme Court 2020da12345 - Combined premium application

Next Steps:
[Actionable advice based on analysis...]
```

### Example 10: Database + Weather Integration

**User:** "Check if we have any outdoor events scheduled when it's going to rain"

**Step 1: Query events**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "database",
    "tool": "query",
    "args": {
      "sql": "SELECT event_name, location, event_date FROM events WHERE location_type = 'outdoor' AND event_date >= CURRENT_DATE ORDER BY event_date"
    }
  }
}
```

**Step 2: Check weather for each date**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "weather",
    "tool": "get_forecast",
    "args": {
      "city": "Seoul",
      "days": 14
    }
  }
}
```

**Agent Response:**
```
Outdoor Events with Rain Risk:

⚠️ Feb 5 - Company Picnic (Seoul Park)
   Forecast: 80% rain, 11°C
   Recommendation: Consider moving indoors or rescheduling

✅ Feb 7 - Team Building (Han River)
   Forecast: Sunny, 13°C
   Status: Good to proceed

⚠️ Feb 10 - Product Launch (Rooftop Venue)
   Forecast: 60% rain, 12°C
   Recommendation: Prepare backup indoor location
```

## ❌ Error Handling

### Example 11: Invalid Tool

**User:** "Use the magic tool"

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "magic_tool",
    "args": {}
  }
}
```

**Response:**
```json
{
  "content": [
    {
      "type": "text",
      "text": "Error: Tool not found: kr-legal:magic_tool. Available: kr-legal:search_statute, kr-legal:search_case_law, kr-legal:resolve_citation, kr-legal:get_statute_full_text, kr-legal:analyze_law"
    }
  ],
  "isError": true
}
```

**Agent Response:**
```
I don't have access to a "magic tool" in the kr-legal server. 

Available legal tools are:
• search_statute - Search statutes
• search_case_law - Search case law
• resolve_citation - Resolve citations
• get_statute_full_text - Get full statute text
• analyze_law - Analyze laws

What would you like me to do?
```

### Example 12: Missing Required Parameter

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute"
    // Missing "args" with required "query" parameter
  }
}
```

**Response:**
```json
{
  "content": [
    {
      "type": "text",
      "text": "Error: Invalid arguments for search_statute. Required: query"
    }
  ],
  "isError": true
}
```

### Example 13: Server Connection Error

**Tool Call:**
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "offline-server",
    "tool": "some_tool",
    "args": {}
  }
}
```

**Response:**
```json
{
  "content": [
    {
      "type": "text",
      "text": "Error: Tool not found: offline-server:some_tool. Server may be disconnected."
    }
  ],
  "isError": true
}
```

## 🔗 Related Documentation

- [Main README](../README.md)
- [API Reference](API.md)
- [Configuration Guide](CONFIGURATION.md)

---

**Tips for Using MCP Tools:**
- Always start with `action=list` to see available tools
- Check tool input schemas before calling
- Provide all required parameters
- Handle errors gracefully
- Chain multiple tools for complex workflows


path: docs/REAL_EXAMPLE_KR_LEGAL.md
content: # Real Working Example: kr-legal-search

This is a **real, working configuration** for connecting to the kr-legal-search MCP server.

## ⚠️ Important: No API Key Required

The current kr-legal-search service **does not require an API key**. The documentation mentioning `KR_LEGAL_API_KEY` was for a hypothetical future version.

## 🚀 Working Configuration

### OpenClaw Configuration

Edit `~/.openclaw/openclaw.json`:

```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "enabled": true,
          "servers": {
            "kr-legal": {
              "enabled": true,
              "transport": "http",
              "url": "http://localhost:3000/mcp"
            }
          }
        }
      }
    }
  }
}
```

**That's it!** No API key needed.

## 🎯 Start the kr-legal Service

Assuming you have the kr-legal MCP server running:

```bash
# Start the kr-legal server (adjust path as needed)
cd /path/to/kr-legal-server
npm start

# Should output:
# kr-legal MCP server listening on http://localhost:3000
```

## ✅ Verify It Works

### Step 1: Restart OpenClaw

```bash
openclaw gateway restart
```

### Step 2: Check Logs

```bash
openclaw logs | grep MCP

# Expected output:
# [MCP] Plugin registered
# [MCP] Starting...
# [MCP] Connecting to kr-legal at http://localhost:3000/mcp
# [MCP] Connected to kr-legal: 5 tools available
# [MCP] Started
```

### Step 3: Test in OpenClaw

**In OpenClaw chat:**
```
User: List MCP tools

AI: Let me check available MCP tools.
[Uses: mcp with action=list]

Available MCP tools:
- kr-legal:search_statute
- kr-legal:search_case_law
- kr-legal:resolve_citation
- kr-legal:get_statute_full_text
- kr-legal:analyze_law
```

### Step 4: Try a Search

**In OpenClaw chat:**
```
User: Search for Korean civil law

AI: I'll search Korean statutes for civil law.
[Uses: mcp with action=call, server=kr-legal, tool=search_statute]

Found statutes related to civil law:
1. 민법 (Civil Code) - Statute #0001
...
```

## 📊 Full Example Interaction

### User Query
```
User: Find Korean labor law about overtime pay
```

### Tool Call 1: Search statutes
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "search_statute",
    "args": {
      "query": "연장근로 수당",
      "category": "노동법",
      "limit": 3
    }
  }
}
```

### Response
```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"results\":[{\"title\":\"근로기준법 제56조\",\"statute_id\":\"0065\",\"article\":56,...}]}"
    }
  ]
}
```

### Tool Call 2: Get full text
```json
{
  "tool": "mcp",
  "args": {
    "action": "call",
    "server": "kr-legal",
    "tool": "get_statute_full_text",
    "args": {
      "statute_id": "0065",
      "article": 56
    }
  }
}
```

## 🔧 Troubleshooting

### Issue: "Failed to connect to kr-legal"

**Check if server is running:**
```bash
curl http://localhost:3000/mcp
# Should return something, even if it's an error about missing params
```

**If not running:**
```bash
# Start the kr-legal server
cd /path/to/kr-legal-server
npm start
```

### Issue: "Tool not found: kr-legal:search_statute"

**Restart OpenClaw:**
```bash
openclaw gateway restart
```

**Check logs:**
```bash
openclaw logs | grep "Connected to kr-legal"
# Should show: [MCP] Connected to kr-legal: 5 tools available
```

### Issue: Port 3000 already in use

**Change the port in both places:**

1. **kr-legal server** (adjust to use different port, e.g., 3001)
2. **OpenClaw config:**
```json
{
  "servers": {
    "kr-legal": {
      "url": "http://localhost:3001/mcp"
    }
  }
}
```

## 📝 Minimal Test Configuration

Here's the **absolute minimum** to test:

**`~/.openclaw/openclaw.json`:**
```json
{
  "plugins": {
    "entries": {
      "mcp-integration": {
        "enabled": true,
        "config": {
          "servers": {
            "kr-legal": {
              "url": "http://localhost:3000/mcp"
            }
          }
        }
      }
    }
  }
}
```

**Start server → Restart OpenClaw → Test in chat**

## 🎉 Success Criteria

You know it's working when:

1. ✅ OpenClaw logs show "Connected to kr-legal: X tools available"
2. ✅ `List MCP tools` command shows kr-legal tools
3. ✅ Calling a tool returns results (not errors)
4. ✅ Agent can successfully use kr-legal tools in conversation

## 📋 Complete Setup Checklist

- [ ] kr-legal MCP server is installed
- [ ] kr-legal server is running on port 3000
- [ ] mcp-integration plugin is installed in OpenClaw
- [ ] Configuration added to openclaw.json (no API key needed!)
- [ ] OpenClaw gateway restarted
- [ ] Logs show successful connection
- [ ] Tools are listed correctly
- [ ] Test query works

## 🔗 Related Files

- Main documentation: [README.md](../README.md)
- Configuration guide: [CONFIGURATION.md](CONFIGURATION.md)
- More examples: [EXAMPLES.md](EXAMPLES.md)
- Troubleshooting: [TROUBLESHOOTING.md](TROUBLESHOOTING.md)

---

**Key Point:** The current kr-legal service is **ready to use without any API key**. Just make sure the server is running and configure the URL in OpenClaw!

**Last Updated:** 2026-02-01  
**Tested With:** OpenClaw 2026.1.x, kr-legal-search MCP server


path: docs/TROUBLESHOOTING.md
content: # Troubleshooting Guide

Solutions to common issues with the MCP Integration plugin.

## 🔍 Diagnostic Commands

### Quick Status Check

```bash
# Check OpenClaw status
openclaw status

# Check MCP plugin logs
openclaw logs | grep MCP

# Check plugin directory
ls -la ~/.openclaw/extensions/mcp-integration/

# Test configuration syntax
cat ~/.openclaw/openclaw.json | jq '.plugins.entries["mcp-integration"]'
```

## 🚨 Common Issues

### Issue 1: Plugin Not Loading

**Symptoms:**
```
openclaw status
# mcp-integration: not found
```

**Diagnostic:**
```bash
# Check if plugin exists
ls -la ~/.openclaw/extensions/mcp-integration/

# Check plugin metadata
cat ~/.openclaw/extensions/mcp-integration/config/openclaw.plugin.json

# Check for errors
openclaw logs | grep -i "mcp" | grep -i "error"
```

**Solutions:**

**A. Plugin not installed:**
```bash
# Install plugin
cd ~/.openclaw/extensions/
git clone <repository-url> mcp-integration
cd mcp-integration
npm install

# Restart
openclaw gateway restart
```

**B. Configuration error:**
```bash
# Validate JSON
cat ~/.openclaw/openclaw.json | jq .

# Fix syntax errors, then:
openclaw gateway restart
```

**C. Dependencies missing:**
```bash
cd ~/.openclaw/extensions/mcp-integration/
npm install
openclaw gateway restart
```

### Issue 2: Server Connection Failed

**Symptoms:**
```
[MCP] Failed to connect to kr-legal: fetch failed
```

**Diagnostic:**
```bash
# Test server is running
curl http://localhost:3000/mcp

# Check if port is open
netstat -tuln | grep 3000

# Test server with JSON-RPC
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

**Solutions:**

**A. Server not running:**
```bash
# Start your MCP server
node server.js
# or
npm start
```

**B. Wrong URL in config:**
```json
{
  "servers": {
    "kr-legal": {
      "enabled": true,
      "url": "http://localhost:3000/mcp"  // Check port and path
    }
  }
}
```

**C. Firewall blocking:**
```bash
# Allow local connections
sudo ufw allow from 127.0.0.1

# Or allow specific port
sudo ufw allow 3000/tcp
```

**D. Server not responding to MCP protocol:**
```bash
# Test if server responds correctly
curl -v -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
  }'

# Should return JSON-RPC response with tools
```

### Issue 3: Tool Not Found

**Symptoms:**
```
Error: Tool not found: kr-legal:search_statute
```

**Diagnostic:**
```bash
# List available tools in OpenClaw
# In chat: "List MCP tools"

# Check server is connected
openclaw logs | grep "Connected to kr-legal"

# Check what tools were registered
openclaw logs | grep "tools available"
```

**Solutions:**

**A. Server disconnected:**
```bash
# Restart gateway to reconnect
openclaw gateway restart

# Check logs
openclaw logs | grep "Connecting to kr-legal"
openclaw logs | grep "Connected to kr-legal"
```

**B. Tool name mismatch:**
```json
// Correct format: "server:tool"
{
  "server": "kr-legal",
  "tool": "search_statute"  // Not "searchStatute" or "search-statute"
}
```

**C. Server disabled:**
```json
{
  "servers": {
    "kr-legal": {
      "enabled": true  // Must be true
    }
  }
}
```

### Issue 4: Invalid Arguments

**Symptoms:**
```
Error: Invalid arguments for search_statute. Required: query
```

**Diagnostic:**
```bash
# List tools to see schema
# In chat: "List MCP tools"

# Check what parameters are required
```

**Solution:**

Check the tool's `inputSchema` and provide all required parameters:

```json
// If schema shows:
{
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "limit": { "type": "number" }
    },
    "required": ["query"]  // ← "query" is required
  }
}

// Then call with:
{
  "action": "call",
  "server": "kr-legal",
  "tool": "search_statute",
  "args": {
    "query": "민법"  // ← Must provide required param
  }
}
```

### Issue 5: HTTP Transport Errors

**Symptoms:**
```
[Transport] POST failed: HTTP 500
[Transport] SSE stream error
```

**Diagnostic:**
```bash
# Enable debug mode
# Edit http-transport.js:
# new StreamableHTTPClientTransport(url, { debug: true })

# Check server logs for errors

# Test with curl
curl -v -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

**Solutions:**

**A. Server error (500):**
- Check MCP server logs
- Verify server implementation
- Ensure server handles JSON-RPC correctly

**B. Invalid response format:**
```javascript
// Server must return valid JSON-RPC:
{
  "jsonrpc": "2.0",
  "id": 1,  // Must match request ID
  "result": {  // Or "error"
    "tools": [...]
  }
}
```

**C. SSE not supported:**
- GET SSE stream is optional
- Plugin will fall back to POST-only mode
- Error is logged but doesn't affect functionality

### Issue 6: Session ID Issues

**Symptoms:**
```
[Transport] Session ID not persisted
[Transport] Creating new session on each request
```

**Solution:**

This is usually not a problem. The transport automatically manages sessions:
- First request gets a session ID from `mcp-session-id` header
- Subsequent requests use that session ID
- If server doesn't support sessions, each request is independent

### Issue 7: Plugin Crashes OpenClaw

**Symptoms:**
```
openclaw status
# gateway: crashed
```

**Diagnostic:**
```bash
# Check crash logs
openclaw logs | grep -A 20 "crash"

# Check JavaScript errors
openclaw logs | grep "Error:"
openclaw logs | grep "TypeError:"
```

**Solutions:**

**A. Syntax error in plugin code:**
```bash
# Check plugin files
node --check ~/.openclaw/extensions/mcp-integration/index.js
node --check ~/.openclaw/extensions/mcp-integration/http-transport.js
```

**B. Missing dependency:**
```bash
cd ~/.openclaw/extensions/mcp-integration/
npm install
```

**C. Incompatible OpenClaw version:**
```bash
# Check required version
cat ~/.openclaw/extensions/mcp-integration/config/openclaw.plugin.json | jq '.openclaw.minVersion'

# Check installed version
openclaw --version

# Upgrade if needed
openclaw update
```

### Issue 8: Memory Leaks

**Symptoms:**
```
# OpenClaw using excessive memory over time
top -p $(pgrep -f openclaw)
```

**Solutions:**

**A. Connection not closing:**
```javascript
// In MCPManager.disconnect():
for (const [name, { client }] of this.clients.entries()) {
  await client.close();  // ← Must close clients
}
```

**B. SSE streams not cleaned up:**
```javascript
// In http-transport.js close():
if (this._sseAbortController) {
  this._sseAbortController.abort();  // ← Must abort SSE
}
```

**C. Event listeners not removed:**
```javascript
// Remove event listeners before destroying
transport.onmessage = null;
transport.onerror = null;
transport.onclose = null;
```

## 🧪 Debug Mode

### Enable Full Debug Logging

**1. Edit http-transport.js:**
```javascript
const transport = new StreamableHTTPClientTransport(url, { 
  debug: true  // ← Add this
});
```

**2. Restart OpenClaw:**
```bash
openclaw gateway restart
```

**3. View debug logs:**
```bash
openclaw logs | grep -i transport
```

**Debug output:**
```
[Transport] Started
[Transport] Opening GET SSE stream
[Transport] GET SSE stream opened
[Transport] SSE message: {"jsonrpc":"2.0",...}
[Transport] POST request: {"jsonrpc":"2.0","id":1,"method":"tools/list"}
[Transport] POST response: {"jsonrpc":"2.0","id":1,"result":{...}}
```

## 📊 Collecting Diagnostic Info

### Create Diagnostic Report

```bash
#!/bin/bash
# save as: diagnose-mcp.sh

echo "=== System Info ==="
uname -a
node --version
openclaw --version

echo -e "\n=== Plugin Status ==="
ls -la ~/.openclaw/extensions/mcp-integration/

echo -e "\n=== Configuration ==="
cat ~/.openclaw/openclaw.json | jq '.plugins.entries["mcp-integration"]'

echo -e "\n=== Recent Logs ==="
openclaw logs | grep -i mcp | tail -50

echo -e "\n=== Server Tests ==="
for url in http://localhost:3000/mcp http://localhost:3001/mcp; do
  echo "Testing $url..."
  curl -s -X POST "$url" \
    -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
    | jq . 2>/dev/null || echo "Failed"
done
```

Run and share:
```bash
chmod +x diagnose-mcp.sh
./diagnose-mcp.sh > mcp-diagnostic.txt
```

## 📞 Getting Help

### Before Asking for Help

1. Check this troubleshooting guide
2. Review the logs: `openclaw logs | grep MCP`
3. Test server connection manually with `curl`
4. Verify configuration syntax with `jq`
5. Try with minimal configuration
6. Create diagnostic report (above)

### Support Channels

1. **GitHub Issues**: Include diagnostic report
2. **Discord**: OpenClaw Community #plugins channel
3. **Email**: Attach diagnostic report

### Useful Information to Include

- OpenClaw version: `openclaw --version`
- Node version: `node --version`
- Plugin version: Check `package.json`
- Configuration (redacted secrets)
- Error logs
- Steps to reproduce
- Diagnostic report

## 🔗 Related Documentation

- [Main README](../README.md)
- [Configuration](CONFIGURATION.md)
- [API Reference](API.md)

---

**Quick Fixes:**
- Restart gateway: `openclaw gateway restart`
- Check logs: `openclaw logs | grep MCP`
- Test server: `curl http://localhost:3000/mcp`
- Validate config: `cat ~/.openclaw/openclaw.json | jq .`


path: package.json
content: {
  "name": "openclaw-mcp-integration",
  "version": "0.1.0",
  "description": "Model Context Protocol (MCP) integration for OpenClaw",
  "main": "src/index.js",
  "type": "module",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.25.3",
    "eventsource": "^4.1.0",
    "eventsource-parser": "^3.0.6"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}


path: src/index.js
content: import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from './http-transport.js';

/**
 * MCP Integration Plugin for OpenClaw
 * Connects to MCP servers via Streamable HTTP transport
 */
class MCPManager {
  constructor(logger) {
    this.logger = logger;
    this.clients = new Map();
    this.tools = new Map();
  }

  async connectServer(name, config) {
    try {
      const url = config.url;
      let safeUrl = url;
      try {
        const u = new URL(url);
        u.password = '';
        u.username = '';
        safeUrl = u.toString();
      } catch (e) {
        // invalid url, just keep it as is or mask it
      }
      this.logger.info(`[MCP] Connecting to ${name} at ${safeUrl}`);

      const transport = new StreamableHTTPClientTransport(url);

      const client = new Client(
        { name: `openclaw-${name}`, version: '0.1.0' },
        { capabilities: {} }
      );

      await client.connect(transport);

      const { tools } = await client.listTools();

      this.clients.set(name, { client, transport });

      tools.forEach(tool => {
        this.tools.set(`${name}:${tool.name}`, {
          server: name,
          tool,
          client
        });
      });

      this.logger.info(`[MCP] Connected to ${name}: ${tools.length} tools available`);
      return tools;
    } catch (error) {
      this.logger.error(`[MCP] Failed to connect to ${name}: ${error.message}`);
      throw error;
    }
  }

  async callTool(serverName, toolName, args = {}) {
    const toolKey = `${serverName}:${toolName}`;
    const entry = this.tools.get(toolKey);

    if (!entry) {
      throw new Error(`Tool not found: ${toolKey}. Available: ${Array.from(this.tools.keys()).join(', ')}`);
    }

    const result = await entry.client.callTool({ name: toolName, arguments: args });
    return result;
  }

  listTools() {
    const toolList = [];
    for (const [key, entry] of this.tools.entries()) {
      toolList.push({
        id: key,
        server: entry.server,
        name: entry.tool.name,
        description: entry.tool.description,
        inputSchema: entry.tool.inputSchema
      });
    }
    return toolList;
  }

  async disconnect() {
    for (const [name, { client }] of this.clients.entries()) {
      try {
        await client.close();
        this.logger.info(`[MCP] Disconnected from ${name}`);
      } catch (error) {
        this.logger.error(`[MCP] Error disconnecting from ${name}: ${error.message}`);
      }
    }
    this.clients.clear();
    this.tools.clear();
  }
}

/**
 * OpenClaw plugin entry point
 */
export default function register(api) {
  const mcpManager = new MCPManager(api.logger);

  api.registerService({
    id: 'mcp-integration',
    start: async () => {
      api.logger.info('[MCP] Starting...');

      const pluginConfig = api.config?.plugins?.entries?.['mcp-integration']?.config || {};
      const servers = pluginConfig.servers || {};

      for (const [name, config] of Object.entries(servers)) {
        if (config.enabled !== false && config.url) {
          try {
            await mcpManager.connectServer(name, config);
          } catch (error) {
            api.logger.error(`[MCP] Failed to initialize ${name}: ${error.message}`);
          }
        }
      }

      api.logger.info('[MCP] Started');
    },
    stop: async () => {
      api.logger.info('[MCP] Stopping...');
      await mcpManager.disconnect();
    }
  });

  api.registerTool({
    name: 'mcp',
    description: 'Call MCP (Model Context Protocol) server tools. Use action=list to see available tools, then action=call to invoke them.',
    parameters: {
      type: 'object',
      properties: {
        action: {
          type: 'string',
          enum: ['list', 'call'],
          description: 'Action: list or call'
        },
        server: {
          type: 'string',
          description: 'MCP server name (for call)'
        },
        tool: {
          type: 'string',
          description: 'Tool name (for call)'
        },
        args: {
          type: 'object',
          description: 'Tool arguments (for call)'
        }
      },
      required: ['action']
    },
    async execute(_id, params) {
      try {
        switch (params.action) {
          case 'list': {
            const tools = mcpManager.listTools();
            return {
              content: [{
                type: 'text',
                text: tools.length > 0
                  ? JSON.stringify(tools, null, 2)
                  : 'No MCP tools available. Check server connection.'
              }]
            };
          }

          case 'call': {
            if (!params.server || !params.tool) {
              throw new Error('server and tool are required for call action');
            }
            const result = await mcpManager.callTool(params.server, params.tool, params.args || {});
            return {
              content: [{
                type: 'text',
                text: JSON.stringify(result, null, 2)
              }]
            };
          }

          default:
            throw new Error(`Unknown action: ${params.action}`);
        }
      } catch (error) {
        return {
          content: [{ type: 'text', text: `Error: ${error.message}` }],
          isError: true
        };
      }
    }
  });

  api.logger.info('[MCP] Plugin registered');
}


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)