OpenClaw MCP Integration with n8n: Building Production-Grade Agentic AI Workflows
OpenClaw MCP Integration with n8n: Building Production-Grade Agentic AI Workflows
A comprehensive guide to bridging OpenClaw's autonomous agent capabilities with n8n's enterprise workflow automation through Model Context Protocol integration.
1. Introduction: The Agentic AI Revolution
The automation landscape has shifted dramatically. Where 2024 and 2025 focused on chatbots and simple LLM integrations, 2026 is the year of agentic AI—autonomous systems that don't just respond to prompts but actively pursue goals, make decisions, and execute complex multi-step workflows independently.
The Rise of OpenClaw
OpenClaw has emerged as the catalyst for this transformation. With over 60,000 GitHub stars in just weeks (according to GitHub metrics), it has become one of the fastest-growing open-source AI projects in history. But OpenClaw is more than hype—it's fundamentally changed how we think about personal AI assistants.
What makes OpenClaw different:
- True Autonomy: Unlike traditional chatbots, OpenClaw agents reason about goals and select their own next actions
- Multi-Channel Presence: Operates across WhatsApp, Telegram, Slack, Discord, Signal, iMessage, and 15+ messaging platforms
- Local-First Architecture: Self-hosted gateway that keeps your data under your control
- Agent-Native Design: Built for coding agents with tool use, persistent sessions, and memory
- Multi-Agent Routing: Routes different channels/peers to isolated agents with workspace separation
The MCP Connection
The Model Context Protocol (MCP), pioneered by Anthropic, has become the standard for AI agent tool integration. OpenClaw's adoption of MCP transforms it from a standalone assistant into a universal agent orchestrator that can leverage any MCP-compatible tool.
Why MCP matters:
┌─────────────────────────────────────────────────────────────────┐
│ MCP ARCHITECTURE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ MCP │ │ MCP │ │ Tools │ │
│ │ Client │◄───────►│ Server │◄───────►│ (n8n) │ │
│ │ │ │ │ │ │ │
│ │ OpenClaw │ │ Protocol │ │ Workflows │ │
│ │ Claude │ │ Bridge │ │ APIs │ │
│ │ Cursor │ │ │ │ Services │ │
│ └─────────────┘ └─────────────┘ └───────────┘ │
│ │
│ Standardized tool discovery, invocation, and context sharing │
│ │
└─────────────────────────────────────────────────────────────────┘
Enter n8n: The Enterprise Automation Layer
While OpenClaw excels at autonomous decision-making, n8n provides the robust workflow infrastructure that enterprises demand:
- 400+ Native Integrations: CRMs, databases, messaging platforms, APIs
- Visual Workflow Builder: Complex automations without sacrificing maintainability
- Self-Hosted Option: Data sovereignty and compliance requirements
- Enterprise-Grade Reliability: Production-tested at Fortune 500 scale
- Fair-Code License: Use freely, modify as needed, contribute back
The Integration Imperative
Combining OpenClaw's agentic intelligence with n8n's automation power creates a symbiotic system:
- OpenClaw handles: Natural language understanding, goal decomposition, decision-making
- n8n handles: Reliable execution, error handling, retries, enterprise integrations
- MCP bridges: Standardized protocol for seamless communication
Real-world impact:
- Customer Support: OpenClaw understands nuanced customer requests; n8n executes ticket creation, Slack notifications, and CRM updates
- Content Operations: OpenClaw plans content strategy; n8n orchestrates publishing, distribution, and analytics
- DevOps Automation: OpenClaw interprets deployment requests; n8n manages infrastructure changes with approval gates
- Sales Intelligence: OpenClaw researches prospects; n8n updates Salesforce, sends emails, schedules meetings
2. Understanding Model Context Protocol (MCP)
Before diving into implementation, let's understand MCP's architecture and why it's become the de facto standard for AI agent tooling.
MCP Core Concepts
1. Resources: Read-only data that agents can access
- Database queries
- API responses
- File contents
- Configuration data
2. Tools: Executable functions that agents can invoke
- Send emails
- Create calendar events
- Update CRM records
- Trigger CI/CD pipelines
3. Prompts: Pre-defined templates for common interactions
- Standardized request formats
- Consistent response structures
- Role-based instructions
MCP Message Flow
┌──────────────────────────────────────────────────────────────────┐
│ MCP REQUEST FLOW │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 1. DISCOVERY │
│ ┌─────────┐ List Tools/Resources ┌─────────┐ │
│ │ Client │ ──────────────────────► │ Server │ │
│ │ │ ◄────────────────────── │ │ │
│ └─────────┘ Tool Definitions └─────────┘ │
│ │
│ 2. INVOCATION │
│ ┌─────────┐ Call Tool (params) ┌─────────┐ │
│ │ Client │ ──────────────────────► │ Server │ │
│ │ │ ◄────────────────────── │ │ │
│ └─────────┘ Result/Error └─────────┘ │
│ │
│ 3. CONTEXT SHARING │
│ • Schema definitions │
│ • Error information │
│ • Progress updates │
│ • Resource subscriptions │
│ │
└──────────────────────────────────────────────────────────────────┘
Why MCP Over Traditional APIs?
| Aspect | Traditional API | MCP |
|---|---|---|
| Discovery | Manual documentation | Automatic introspection |
| Schema | Static OpenAPI specs | Runtime negotiation |
| Context | Request-only | Persistent sessions |
| Tools | Fixed endpoints | Dynamic registration |
| Errors | HTTP codes | Structured explanations |
| Streaming | Custom implementations | Built-in support |
MCP Server Types
1.stdio Transport: Local process communication
- Ideal for: Local development, CLI tools
- Latency: Microseconds
- Security: OS-level process isolation
2.SSE Transport: Server-Sent Events over HTTP
- Ideal for: Remote services, web applications
- Latency: Milliseconds
- Security: HTTPS + authentication tokens
3.WebSocket Transport: Bidirectional streaming
- Ideal for: Real-time applications
- Latency: Milliseconds
- Security: WSS + token validation
3. OpenClaw MCP Architecture
OpenClaw implements MCP as a first-class citizen, enabling seamless integration with any MCP-compatible tool or service.
OpenClaw MCP Features
Native MCP Client Support:
# OpenClaw MCP Configuration (mcp.yml)
servers:
# n8n MCP Server
n8n-automation:
command: node
args: ["/path/to/n8n-mcp-server/dist/index.js"]
env:
N8N_HOST: "https://n8n.company.internal"
N8N_API_KEY: "${N8N_API_KEY}"
# External Composio MCP
composio-tools:
url: "https://connect.composio.dev/mcp"
headers:
Authorization: "Bearer ${COMPOSIO_API_KEY}"
# Custom Enterprise MCP
enterprise-integrations:
command: python
args: ["-m", "enterprise_mcp_server"]
env:
DATABASE_URL: "${ENTERPRISE_DB_URL}"
Key Capabilities:
- Automatic Tool Discovery: OpenClaw discovers all available tools on startup
- Dynamic Tool Registration: New tools appear without restarts
- Tool Selection Intelligence: LLM chooses appropriate tools based on context
- Error Recovery: Automatic retry with exponential backoff
- Progress Reporting: Real-time updates on long-running operations
OpenClaw + MCP Workflow
┌─────────────────────────────────────────────────────────────────┐
│ OPENCLAW MCP INTEGRATION FLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User Message │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ OpenClaw │ 1. Parse intent, identify goal │
│ │ Gateway │ 2. Load conversation context │
│ │ │ 3. Determine required capabilities │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Tool Selection │ Analyze available MCP tools │
│ │ (LLM Reasoning)│ Select optimal tool sequence │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MCP Client │ Format MCP request │
│ │ Layer │ Invoke tool │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MCP Server │ Process request │
│ │ (n8n/Make/etc)│ Execute workflow/API call │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Result │ Parse response │
│ │ Processing │ Update context │
│ │ │ Generate user response │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Security Model
OpenClaw implements a defense-in-depth security approach for MCP:
1. Capability-Based Access:
// Tool capabilities define what operations are allowed
interface ToolCapabilities {
read: boolean; // Can read data
write: boolean; // Can modify data
execute: boolean; // Can trigger actions
admin: boolean; // Administrative functions
}
// Each MCP server registers with specific capabilities
const n8nServer = {
name: "n8n-automation",
capabilities: ["read", "write", "execute"],
restrictedWorkflows: ["production-deployments"] // Exclude sensitive workflows
};
2. Request Approval System:
# OpenClaw approval configuration
approvals:
high-risk-actions:
- pattern: "delete.*"
requires_approval: true
- pattern: "deploy.*production.*"
requires_approval: true
- pattern: "transfer.*funds.*"
requires_approval: true
approvers: ["finance-team"]
3. Audit Logging:
- Every MCP call logged with full context
- Immutable audit trail
- Integration with SIEM systems
- Compliance reporting (SOC2, GDPR, etc.)
4. Building the n8n MCP Server
Now let's build a production-ready MCP server that exposes n8n workflows as tools for OpenClaw.
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ N8N MCP SERVER │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ MCP Server Core │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
│ │ │ Tools │ │ Resources │ │ Prompts │ │ │
│ │ │ Registry │ │ Registry │ │ Registry │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │ │
│ │ │ │ │ │ │
│ │ ┌──────▼────────────────▼──────────────────▼────────┐ │ │
│ │ │ n8n API Integration Layer │ │ │
│ │ │ • Workflow Discovery │ │ │
│ │ │ • Execution Management │ │ │
│ │ │ • Credential Handling │ │ │
│ │ │ • Webhook Management │ │ │
│ │ └───────────────────────┬─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌───────────────────────▼─────────────────────────────┐ │ │
│ │ │ Authentication Layer │ │ │
│ │ │ • API Key Validation │ │ │
│ │ │ • OAuth 2.0 Support │ │ │
│ │ │ • JWT Token Verification │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Transport: stdio | SSE | WebSocket │
│ │
└─────────────────────────────────────────────────────────────────┘
Implementation: Step-by-Step
Step 1: Project Setup
# Create project directory
mkdir n8n-mcp-server
cd n8n-mcp-server
npm init -y
# Install dependencies
npm install @modelcontextprotocol/sdk zod dotenv winston
npm install -D @types/node typescript
# Initialize TypeScript
npx tsc --init
Step 2: Core Server Implementation
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { N8nClient } from "./n8n-client.js";
import { ToolRegistry } from "./tool-registry.js";
import { logger } from "./logger.js";
class N8nMcpServer {
private server: Server;
private n8nClient: N8nClient;
private toolRegistry: ToolRegistry;
constructor() {
this.n8nClient = new N8nClient({
baseUrl: process.env.N8N_HOST!,
apiKey: process.env.N8N_API_KEY!,
});
this.toolRegistry = new ToolRegistry(this.n8nClient);
this.server = new Server(
{
name: "n8n-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
this.setupHandlers();
}
private setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
const tools = await this.toolRegistry.getTools();
return { tools };
});
// Execute tool
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
logger.info(`Executing tool: ${name}`, { args });
try {
const result = await this.toolRegistry.executeTool(name, args);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
logger.error(`Tool execution failed: ${name}`, { error });
throw error;
}
});
// List available resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
const resources = await this.toolRegistry.getResources();
return { resources };
});
// Read resource
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
const content = await this.toolRegistry.readResource(uri);
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(content, null, 2),
},
],
};
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
logger.info("n8n MCP Server running on stdio");
}
}
// Start server
const server = new N8nMcpServer();
server.run().catch(console.error);
Step 3: n8n API Client
// src/n8n-client.ts
import { logger } from "./logger.js";
interface N8nConfig {
baseUrl: string;
apiKey: string;
}
interface Workflow {
id: string;
name: string;
active: boolean;
tags?: { name: string }[];
nodes?: any[];
}
interface ExecutionResult {
executionId: string;
status: "success" | "error" | "running";
data?: any;
error?: string;
}
export class N8nClient {
private config: N8nConfig;
constructor(config: N8nConfig) {
this.config = config;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${this.config.baseUrl}/api/v1${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
"X-N8N-API-KEY": this.config.apiKey,
"Content-Type": "application/json",
...options.headers,
},
});
if (!response.ok) {
throw new Error(`n8n API error: ${response.status} ${response.statusText}`);
}
return response.json();
}
async getWorkflows(): Promise<Workflow[]> {
const response = await this.request<{ data: Workflow[] }>("/workflows");
return response.data;
}
async getWorkflow(id: string): Promise<Workflow> {
return this.request<Workflow>(`/workflows/${id}`);
}
async executeWorkflow(
workflowId: string,
data: Record<string, any>
): Promise<ExecutionResult> {
logger.info(`Triggering workflow execution: ${workflowId}`);
// Use webhook if available, otherwise use direct execution
try {
const response = await this.request<ExecutionResult>(
`/workflows/${workflowId}/execute`,
{
method: "POST",
body: JSON.stringify(data),
}
);
return response;
} catch (error) {
// Fallback to webhook execution
return this.executeViaWebhook(workflowId, data);
}
}
private async executeViaWebhook(
workflowId: string,
data: Record<string, any>
): Promise<ExecutionResult> {
const webhookUrl = `${this.config.baseUrl}/webhook/${workflowId}`;
const response = await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`Webhook execution failed: ${response.statusText}`);
}
const result = await response.json();
return {
executionId: result.executionId || "webhook",
status: result.status || "success",
data: result,
};
}
async getExecution(executionId: string): Promise<ExecutionResult> {
return this.request<ExecutionResult>(`/executions/${executionId}`);
}
async getWorkflowExecutions(workflowId: string, limit = 10): Promise<ExecutionResult[]> {
const response = await this.request<{ data: ExecutionResult[] }>(
`/executions?filter[workflowId]=${workflowId}&limit=${limit}`
);
return response.data;
}
}
Step 4: Tool Registry
// src/tool-registry.ts
import { z } from "zod";
import { N8nClient } from "./n8n-client.js";
import { logger } from "./logger.js";
interface Tool {
name: string;
description: string;
inputSchema: z.ZodType<any>;
workflowId?: string;
tags: string[];
}
interface Resource {
uri: string;
name: string;
mimeType: string;
description?: string;
}
export class ToolRegistry {
private n8nClient: N8nClient;
private tools: Map<string, Tool> = new Map();
private resources: Map<string, Resource> = new Map();
constructor(n8nClient: N8nClient) {
this.n8nClient = n8nClient;
}
async initialize() {
await this.discoverWorkflows();
await this.registerStaticTools();
}
private async discoverWorkflows() {
logger.info("Discovering n8n workflows...");
try {
const workflows = await this.n8nClient.getWorkflows();
for (const workflow of workflows) {
// Only expose active workflows with MCP tag
if (!workflow.active) continue;
if (!workflow.tags?.some((t) => t.name === "mcp")) continue;
const toolName = this.sanitizeWorkflowName(workflow.name);
this.tools.set(toolName, {
name: toolName,
description: `Execute n8n workflow: ${workflow.name}`,
inputSchema: z.object({
data: z.record(z.any()).optional().describe("Workflow input data"),
waitForCompletion: z
.boolean()
.optional()
.default(true)
.describe("Wait for workflow completion"),
}),
workflowId: workflow.id,
tags: ["n8n", "workflow", ...(workflow.tags?.map((t) => t.name) || [])],
});
// Register as resource for execution history
this.resources.set(`execution-history://${workflow.id}`, {
uri: `execution-history://${workflow.id}`,
name: `${toolName}-history`,
mimeType: "application/json",
description: `Execution history for workflow: ${workflow.name}`,
});
}
logger.info(`Discovered ${this.tools.size} MCP-enabled workflows`);
} catch (error) {
logger.error("Failed to discover workflows", { error });
}
}
private registerStaticTools() {
// Tool: List all workflows
this.tools.set("list_workflows", {
name: "list_workflows",
description: "List all available n8n workflows with MCP tag",
inputSchema: z.object({
includeInactive: z.boolean().optional().default(false),
}),
tags: ["discovery", "metadata"],
});
// Tool: Get workflow status
this.tools.set("get_workflow_status", {
name: "get_workflow_status",
description: "Get the current status and recent executions of a workflow",
inputSchema: z.object({
workflowId: z.string().describe("ID of the workflow to check"),
}),
tags: ["monitoring", "status"],
});
// Tool: Search executions
this.tools.set("search_executions", {
name: "search_executions",
description: "Search workflow execution history with filters",
inputSchema: z.object({
workflowId: z.string().optional().describe("Filter by workflow ID"),
status: z.enum(["success", "error", "running"]).optional(),
since: z.string().optional().describe("ISO date string"),
limit: z.number().optional().default(10),
}),
tags: ["search", "history"],
});
}
private sanitizeWorkflowName(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]+/g, "_")
.replace(/^_+|_+$/g, "");
}
async getTools(): Promise<any[]> {
if (this.tools.size === 0) {
await this.initialize();
}
return Array.from(this.tools.values()).map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema: zodToJsonSchema(tool.inputSchema),
}));
}
async executeTool(name: string, args: any): Promise<any> {
const tool = this.tools.get(name);
if (!tool) {
throw new Error(`Tool not found: ${name}`);
}
// Validate input
const validated = tool.inputSchema.parse(args);
switch (name) {
case "list_workflows":
return this.handleListWorkflows(validated);
case "get_workflow_status":
return this.handleGetWorkflowStatus(validated);
case "search_executions":
return this.handleSearchExecutions(validated);
default:
if (tool.workflowId) {
return this.handleWorkflowExecution(tool, validated);
}
throw new Error(`Unknown tool: ${name}`);
}
}
private async handleListWorkflows(args: any) {
const workflows = await this.n8nClient.getWorkflows();
return workflows
.filter((w) => args.includeInactive || w.active)
.map((w) => ({
id: w.id,
name: w.name,
active: w.active,
tags: w.tags?.map((t) => t.name) || [],
}));
}
private async handleGetWorkflowStatus(args: any) {
const workflow = await this.n8nClient.getWorkflow(args.workflowId);
const executions = await this.n8nClient.getWorkflowExecutions(
args.workflowId,
5
);
return {
workflow: {
id: workflow.id,
name: workflow.name,
active: workflow.active,
},
recentExecutions: executions,
};
}
private async handleSearchExecutions(args: any) {
if (args.workflowId) {
return this.n8nClient.getWorkflowExecutions(args.workflowId, args.limit);
}
// Implement broader search if needed
return [];
}
private async handleWorkflowExecution(tool: Tool, args: any) {
if (!tool.workflowId) {
throw new Error(`Workflow ID not configured for tool: ${tool.name}`);
}
const result = await this.n8nClient.executeWorkflow(
tool.workflowId,
args.data || {}
);
if (args.waitForCompletion && result.executionId) {
// Poll for completion
return this.waitForExecution(result.executionId);
}
return result;
}
private async waitForExecution(
executionId: string,
maxAttempts = 30,
intervalMs = 1000
): Promise<any> {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const execution = await this.n8nClient.getExecution(executionId);
if (execution.status !== "running") {
return execution;
}
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}
throw new Error(`Execution timeout: ${executionId}`);
}
async getResources(): Promise<Resource[]> {
return Array.from(this.resources.values());
}
async readResource(uri: string): Promise<any> {
const resource = this.resources.get(uri);
if (!resource) {
throw new Error(`Resource not found: ${uri}`);
}
const workflowId = uri.replace("execution-history://", "");
return this.n8nClient.getWorkflowExecutions(workflowId, 50);
}
}
// Helper: Convert Zod schema to JSON Schema
function zodToJsonSchema(schema: z.ZodType<any>): any {
return {
type: "object",
properties: {},
// Simplified - use zod-to-json-schema library for full conversion
};
}
Step 5: Configuration and Deployment
// src/logger.ts
import winston from "winston";
export const logger = winston.createLogger({
level: process.env.LOG_LEVEL || "info",
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: "logs/error.log", level: "error" }),
new winston.transports.File({ filename: "logs/combined.log" }),
],
});
// package.json
{
"name": "n8n-mcp-server",
"version": "1.0.0",
"description": "MCP server for n8n workflow automation",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsc --watch & nodemon dist/index.js",
"lint": "eslint src/**/*.ts",
"test": "vitest"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.5.0",
"dotenv": "^16.3.1",
"winston": "^3.11.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20.10.0",
"nodemon": "^3.0.2",
"typescript": "^5.3.3",
"vitest": "^1.1.0"
}
}
5. OpenClaw Configuration for n8n MCP
Now let's configure OpenClaw to use our n8n MCP server.
Configuration File Structure
# ~/.config/openclaw/mcp.yml
servers:
# Primary n8n MCP Server
n8n-enterprise:
command: node
args:
- "/opt/n8n-mcp-server/dist/index.js"
env:
N8N_HOST: "https://n8n.company.internal"
N8N_API_KEY: "${N8N_API_KEY}"
LOG_LEVEL: "info"
disabled: false
autoApprove: [] # Require approval for all actions
# Development n8n Instance
n8n-dev:
command: node
args:
- "/opt/n8n-mcp-server/dist/index.js"
env:
N8N_HOST: "https://n8n-dev.company.internal"
N8N_API_KEY: "${N8N_DEV_API_KEY}"
LOG_LEVEL: "debug"
disabled: false
autoApprove:
- "list_workflows" # Safe to auto-approve
- "get_workflow_status"
# External Composio (for additional tools)
composio:
url: "https://connect.composio.dev/mcp"
headers:
Authorization: "Bearer ${COMPOSIO_API_KEY}"
disabled: false
Environment Variables
# ~/.config/openclaw/.env
# Production n8n
N8N_HOST=https://n8n.company.internal
N8N_API_KEY=n8n_api_xxxxx
# Development n8n
N8N_DEV_API_KEY=n8n_api_yyyyy
# Composio
COMPOSIO_API_KEY=composio_zzzzz
# Logging
LOG_LEVEL=info
Runtime Verification
# Verify MCP servers are loaded
openclaw mcp status
# Expected output:
# ┌─────────────────┬─────────┬────────────┬─────────────────────────┐
# │ Server │ Status │ Tools │ Last Health Check │
# ├─────────────────┼─────────┼────────────┼─────────────────────────┤
# │ n8n-enterprise │ ● ready │ 12 tools │ 2026-05-27 09:30:15 UTC │
# │ n8n-dev │ ● ready │ 8 tools │ 2026-05-27 09:30:15 UTC │
# │ composio │ ● ready │ 156 tools │ 2026-05-27 09:30:14 UTC │
# └─────────────────┴─────────┴────────────┴─────────────────────────┘
# Test tool invocation
openclaw mcp test n8n-enterprise list_workflows
6. Real-World Use Cases and Examples
Let's explore practical implementations combining OpenClaw and n8n through MCP.
Use Case 1: Intelligent Customer Support
Scenario: Customer sends a support request via WhatsApp
┌─────────────────────────────────────────────────────────────────┐
│ CUSTOMER SUPPORT AUTOMATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Customer Message (WhatsApp) │
│ "Hi, I was charged twice for order #12345" │
│ │ │
│ ▼ │
│ 2. OpenClaw Analysis │
│ • Intent: billing_issue │
│ • Entities: order_id=12345, issue=duplicate_charge │
│ • Sentiment: concerned │
│ • Priority: high (billing) │
│ │ │
│ ▼ │
│ 3. MCP Tool Invocation │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Tool: lookup_order │ │
│ │ Params: { order_id: "12345" } │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 4. n8n Workflow Execution │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • Query Shopify for order details │ │
│ │ • Check Stripe for payment records │ │
│ │ • Verify duplicate charge │ │
│ │ • Create Zendesk ticket │ │
│ │ • Calculate refund amount │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 5. OpenClaw Response │
│ "I found your order #12345. You were indeed charged twice │
│ ($89.99 x 2). I've created ticket #Z-4567 and initiated │
│ a refund for the duplicate charge. You should see the │
│ refund in 3-5 business days. Is there anything else I │
│ can help you with?" │
│ │
└─────────────────────────────────────────────────────────────────┘
n8n Workflow Structure:
{
"name": "Customer Support - Billing Issues",
"nodes": [
{
"type": "n8n-nodes-base.webhook",
"name": "MCP Trigger",
"webhookId": "billing-support"
},
{
"type": "n8n-nodes-base.shopify",
"name": "Get Order",
"operation": "get"
},
{
"type": "n8n-nodes-base.stripe",
"name": "Check Payments",
"operation": "getAllCharges"
},
{
"type": "n8n-nodes-base.zendesk",
"name": "Create Ticket",
"operation": "create"
},
{
"type": "n8n-nodes-base.if",
"name": "Duplicate Found?"
},
{
"type": "n8n-nodes-base.stripe",
"name": "Process Refund",
"operation": "refund"
}
],
"tags": ["mcp", "customer-support", "billing"]
}
Use Case 2: Sales Intelligence and Lead Enrichment
Scenario: Sales rep mentions a prospect in Slack
┌─────────────────────────────────────────────────────────────────┐
│ SALES INTELLIGENCE WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Slack Message: │
│ "Talking to Acme Corp next week, anyone know them?" │
│ │
│ OpenClaw Actions: │
│ 1. Parse: prospect="Acme Corp" │
│ 2. Invoke MCP tools: │
│ • enrich_company_data │
│ • find_similar_customers │
│ • get_competitive_intel │
│ • check_existing_opportunity │
│ │
│ n8n Parallel Execution: │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
│ │ Clearbit API │ │ LinkedIn │ │ Salesforce │ │
│ │ • Company size │ │ • Key contacts │ │ • Opp history │ │
│ │ • Industry │ │ • Mutual conns │ │ • Similar wins │ │
│ │ • Technologies │ │ • Recent posts │ │ • Win rate │ │
│ └─────────────────┘ └─────────────────┘ └──────────────────┘ │
│ │
│ OpenClaw Response (Slack): │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 🎯 Acme Corp Intelligence Report ││
│ │ ││
│ │ **Company**: 500 employees, Series C, SaaS/FinTech ││
│ │ **Tech Stack**: AWS, Salesforce, Segment, Zendesk ││
│ │ **Similar Wins**: TechCorp (closed $250K), InnovateLtd ││
│ │ ││
│ │ **Key Contacts**: ││
│ │ • Sarah Chen (CTO) - Former colleague of ours! ││
│ │ • Mike Ross (VP Sales) - Posted about automation needs ││
│ │ ││
│ │ **Opportunity**: $150K ARR potential, 85% win rate for ││
│ │ similar profiles. No existing opp in Salesforce. ││
│ │ ││
│ │ [View Full Report] [Create Opportunity] [Schedule Meeting] ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘
Use Case 3: DevOps Automation with Human-in-the-Loop
Scenario: Developer asks OpenClaw to deploy a hotfix
┌─────────────────────────────────────────────────────────────────┐
│ DEVOPS AUTOMATION WITH APPROVAL │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Developer (Discord): │
│ "@Claw deploy hotfix for payment bug to production" │
│ │
│ OpenClaw Processing: │
│ 1. Intent Analysis: deploy_hotfix │
│ 2. Context Gathering: │
│ • Current branch: hotfix/payment-gateway-fix │
│ • Last commit: 2 hours ago │
│ • CI status: ✅ passed │
│ • Tests: ✅ 247/247 passed │
│ │
│ 3. Risk Assessment: HIGH (production deployment) │
│ │
│ 4. Approval Request (Slack #deployments): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 🚀 Production Hotfix Deployment Request │ │
│ │ │ │
│ │ Branch: hotfix/payment-gateway-fix │ │
│ │ Commit: abc1234 - Fix critical payment processing bug │ │
│ │ Tests: ✅ All passing │ │
│ │ Rollback: Ready (previous image: prod-v2.3.1) │ │
│ │ │ │
│ │ Requested by: @developer via OpenClaw │ │
│ │ │ │
│ │ [Approve] [Reject] [Schedule for 2AM] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 5. On Approval → n8n Workflow: │
│ • Tag release: v2.3.2-hotfix │
│ • Build Docker image │
│ • Push to registry │
│ • Update Kubernetes deployment │
│ • Run smoke tests │
│ • Notify #general channel │
│ • Update status page │
│ │
│ 6. OpenClaw Confirmation: │
│ "✅ Hotfix deployed successfully to production (v2.3.2). │
│ Smoke tests passing. Deployment log: [link]" │
│ │
└─────────────────────────────────────────────────────────────────┘
Use Case 4: Content Operations at Scale
Scenario: Content team needs to publish across multiple channels
┌─────────────────────────────────────────────────────────────────┐
│ CONTENT DISTRIBUTION AUTOMATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Content Manager (Telegram): │
│ "Publish the blog post about MCP integration to all channels │
│ and schedule social media for next week" │
│ │
│ OpenClaw Actions: │
│ 1. Identify content: "blog post about MCP integration" │
│ → Found: draft-mcp-openclaw-guide.md │
│ │
│ 2. Content Enhancement: │
│ • Generate SEO metadata │
│ • Create social media snippets │
│ • Design featured image (via DALL-E) │
│ • Extract key quotes for Twitter/X threads │
│ │
│ 3. MCP Tool Invocations: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ publish_to_cms │ │
│ │ ├── WordPress: blog.tropical-media.work │ │
│ │ ├── Medium: @tropicalmedia │ │
│ │ └── Dev.to: @tropicalmedia │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ schedule_social_posts │ │
│ │ ├── Twitter: 5 posts over next week │ │
│ │ ├── LinkedIn: 2 posts (Monday, Thursday) │ │
│ │ └── HackerNews: Submit Thursday 9AM EST │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ notify_team │ │
│ │ ├── Slack #content: "Published: MCP Guide" │ │
│ │ ├── Email newsletter: Schedule for tomorrow │ │
│ │ └── Analytics: Track performance │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 4. Result Summary: │
│ "✅ Published to 3 CMS platforms │
│ ✅ Scheduled 7 social media posts (May 28 - June 3) │
│ ✅ Newsletter queued for tomorrow │
│ ✅ Analytics tracking enabled │
│ 📊 Dashboard: [link]" │
│ │
└─────────────────────────────────────────────────────────────────┘
7. Security Best Practices
Security is paramount when connecting autonomous AI agents to enterprise systems.
Authentication and Authorization
1. API Key Management:
// Secure credential storage with rotation
interface CredentialManager {
// Store encrypted credentials
store(key: string, value: string, metadata: CredentialMetadata): Promise<void>;
// Retrieve with audit logging
retrieve(key: string, requestContext: RequestContext): Promise<string>;
// Automatic rotation
rotate(key: string): Promise<void>;
// Revocation
revoke(key: string): Promise<void>;
}
// Implementation using HashiCorp Vault
class VaultCredentialManager implements CredentialManager {
async store(key: string, value: string, metadata: CredentialMetadata) {
await vault.kv.v2.createOrUpdateSecret({
path: `n8n-mcp/${key}`,
secret: { value },
metadata: {
rotation_schedule: metadata.rotationSchedule,
last_rotated: new Date().toISOString(),
created_by: metadata.createdBy,
},
});
}
}
2. Scope-Based Permissions:
# Permission matrix
permissions:
# Read-only operations
viewer:
tools:
- list_workflows
- get_workflow_status
- search_executions
resources:
- "execution-history://*"
# Standard user operations
operator:
extends: viewer
tools:
- execute_workflow
workflows:
- "*"
exclude_workflows:
- "production-deployments"
- "finance-reports"
# Administrative operations
admin:
tools:
- "*"
workflows:
- "*"
resources:
- "*"
3. Request Validation:
// Input sanitization and validation
class RequestValidator {
private maxPayloadSize = 10 * 1024 * 1024; // 10MB
private allowedCharacters = /^[\w\s\-\.\@\+\=\{\}\[\]\:\"\'\,]+$/;
validate(request: ToolRequest): ValidationResult {
const errors: string[] = [];
// Size check
const payloadSize = JSON.stringify(request.arguments).length;
if (payloadSize > this.maxPayloadSize) {
errors.push(`Payload exceeds maximum size (${this.maxPayloadSize} bytes)`);
}
// Character validation
for (const [key, value] of Object.entries(request.arguments)) {
if (typeof value === "string" && !this.allowedCharacters.test(value)) {
errors.push(`Invalid characters in parameter: ${key}`);
}
}
// SQL injection prevention
if (this.containsSQLInjection(request.arguments)) {
errors.push("Potential SQL injection detected");
}
// Command injection prevention
if (this.containsCommandInjection(request.arguments)) {
errors.push("Potential command injection detected");
}
return {
valid: errors.length === 0,
errors,
};
}
private containsSQLInjection(args: any): boolean {
const sqlPatterns = [
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\b)/i,
/(\b(UNION|JOIN|WHERE|HAVING|ORDER|GROUP)\b)/i,
/(--|#|\/\*|\*\/)/,
];
const stringified = JSON.stringify(args);
return sqlPatterns.some((pattern) => pattern.test(stringified));
}
private containsCommandInjection(args: any): boolean {
const cmdPatterns = [
/[;&|`$()]/,
/(\b(rm|chmod|sudo|curl|wget|nc|python|bash|sh)\b)/i,
];
const stringified = JSON.stringify(args);
return cmdPatterns.some((pattern) => pattern.test(stringified));
}
}
Audit Logging and Compliance
Comprehensive Audit Trail:
interface AuditEvent {
timestamp: string;
eventType: "tool_invocation" | "tool_result" | "error" | "approval";
serverName: string;
toolName: string;
userId: string;
sessionId: string;
requestId: string;
arguments: any;
result?: any;
error?: string;
durationMs: number;
clientInfo: {
ip: string;
userAgent: string;
};
}
class AuditLogger {
async log(event: AuditEvent) {
// Write to immutable log store
await this.writeToLogStore(event);
// Real-time alerting for anomalies
if (this.isAnomalous(event)) {
await this.sendSecurityAlert(event);
}
// SIEM integration
await this.forwardToSIEM(event);
// Compliance export
await this.updateComplianceIndex(event);
}
private isAnomalous(event: AuditEvent): boolean {
// Detect unusual patterns
const rules = [
// High-frequency invocations
() => this.checkRateAnomaly(event),
// Sensitive workflow access
() => this.checkSensitiveAccess(event),
// Off-hours activity
() => this.checkTimeAnomaly(event),
// Failed authentication patterns
() => this.checkAuthFailures(event),
];
return rules.some((rule) => rule());
}
}
Network Security
Transport Layer Security:
# mcp.yml with TLS configuration
servers:
n8n-enterprise:
command: node
args: ["/opt/n8n-mcp-server/dist/index.js"]
env:
N8N_HOST: "https://n8n.company.internal"
N8N_API_KEY: "${N8N_API_KEY}"
# TLS Configuration
NODE_TLS_REJECT_UNAUTHORIZED: "1"
CA_CERT_PATH: "/etc/ssl/certs/ca.crt"
# Network restrictions
network:
allowedHosts:
- "n8n.company.internal"
- "n8n-dev.company.internal"
deniedHosts:
- "*.external-service.com"
maxConnections: 100
connectionTimeout: 30000
8. Production Deployment
Deploying OpenClaw MCP integration requires careful planning for scalability, reliability, and maintainability.
Deployment Architecture
┌─────────────────────────────────────────────────────────────────┐
│ PRODUCTION DEPLOYMENT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Load Balancer │ │
│ │ (nginx / HAProxy / Traefik) │ │
│ └─────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ │ │ │ │
│ ┌───────▼──────┐ ┌──────▼──────┐ ┌───────▼──────┐ │
│ │ OpenClaw │ │ OpenClaw │ │ OpenClaw │ │
│ │ Gateway #1 │ │ Gateway #2 │ │ Gateway #3 │ │
│ │ │ │ │ │ │ │
│ │ Container │ │ Container │ │ Container │ │
│ └───────┬──────┘ └──────┬──────┘ └───────┬──────┘ │
│ │ │ │ │
│ └────────────────┼─────────────────┘ │
│ │ │
│ ┌────────────────────────▼──────────────────────────┐ │
│ │ Redis Cluster │ │
│ │ (Session State / Message Queue) │ │
│ └────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────┐ │
│ │ MCP Server Pool │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ MCP Server │ │ MCP Server │ │ │
│ │ │ Instance #1 │ │ Instance #2 │ ... │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ └──────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────┐ │
│ │ n8n Cluster │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ n8n Worker │ │ n8n Worker │ │ │
│ │ │ Instance #1 │ │ Instance #2 │ ... │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ Supporting Infrastructure: │
│ • PostgreSQL (n8n persistence) │
│ • Prometheus + Grafana (monitoring) │
│ • Vault (secrets management) │
│ • ELK Stack (log aggregation) │
│ │
└─────────────────────────────────────────────────────────────────┘
Docker Compose Configuration
# docker-compose.yml
version: "3.8"
services:
# OpenClaw Gateway
openclaw:
image: openclaw/openclaw:latest
container_name: openclaw-gateway
restart: unless-stopped
environment:
- OPENCLAW_CONFIG_PATH=/config
- N8N_API_KEY=${N8N_API_KEY}
- REDIS_URL=redis://redis:6379
volumes:
- ./config:/config:ro
- openclaw-data:/data
depends_on:
- redis
networks:
- openclaw-network
deploy:
replicas: 3
resources:
limits:
cpus: "2"
memory: 4G
# MCP Server
n8n-mcp-server:
image: company/n8n-mcp-server:latest
container_name: n8n-mcp
restart: unless-stopped
environment:
- N8N_HOST=${N8N_HOST}
- N8N_API_KEY=${N8N_API_KEY}
- LOG_LEVEL=info
networks:
- openclaw-network
- n8n-network
deploy:
replicas: 2
resources:
limits:
cpus: "1"
memory: 2G
# Redis for session state
redis:
image: redis:7-alpine
container_name: openclaw-redis
restart: unless-stopped
volumes:
- redis-data:/data
networks:
- openclaw-network
command: redis-server --appendonly yes --maxmemory 2gb --maxmemory-policy allkeys-lru
# n8n (simplified - assumes external cluster or compose)
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- WEBHOOK_URL=${WEBHOOK_URL}
volumes:
- n8n-data:/home/node/.n8n
depends_on:
- postgres
networks:
- n8n-network
# PostgreSQL for n8n
postgres:
image: postgres:15-alpine
container_name: n8n-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=n8n
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- n8n-network
# Monitoring
prometheus:
image: prom/prometheus:latest
container_name: openclaw-prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- openclaw-network
grafana:
image: grafana/grafana:latest
container_name: openclaw-grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
networks:
- openclaw-network
networks:
openclaw-network:
driver: bridge
n8n-network:
driver: bridge
volumes:
openclaw-data:
redis-data:
n8n-data:
postgres-data:
prometheus-data:
grafana-data:
Kubernetes Deployment
# k8s/openclaw-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: openclaw-gateway
namespace: automation
spec:
replicas: 3
selector:
matchLabels:
app: openclaw
template:
metadata:
labels:
app: openclaw
spec:
containers:
- name: openclaw
image: openclaw/openclaw:latest
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "4Gi"
cpu: "2000m"
env:
- name: N8N_API_KEY
valueFrom:
secretKeyRef:
name: openclaw-secrets
key: n8n-api-key
- name: REDIS_URL
value: "redis://redis:6379"
volumeMounts:
- name: config
mountPath: /config
readOnly: true
- name: data
mountPath: /data
volumes:
- name: config
configMap:
name: openclaw-config
- name: data
persistentVolumeClaim:
claimName: openclaw-data
---
apiVersion: v1
kind: Service
metadata:
name: openclaw
namespace: automation
spec:
selector:
app: openclaw
ports:
- port: 3000
targetPort: 3000
type: ClusterIP
---
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: openclaw-hpa
namespace: automation
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: openclaw-gateway
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# k8s/n8n-mcp-server.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n-mcp-server
namespace: automation
spec:
replicas: 2
selector:
matchLabels:
app: n8n-mcp
template:
metadata:
labels:
app: n8n-mcp
spec:
containers:
- name: mcp-server
image: company/n8n-mcp-server:latest
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
env:
- name: N8N_HOST
value: "https://n8n.internal"
- name: N8N_API_KEY
valueFrom:
secretKeyRef:
name: n8n-mcp-secrets
key: api-key
livenessProbe:
exec:
command:
- node
- -e
- "require('http').get('http://localhost:3000/health', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))"
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- node
- -e
- "require('http').get('http://localhost:3000/ready', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))"
initialDelaySeconds: 5
periodSeconds: 5
9. Monitoring and Observability
Comprehensive monitoring is essential for production MCP deployments.
Metrics to Track
1. MCP Server Metrics:
// Prometheus metrics
import { Counter, Histogram, Gauge } from "prom-client";
const mcpMetrics = {
// Tool invocation metrics
toolInvocations: new Counter({
name: "mcp_tool_invocations_total",
help: "Total number of tool invocations",
labelNames: ["server", "tool", "status"],
}),
// Execution duration
executionDuration: new Histogram({
name: "mcp_execution_duration_seconds",
help: "Duration of tool executions",
labelNames: ["server", "tool"],
buckets: [0.1, 0.5, 1, 2, 5, 10, 30, 60],
}),
// Active connections
activeConnections: new Gauge({
name: "mcp_active_connections",
help: "Number of active MCP connections",
labelNames: ["server"],
}),
// Tool discovery metrics
toolDiscoveryTime: new Histogram({
name: "mcp_tool_discovery_duration_seconds",
help: "Time to discover available tools",
labelNames: ["server"],
}),
// Error rates
errorRate: new Counter({
name: "mcp_errors_total",
help: "Total number of MCP errors",
labelNames: ["server", "error_type"],
}),
};
2. n8n Integration Metrics:
const n8nMetrics = {
// Workflow execution
workflowExecutions: new Counter({
name: "n8n_workflow_executions_total",
help: "Total n8n workflow executions",
labelNames: ["workflow", "status", "trigger"],
}),
// Execution duration
workflowDuration: new Histogram({
name: "n8n_workflow_duration_seconds",
help: "Duration of workflow executions",
labelNames: ["workflow"],
}),
// Queue depth
queueDepth: new Gauge({
name: "n8n_queue_depth",
help: "Number of pending executions",
}),
// API latency
apiLatency: new Histogram({
name: "n8n_api_latency_seconds",
help: "n8n API response latency",
labelNames: ["endpoint", "method"],
}),
};
Health Checks
// Health check endpoint
interface HealthStatus {
status: "healthy" | "degraded" | "unhealthy";
checks: {
mcpConnection: ComponentHealth;
n8nApi: ComponentHealth;
database: ComponentHealth;
memory: ComponentHealth;
};
timestamp: string;
}
class HealthChecker {
async check(): Promise<HealthStatus> {
const checks = await Promise.all([
this.checkMcpConnection(),
this.checkN8nApi(),
this.checkDatabase(),
this.checkMemory(),
]);
const overallStatus = this.determineOverallStatus(checks);
return {
status: overallStatus,
checks: {
mcpConnection: checks[0],
n8nApi: checks[1],
database: checks[2],
memory: checks[3],
},
timestamp: new Date().toISOString(),
};
}
private async checkMcpConnection(): Promise<ComponentHealth> {
try {
const start = Date.now();
await this.mcpClient.ping();
const latency = Date.now() - start;
return {
status: latency < 1000 ? "healthy" : "degraded",
latency: `${latency}ms`,
message: "MCP connection active",
};
} catch (error) {
return {
status: "unhealthy",
message: `MCP connection failed: ${error.message}`,
};
}
}
private determineOverallStatus(checks: ComponentHealth[]): HealthStatus["status"] {
if (checks.every((c) => c.status === "healthy")) return "healthy";
if (checks.some((c) => c.status === "unhealthy")) return "unhealthy";
return "degraded";
}
}
Alerting Rules
# prometheus/alerts.yml
groups:
- name: mcp_alerts
rules:
- alert: MCPHighErrorRate
expr: rate(mcp_errors_total[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "High MCP error rate"
description: "Error rate is {{ $value }} errors/sec for {{ $labels.server }}"
- alert: MCPHighLatency
expr: histogram_quantile(0.95, rate(mcp_execution_duration_seconds_bucket[5m])) > 30
for: 5m
labels:
severity: warning
annotations:
summary: "High MCP execution latency"
description: "95th percentile latency is {{ $value }}s"
- alert: N8NQueueBacklog
expr: n8n_queue_depth > 100
for: 10m
labels:
severity: warning
annotations:
summary: "n8n execution queue backlog"
description: "Queue depth is {{ $value }} executions"
- alert: MCPConnectionLoss
expr: mcp_active_connections == 0
for: 1m
labels:
severity: critical
annotations:
summary: "MCP connection lost"
description: "No active MCP connections"
10. Performance Optimization
Optimizing MCP-n8n integrations for high-throughput scenarios.
Caching Strategies
// Multi-layer caching
interface CacheStrategy {
// In-memory cache for hot data
l1: LRUCache<string, any>;
// Redis for distributed cache
l2: Redis;
// Persistent cache for tool definitions
l3: DatabaseCache;
}
class ToolCache {
private l1: LRUCache<string, ToolDefinition>;
private l2: Redis;
constructor() {
this.l1 = new LRUCache({
max: 1000,
ttl: 1000 * 60 * 5, // 5 minutes
});
this.l2 = new Redis(process.env.REDIS_URL);
}
async getToolDefinition(server: string, tool: string): Promise<ToolDefinition | null> {
const key = `tool:${server}:${tool}`;
// L1: Memory cache
const l1Value = this.l1.get(key);
if (l1Value) return l1Value;
// L2: Redis cache
const l2Value = await this.l2.get(key);
if (l2Value) {
const parsed = JSON.parse(l2Value);
this.l1.set(key, parsed);
return parsed;
}
return null;
}
async setToolDefinition(
server: string,
tool: string,
definition: ToolDefinition
): Promise<void> {
const key = `tool:${server}:${tool}`;
const value = JSON.stringify(definition);
// Update both caches
this.l1.set(key, definition);
await this.l2.setex(key, 3600, value); // 1 hour TTL
}
}
Connection Pooling
// HTTP connection pool for n8n API
class N8nConnectionPool {
private agent: Agent;
private maxSockets: number;
private maxFreeSockets: number;
private timeout: number;
constructor(config: PoolConfig) {
this.maxSockets = config.maxSockets || 50;
this.maxFreeSockets = config.maxFreeSockets || 10;
this.timeout = config.timeout || 30000;
this.agent = new Agent({
keepAlive: true,
maxSockets: this.maxSockets,
maxFreeSockets: this.maxFreeSockets,
timeout: this.timeout,
freeSocketTimeout: 30000,
});
}
async request(url: string, options: RequestInit): Promise<Response> {
return fetch(url, {
...options,
agent: this.agent,
});
}
getStats(): PoolStats {
return {
activeConnections: this.agent.activeConnections,
idleConnections: this.agent.idleConnections,
pendingRequests: this.agent.pendingRequests,
};
}
}
Batch Processing
// Batch multiple tool calls
class BatchProcessor {
private queue: QueuedRequest[] = [];
private batchSize: number;
private flushInterval: number;
private timer: NodeJS.Timeout | null = null;
constructor(config: BatchConfig) {
this.batchSize = config.batchSize || 10;
this.flushInterval = config.flushInterval || 100;
}
async enqueue(request: ToolRequest): Promise<ToolResult> {
return new Promise((resolve, reject) => {
this.queue.push({ request, resolve, reject });
if (this.queue.length >= this.batchSize) {
this.flush();
} else if (!this.timer) {
this.timer = setTimeout(() => this.flush(), this.flushInterval);
}
});
}
private async flush(): Promise<void> {
if (this.queue.length === 0) return;
const batch = this.queue.splice(0, this.batchSize);
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
try {
// Execute batch
const results = await this.executeBatch(batch.map((b) => b.request));
// Resolve individual promises
batch.forEach((item, index) => {
item.resolve(results[index]);
});
} catch (error) {
// Reject all on batch failure
batch.forEach((item) => item.reject(error));
}
}
private async executeBatch(requests: ToolRequest[]): Promise<ToolResult[]> {
// Parallel execution with concurrency limit
const limit = pLimit(5);
return Promise.all(
requests.map((req) => limit(() => this.executeTool(req)))
);
}
}
11. Troubleshooting Common Issues
Issue 1: Tool Discovery Failures
Symptoms: OpenClaw can't see n8n workflows
Diagnosis:
# Check MCP server logs
openclaw mcp logs n8n-enterprise
# Verify n8n API connectivity
curl -H "X-N8N-API-KEY: $N8N_API_KEY" \
$N8N_HOST/api/v1/workflows
# Check workflow tags
# Workflows MUST have "mcp" tag to be exposed
Resolution:
// Enhanced discovery with retry
async function discoverWorkflowsWithRetry(
n8nClient: N8nClient,
maxRetries = 3
): Promise<Workflow[]> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const workflows = await n8nClient.getWorkflows();
// Filter for MCP-enabled workflows
const mcpWorkflows = workflows.filter(
(w) => w.active && w.tags?.some((t) => t.name === "mcp")
);
if (mcpWorkflows.length === 0) {
console.warn("No MCP-tagged workflows found");
}
return mcpWorkflows;
} catch (error) {
if (attempt === maxRetries) throw error;
const delay = Math.pow(2, attempt) * 1000;
console.log(`Retry ${attempt}/${maxRetries} in ${delay}ms`);
await new Promise((r) => setTimeout(r, delay));
}
}
return [];
}
Issue 2: Execution Timeouts
Symptoms: Long-running workflows fail with timeout errors
Solutions:
// Implement async execution pattern
class AsyncExecutionManager {
async executeLongRunningWorkflow(
workflowId: string,
data: any,
maxWaitTime = 300000 // 5 minutes
): Promise<ExecutionResult> {
// Start execution
const { executionId } = await this.n8nClient.triggerWorkflow(
workflowId,
data
);
// Poll for completion
const startTime = Date.now();
while (Date.now() - startTime < maxWaitTime) {
const status = await this.n8nClient.getExecutionStatus(executionId);
if (status === "completed") {
return this.n8nClient.getExecutionResult(executionId);
}
if (status === "failed") {
throw new Error(`Workflow execution failed: ${executionId}`);
}
// Exponential backoff
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise((r) => setTimeout(r, delay));
}
// Return execution ID for async check
return {
status: "pending",
executionId,
message: "Execution in progress, check status later",
};
}
}
Issue 3: Authentication Errors
Symptoms: 401/403 errors when calling n8n API
Resolution:
// Token refresh logic
class TokenManager {
private token: string | null = null;
private expiresAt: number = 0;
private refreshPromise: Promise<string> | null = null;
async getToken(): Promise<string> {
// Return cached token if valid
if (this.token && Date.now() < this.expiresAt - 60000) {
return this.token;
}
// Deduplicate refresh requests
if (this.refreshPromise) {
return this.refreshPromise;
}
this.refreshPromise = this.refreshToken();
try {
this.token = await this.refreshPromise;
return this.token;
} finally {
this.refreshPromise = null;
}
}
private async refreshToken(): Promise<string> {
const response = await fetch(`${this.authUrl}/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: this.clientId,
client_secret: this.clientSecret,
}),
});
if (!response.ok) {
throw new Error(`Token refresh failed: ${response.statusText}`);
}
const data = await response.json();
this.expiresAt = Date.now() + data.expires_in * 1000;
return data.access_token;
}
}
Issue 4: Memory Leaks
Symptoms: Gradual memory growth requiring restarts
Diagnostic Commands:
# Monitor memory usage
watch -n 5 'docker stats --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"'
# Heap dump for analysis
node --heap-prof -e "require('./dist/index.js')"
# Memory profiling with clinic
clinic doctor -- node dist/index.js
Mitigation:
// Periodic memory cleanup
class MemoryManager {
private cleanupInterval: NodeJS.Timeout;
constructor(intervalMs = 60000) {
this.cleanupInterval = setInterval(() => this.cleanup(), intervalMs);
}
private cleanup(): void {
// Clear old execution contexts
const maxAge = 30 * 60 * 1000; // 30 minutes
const cutoff = Date.now() - maxAge;
for (const [id, context] of this.executionContexts) {
if (context.createdAt < cutoff) {
this.executionContexts.delete(id);
}
}
// Force garbage collection if available
if (global.gc) {
global.gc();
}
// Log memory stats
const usage = process.memoryUsage();
logger.info("Memory usage", {
heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
external: `${Math.round(usage.external / 1024 / 1024)}MB`,
});
}
destroy(): void {
clearInterval(this.cleanupInterval);
}
}
12. Future Trends and Roadmap
The MCP ecosystem is evolving rapidly. Here's what to expect:
1. Hermes Agent Integration
Hermes Agent, emerging as a major OpenClaw competitor, focuses on continuity and learning across sessions. Integration patterns:
// Future: Hermes + n8n MCP bridge
interface HermesIntegration {
// Shared memory across sessions
sharedContext: ContextStore;
// Learned workflow patterns
learnedPatterns: PatternLibrary;
// Cross-agent task delegation
delegateToN8n(task: Task): Promise<Result>;
}
2. Multi-Agent Orchestration
// Future: Agent-to-Agent (A2A) protocol integration
interface MultiAgentOrchestrator {
// Register multiple MCP servers
registerAgent(server: MCPServer): void;
// Dynamic agent selection
selectAgentForTask(task: Task): Promise<MCPServer>;
// Cross-agent context sharing
shareContext(from: string, to: string, context: any): void;
}
3. Edge Deployment
# Future: Edge MCP servers
edge:
deployment:
regions:
- us-east-1
- eu-west-1
- ap-southeast-1
replication:
min_instances: 2
max_instances: 10
latency_target: 50ms
13. Conclusion
The integration of OpenClaw with n8n through Model Context Protocol represents a paradigm shift in AI-powered automation. This combination delivers:
Key Benefits
- Unmatched Flexibility: OpenClaw's agentic reasoning + n8n's 400+ integrations
- Enterprise Reliability: Production-tested infrastructure with self-hosting options
- Security First: Defense-in-depth with audit trails and compliance features
- Developer Experience: Type-safe, well-documented, community-driven
- Future-Proof: Based on open standards (MCP) with active ecosystem growth
Getting Started Checklist
- Deploy n8n instance with MCP-tagged workflows
- Build and deploy MCP server using this guide
- Configure OpenClaw with MCP server connection
- Implement security policies and approval workflows
- Set up monitoring and alerting
- Train team on OpenClaw-n8n interaction patterns
- Document organization-specific use cases
- Plan for scaling and high availability
Resources
- OpenClaw Documentation: https://docs.openclaw.ai/
- MCP Specification: https://modelcontextprotocol.io/
- n8n MCP Node: Available in n8n 2025.x+
- Community: OpenClaw Discord, n8n Forum
- This Guide's Repository: https://github.com/tropical-media/openclaw-n8n-mcp-guide
Ready to build the future of agentic automation? Start with a single MCP-enabled workflow and iterate. The possibilities are limitless.
About Tropical Media
Tropical Media specializes in AI automation, n8n workflow development, and OpenClaw implementations for businesses worldwide. We help organizations harness the power of agentic AI to transform their operations.
🌐 https://tropical-media.work
📧 [email protected]
💬 Book a consultation: https://tropical-media.work/contact
AI Agent Orchestration at Scale: Event-Driven Architecture for Enterprise n8n Deployments
Master event-driven architecture patterns for AI agent orchestration using n8n, Apache Kafka, RabbitMQ, and Redis. Learn scalability patterns, saga implementations, CQRS, and production deployment strategies for 10,000+ events per second.
AI-Powered Customer Support: A Practical Guide
How to implement AI in your customer support workflow without losing the human touch — from chatbot triage to intelligent ticket routing and automated responses.