Eugene-WebDev/custom-n8n-mcp-server-wsl-claude-code
If you are the rightful owner of custom-n8n-mcp-server-wsl-claude-code and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
This document provides a comprehensive guide to setting up a Model Context Protocol (MCP) server using n8n and Claude Code, leveraging WSL on a Windows machine.
custom-n8n-mcp-server-wsl-claude-code
# Complete n8n MCP Server Setup Guide
Battle-tested setup guide with lessons learned and troubleshooting tips
š Table of Contents
- Architecture Overview
- Prerequisites
- Step 0: Install Claude Code
- Step 1: Prepare WSL Environment
- Step 2: Create MCP Server Project
- Step 3: Write the MCP Server Code
- Step 4: Build and Configure
- Step 5: Configure n8n Credentials
- Step 6: Connect Claude Code to MCP Server
- Step 7: Test Your Setup
- Troubleshooting
- Lessons Learned
Architecture Overview
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Windows 10 Machine ā
ā ā
ā āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Claude Code ā āāāāāāāāāāŗā WSL Ubuntu 24.04 ā ā
ā ā (Windows) ā ā ā ā
ā āāāāāāāāāāāāāāāāāāā ā āāāāāāāāāāāāāāāāāā ā ā
ā ā ā n8n MCP Server ā ā ā
ā ā ā (Node.js) ā ā ā
ā ā āāāāāāāāāā¬āāāāāāāā ā ā
ā āāāāāāāāāāāāā¼āāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāā
ā
ā HTTPS/API
ā¼
āāāāāāāāāāāāāāāāāāāāāāā
ā n8n Instance ā
ā (VPS/Cloud) ā
ā n8n.yoursite.com ā
āāāāāāāāāāāāāāāāāāāāāāā
Components:
- Claude Code: CLI tool running on Windows that you interact with
- MCP Server: Runs in WSL Ubuntu, acts as a bridge between Claude and n8n
- n8n: Your workflow automation tool hosted on a VPS
Why this architecture?
- MCP server runs locally for low latency with Claude Code
- Communicates with remote n8n via HTTP API (no VPN needed)
- Easy to develop and debug locally
Prerequisites
Required Software
- ā Windows 10/11 with WSL2 enabled
- ā WSL Ubuntu 24.04 distribution
- ā Node.js (will be installed in WSL)
- ā n8n instance with API access enabled
Required Access
- š n8n instance URL (e.g.,
https://n8n.yoursite.com
) - š n8n API key (generate from n8n Settings ā API)
Step 0: Install Claude Code
On Windows (PowerShell or Command Prompt)
# Install Claude Code globally via npm
npm install -g @anthropic-ai/claude-code
# Verify installation
claude code --version
š” Tip: If you don't have Node.js on Windows yet, download it from nodejs.org (LTS version recommended).
Step 1: Prepare WSL Environment
1.1 Install Node.js in WSL
Open WSL Ubuntu terminal:
# Navigate to home directory
cd ~
# Install Node.js 20 LTS (recommended)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs
# Verify installation
node --version # Should show v20.x.x
npm --version # Should show 10.x.x
ā ļø Common Issue: Docker Desktop may interfere with WSL environments. Make sure you're installing Node.js in the correct WSL distribution (Ubuntu-24.04).
š” Tip: Check your WSL distributions with:
wsl -l -v
Step 2: Create MCP Server Project
2.1 Initialize Project
In your WSL Ubuntu terminal:
# Create project directory
cd ~
mkdir n8n-mcp-server
cd n8n-mcp-server
# Initialize Node.js project
npm init -y
2.2 Install Dependencies
# Install MCP SDK and required packages
npm install @modelcontextprotocol/sdk axios dotenv
# Install TypeScript and type definitions
npm install -D @types/node typescript
Expected output:
- Should install ~100+ packages
- No vulnerabilities (or only low-severity ones)
2.3 Create TypeScript Configuration
Create tsconfig.json
:
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
EOF
2.4 Update package.json
# Set module type and scripts
npm pkg set type="module"
npm pkg set scripts.build="tsc"
npm pkg set scripts.start="node build/index.js"
Step 3: Write the MCP Server Code
3.1 Create Source Directory
mkdir src
3.2 Create the Server File
Create src/index.ts
with the following content:
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import * as dotenv from "dotenv";
dotenv.config();
const N8N_URL = process.env.N8N_URL || "http://your-vps-ip:5678";
const N8N_API_KEY = process.env.N8N_API_KEY || "";
const api = axios.create({
baseURL: `${N8N_URL}/api/v1`,
headers: {
"X-N8N-API-KEY": N8N_API_KEY,
},
});
const server = new Server(
{
name: "n8n-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "list_workflows",
description: "List all workflows in n8n",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "get_workflow",
description: "Get details of a specific workflow by ID",
inputSchema: {
type: "object",
properties: {
id: {
type: "string",
description: "Workflow ID",
},
},
required: ["id"],
},
},
{
name: "create_workflow",
description: "Create a new workflow",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "Workflow name",
},
nodes: {
type: "array",
description: "Array of workflow nodes",
},
connections: {
type: "object",
description: "Node connections",
},
settings: {
type: "object",
description: "Workflow settings",
},
},
required: ["name"],
},
},
{
name: "update_workflow",
description: "Update an existing workflow",
inputSchema: {
type: "object",
properties: {
id: {
type: "string",
description: "Workflow ID",
},
name: {
type: "string",
description: "Workflow name",
},
nodes: {
type: "array",
description: "Array of workflow nodes",
},
connections: {
type: "object",
description: "Node connections",
},
},
required: ["id"],
},
},
{
name: "delete_workflow",
description: "Delete a workflow by ID",
inputSchema: {
type: "object",
properties: {
id: {
type: "string",
description: "Workflow ID",
},
},
required: ["id"],
},
},
{
name: "activate_workflow",
description: "Activate a workflow",
inputSchema: {
type: "object",
properties: {
id: {
type: "string",
description: "Workflow ID",
},
},
required: ["id"],
},
},
{
name: "deactivate_workflow",
description: "Deactivate a workflow",
inputSchema: {
type: "object",
properties: {
id: {
type: "string",
description: "Workflow ID",
},
},
required: ["id"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
switch (request.params.name) {
case "list_workflows": {
const response = await api.get("/workflows");
return {
content: [
{
type: "text",
text: JSON.stringify(response.data, null, 2),
},
],
};
}
case "get_workflow": {
const { id } = request.params.arguments as { id: string };
const response = await api.get(`/workflows/${id}`);
return {
content: [
{
type: "text",
text: JSON.stringify(response.data, null, 2),
},
],
};
}
case "create_workflow": {
const workflowData = request.params.arguments;
const response = await api.post("/workflows", workflowData);
return {
content: [
{
type: "text",
text: `Workflow created successfully: ${JSON.stringify(response.data, null, 2)}`,
},
],
};
}
case "update_workflow": {
const { id, ...updateData } = request.params.arguments as any;
const response = await api.patch(`/workflows/${id}`, updateData);
return {
content: [
{
type: "text",
text: `Workflow updated successfully: ${JSON.stringify(response.data, null, 2)}`,
},
],
};
}
case "delete_workflow": {
const { id } = request.params.arguments as { id: string };
await api.delete(`/workflows/${id}`);
return {
content: [
{
type: "text",
text: `Workflow ${id} deleted successfully`,
},
],
};
}
case "activate_workflow": {
const { id } = request.params.arguments as { id: string };
await api.patch(`/workflows/${id}`, { active: true });
return {
content: [
{
type: "text",
text: `Workflow ${id} activated`,
},
],
};
}
case "deactivate_workflow": {
const { id } = request.params.arguments as { id: string };
await api.patch(`/workflows/${id}`, { active: false });
return {
content: [
{
type: "text",
text: `Workflow ${id} deactivated`,
},
],
};
}
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
} catch (error: any) {
return {
content: [
{
type: "text",
text: `Error: ${error.message}\n${error.response?.data ? JSON.stringify(error.response.data, null, 2) : ""}`,
},
],
isError: true,
};
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("n8n MCP Server running on stdio");
}
main();
ā ļø Important: If copying via bash heredoc, you may encounter issues with template literals (${}
). Instead:
- Use a text editor (nano, vim, or VS Code with WSL extension)
- Or have Claude Code create it via the Write tool
Step 4: Build and Configure
4.1 Compile TypeScript
cd ~/n8n-mcp-server
# Compile TypeScript to JavaScript
node ./node_modules/typescript/lib/tsc.js
# Verify build output
ls -la build/
Expected output:
build/index.js
file created (~8-9KB)- No compilation errors
ā ļø Common Issue: If you see "node: command not found", your shell environment isn't loading the PATH correctly. Try:
# Use login shell
bash -l
cd ~/n8n-mcp-server
node ./node_modules/typescript/lib/tsc.js
š” Alternative: You can also use:
npx tsc
# Or
npm run build
Step 5: Configure n8n Credentials
5.1 Get Your n8n API Key
- Open your n8n instance in a browser (e.g.,
https://n8n.yoursite.com
) - Go to Settings ā API
- Click Generate API Key
- Copy the key (you won't see it again!)
5.2 Create .env File
In WSL terminal:
cd ~/n8n-mcp-server
# Create .env file (use nano or your preferred editor)
nano .env
Add your credentials:
N8N_URL=https://n8n.yoursite.com
N8N_API_KEY=your-actual-api-key-here
š” Tips:
- Use
https://
if your n8n is behind a reverse proxy (SSL) - Use your subdomain if you have one (better than IP address)
- If using IP:
http://123.45.67.89:5678
(note the port!)
ā ļø Security: Never commit .env
to git! Add it to .gitignore
:
echo ".env" >> .gitignore
Step 6: Connect Claude Code to MCP Server
6.1 Create Claude Code Configuration
The config file should be at: C:\Users\YourUsername\.claude\claude_desktop_config.json
Create it with this content:
{
"mcpServers": {
"n8n": {
"command": "wsl",
"args": [
"-d",
"Ubuntu-24.04",
"--",
"bash",
"-c",
"cd ~/n8n-mcp-server && node build/index.js"
]
}
}
}
š” How to create this file:
Option 1: Via Claude Code (recommended)
- Ask Claude: "Create the MCP config file for me"
- Claude can use the Write tool to create it directly
Option 2: Manually
# In PowerShell
mkdir $env:USERPROFILE\.claude -Force
notepad $env:USERPROFILE\.claude\claude_desktop_config.json
# Paste the JSON content and save
ā ļø Important: Make sure the WSL distribution name matches yours. Check with:
wsl -l -v
If your distribution has a different name (e.g., "Ubuntu"), update the -d
parameter.
Step 7: Test Your Setup
7.1 Restart Claude Code
If Claude Code is already running, exit and restart it to load the new configuration.
# Exit current session (Ctrl+C or type 'exit')
# Start fresh
claude
7.2 Test MCP Tools
Try these commands with Claude:
"List all my n8n workflows"
"Show me the available n8n tools"
"Get details for workflow ID <your-workflow-id>"
Expected behavior:
- Claude should list your workflows
- You should see workflow data returned as JSON
- No connection errors
Troubleshooting
Issue: "node: command not found" in WSL
Cause: Node.js isn't installed or not in PATH
Solution:
# Check if Node.js is installed
which node
# If not found, install it:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs
Issue: "Cannot connect to n8n" or API errors
Possible causes:
- Wrong URL in
.env
- Invalid API key
- n8n API not enabled
- Firewall blocking your IP
Solutions:
Check 1: Test n8n API manually
# From WSL terminal
curl -H "X-N8N-API-KEY: your-api-key" https://n8n.yoursite.com/api/v1/workflows
Expected: JSON list of workflows If error: Check URL, API key, or firewall
Check 2: Verify .env file
cd ~/n8n-mcp-server
cat .env
Check 3: Enable n8n API
- In n8n, go to Settings ā API
- Make sure "API" is enabled
- Generate a fresh API key
Check 4: Firewall/VPS settings
- Ensure your VPS allows incoming connections on port 5678 (or 443 if using reverse proxy)
- Your home IP might need to be whitelisted
Issue: TypeScript compilation errors
Cause: Template literals not properly escaped when creating via bash heredoc
Solution:
Use Claude Code's Write tool or a text editor to create src/index.ts
instead of bash heredoc. The template literals (${}
) can get corrupted with certain bash escaping methods.
Issue: Claude Code doesn't see MCP tools
Possible causes:
- Config file in wrong location
- Syntax error in JSON
- WSL distribution name mismatch
Solutions:
Check 1: Verify config location
Get-Content $env:USERPROFILE\.claude\claude_desktop_config.json
Check 2: Validate JSON syntax Use a JSON validator or:
Get-Content $env:USERPROFILE\.claude\claude_desktop_config.json | ConvertFrom-Json
No error = valid JSON
Check 3: Verify WSL distribution name
wsl -l -v
Make sure the name in -d
parameter matches exactly (case-sensitive)
Issue: CMD.EXE or UNC path errors
Cause: Running npm/node commands from Windows CMD instead of pure WSL environment
Solution: Always run build commands from within WSL terminal:
# In WSL terminal (not Windows CMD/PowerShell)
cd ~/n8n-mcp-server
node ./node_modules/typescript/lib/tsc.js
Lessons Learned
ā Do's
-
Use subdomains over IP addresses
https://n8n.yoursite.com
is better thanhttp://123.45.67.89:5678
- More stable, easier to remember, better for SSL
-
Install Node.js in the correct WSL distribution
- Docker Desktop creates additional WSL distributions
- Always check with
wsl -l -v
which one you're using
-
Use login shells when PATH issues occur
bash -l
ensures environment variables are loaded- Helps with node/npm not found errors
-
Test API connectivity manually first
- Use
curl
to verify n8n API before debugging MCP server - Saves time identifying where the problem is
- Use
-
Let Claude Code create files when possible
- Avoids bash escaping issues with template literals
- Use the Write tool for complex files
ā Don'ts
-
Don't use bash heredoc for files with template literals
${}
syntax gets mangled by bash variable substitution- Use text editors or Claude's Write tool instead
-
Don't mix Windows and WSL node/npm
- Can cause PATH confusion
- Keep builds entirely in WSL
-
Don't forget to rebuild after code changes
- TypeScript needs compilation:
npm run build
- Changes in
src/
don't apply until built tobuild/
- TypeScript needs compilation:
-
Don't commit .env to version control
- Contains sensitive API keys
- Always add to
.gitignore
Advanced: Extending the MCP Server
Adding More n8n Operations
To add support for executions, credentials, or other n8n API endpoints:
- Add new tool definitions in
ListToolsRequestSchema
handler - Add corresponding case in
CallToolRequestSchema
handler - Rebuild:
npm run build
- Restart Claude Code to pick up changes
Example: List Executions
// In ListToolsRequestSchema handler, add to tools array:
{
name: "list_executions",
description: "List workflow executions",
inputSchema: {
type: "object",
properties: {
workflowId: {
type: "string",
description: "Filter by workflow ID (optional)"
}
}
}
}
// In CallToolRequestSchema handler, add new case:
case "list_executions": {
const { workflowId } = request.params.arguments as { workflowId?: string };
const url = workflowId
? `/executions?workflowId=${workflowId}`
: '/executions';
const response = await api.get(url);
return {
content: [
{
type: "text",
text: JSON.stringify(response.data, null, 2),
},
],
};
}
Useful Commands Reference
WSL Commands
# Enter WSL from Windows
wsl -d Ubuntu-24.04
# List WSL distributions
wsl -l -v
# Navigate to project
cd ~/n8n-mcp-server
# Check Node.js version
node --version
# Rebuild project
npm run build
# View .env file
cat .env
# Edit .env file
nano .env
Windows Commands
# Check Claude Code config
Get-Content $env:USERPROFILE\.claude\claude_desktop_config.json
# Access WSL files from Windows
explorer.exe \\wsl.localhost\Ubuntu-24.04\root\n8n-mcp-server
# Start Claude Code
claude
Security Best Practices
-
API Key Management
- Store in
.env
file only - Never hardcode in source files
- Rotate keys periodically
- Store in
-
Network Security
- Use HTTPS for n8n connection when possible
- Consider VPN or IP whitelisting for production
- Don't expose n8n API publicly without authentication
-
Access Control
- Use read-only API keys if only listing workflows
- Separate keys for dev/prod environments
Additional Resources
Summary
You now have:
- ā Claude Code installed on Windows
- ā MCP server running in WSL Ubuntu
- ā Connection to your n8n instance
- ā Ability to manage n8n workflows via Claude
Next steps:
- Ask Claude to list your workflows
- Create new workflows via natural language
- Integrate n8n automation into your development workflow
Created: October 2025 Tested on: Windows 10, WSL Ubuntu 24.04, n8n self-hosted Claude Code Version: Latest
This guide is based on real-world implementation with actual troubleshooting scenarios encountered during setup.