This is page 1 of 2. Use http://codebase.md/illuminaresolutions/n8n-mcp-server?page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── DEVELOPMENT.md
├── LICENSE
├── LLM_GUIDE.md
├── N8N_API.yml
├── package-lock.json
├── package.json
├── README.md
├── smithery.yml
├── src
│ └── index.ts
├── tsconfig.json
└── TYPEKIT_MCP_SDK.md
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# Build
build/
dist/
*.tsbuildinfo
# Dependencies
node_modules/
.pnp/
.pnp.js
.npm/
# Environment
.env
.env.local
.env.*.local
.env.development.local
.env.test.local
.env.production.local
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# IDE
.idea/
.vscode/
*.swp
*.swo
.project
.classpath
.settings/
*.sublime-workspace
*.sublime-project
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.ini
# Testing
coverage/
.nyc_output/
junit.xml
*.lcov
# Temporary files
*.tmp
*.temp
.cache/
.temp/
tmp/
# TypeScript
*.js.map
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# n8n MCP Server
An MCP server that provides access to n8n workflows, executions, credentials, and more through the Model Context Protocol. This allows Large Language Models (LLMs) to interact with n8n instances in a secure and standardized way.
## Installation
### Get your n8n API Key
1. Log into your n8n instance
2. Click your user icon in the bottom left
3. Go to Settings
4. Select API
5. Click "Create API Key"
6. Copy your API key (you won't be able to see it again)
### Install the MCP Server
#### Option 1: Install from npm (Recommended)
```bash
npm install -g @illuminaresolutions/n8n-mcp-server
```
#### Option 2: Install from Source
1. Clone the repository:
```bash
git clone https://github.com/illuminaresolutions/n8n-mcp-server.git
cd n8n-mcp-server
```
2. Install dependencies and build:
```bash
npm install
npm run build
```
3. Start the server in the background:
```bash
nohup npm start > n8n-mcp.log 2>&1 &
```
To stop the server:
```bash
pkill -f "node build/index.js"
```
Note: When installing from npm, the server will be available as `n8n-mcp-server` in your PATH.
## Configuration
### Claude Desktop
1. Open your Claude Desktop configuration:
```
~/Library/Application Support/Claude/claude_desktop_config.json
```
2. Add the n8n configuration:
```json
{
"mcpServers": {
"n8n": {
"command": "n8n-mcp-server",
"env": {
"N8N_HOST": "https://your-n8n-instance.com",
"N8N_API_KEY": "your-api-key-here"
}
}
}
}
```
### Cline (VS Code)
1. Install the server (follow Installation steps above)
2. Open VS Code
3. Open the Cline extension from the left sidebar
4. Click the 'MCP Servers' icon at the top of the pane
5. Scroll to bottom and click 'Configure MCP Servers'
6. Add to the opened settings file:
```json
{
"mcpServers": {
"n8n": {
"command": "n8n-mcp-server",
"env": {
"N8N_HOST": "https://your-n8n-instance.com",
"N8N_API_KEY": "your-api-key-here"
}
}
}
}
```
7. Save the file
8. Ensure the MCP toggle is enabled (green) and the status indicator is green
9. Start using MCP commands in Cline
### Sage
Coming soon! The n8n MCP server will be available through:
- Smithery.ai marketplace
- Import from Claude Desktop
For now, please use Claude Desktop or Cline.
## Validation
After configuration:
1. Restart your LLM application
2. Ask: "List my n8n workflows"
3. You should see your workflows listed
If you get an error:
- Check that your n8n instance is running
- Verify your API key has correct permissions
- Ensure N8N_HOST has no trailing slash
## Features
### Core Features
- List and manage workflows
- View workflow details
- Execute workflows
- Manage credentials
- Handle tags and executions
- Generate security audits
- Manage workflow tags
### Enterprise Features
These features require an n8n Enterprise license:
- Project management
- Variable management
- Advanced user management
## Troubleshooting
### Common Issues
1. "Client not initialized"
- Check N8N_HOST and N8N_API_KEY are set correctly
- Ensure n8n instance is accessible
- Verify API key permissions
2. "License required"
- You're trying to use an Enterprise feature
- Either upgrade to n8n Enterprise or use core features only
3. Connection Issues
- Verify n8n instance is running
- Check URL protocol (http/https)
- Remove trailing slash from N8N_HOST
## Security Best Practices
1. API Key Management
- Use minimal permissions necessary
- Rotate keys regularly
- Never commit keys to version control
2. Instance Access
- Use HTTPS for production
- Enable n8n authentication
- Keep n8n updated
## Support
- [GitHub Issues](https://github.com/illuminaresolutions/n8n-mcp-server/issues)
- [n8n Documentation](https://docs.n8n.io)
## License
[MIT License](LICENSE)
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "node",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true
},
"include": ["src/**/*"]
}
```
--------------------------------------------------------------------------------
/smithery.yml:
--------------------------------------------------------------------------------
```yaml
name: n8n-mcp-server
version: 1.0.0
description: An MCP server that provides access to n8n workflows, executions, credentials, and more through the Model Context Protocol
author: Illuminare Solutions
license: MIT
repository: https://github.com/illuminaresolutions/n8n-mcp-server
type: mcp-server
category: automation
requirements:
node: ">=18.0.0"
installation:
npm: "@illuminaresolutions/n8n-mcp-server"
configuration:
env:
N8N_HOST:
description: "Your n8n instance URL (e.g., https://your-n8n-instance.com)"
required: true
N8N_API_KEY:
description: "Your n8n API key"
required: true
secret: true
capabilities:
- workflow-management
- credential-management
- execution-monitoring
- tag-management
- security-audit
- user-management
- project-management
- variable-management
tags:
- n8n
- automation
- workflow
- mcp
- llm
- ai
- claude
documentation:
getting_started: https://github.com/illuminaresolutions/n8n-mcp-server#installation
configuration: https://github.com/illuminaresolutions/n8n-mcp-server#configuration
api_reference: https://github.com/illuminaresolutions/n8n-mcp-server/blob/main/N8N_API.yml
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "@illuminaresolutions/n8n-mcp-server",
"description": "An MCP server that provides access to n8n workflows, executions, credentials, and more through the Model Context Protocol",
"version": "1.0.0",
"type": "module",
"bin": {
"n8n-mcp-server": "build/index.js"
},
"files": [
"build",
"README.md",
"LICENSE"
],
"license": "MIT",
"author": "Illuminare Solutions",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/illuminaresolutions/n8n-mcp-server.git"
},
"bugs": {
"url": "https://github.com/illuminaresolutions/n8n-mcp-server/issues"
},
"homepage": "https://github.com/illuminaresolutions/n8n-mcp-server#readme",
"engines": {
"node": ">=18.0.0"
},
"keywords": [
"n8n",
"mcp",
"automation",
"workflow",
"llm",
"ai",
"claude",
"modelcontextprotocol"
],
"scripts": {
"build": "tsc && chmod +x build/index.js",
"start": "node build/index.js",
"prepublishOnly": "npm run build",
"clean": "rm -rf build",
"lint": "tsc --noEmit"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.7.0",
"zod": "^3.22.4",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@types/node": "^20.11.5",
"typescript": "^5.3.3"
}
}
```
--------------------------------------------------------------------------------
/DEVELOPMENT.md:
--------------------------------------------------------------------------------
```markdown
# Development Guide
## Core Principles
1. **Keep It Simple**
- Expand src/index.ts as needed - avoid complex directory structures
- Focus on core functionality first
- Use built-in Node.js features when possible
- Check N8N_API.yml for correct endpoints/methods
2. **Document Only What Works**
- No *public* "roadmap" or planned features
- Only document implemented functionality
- Keep documentation clear and focused
3. **JSON Requirements**
- All tool arguments must be compact, single-line JSON
- Example: `{"clientId":"abc123","id":"workflow123"}`
4. **Workflow Creation**
- Include nodes and connections arrays (even if empty)
- 'active' property is read-only
```json
{
"clientId": "abc123",
"name": "My Workflow",
"nodes": [],
"connections": {}
}
```
5. **Enterprise Features**
- Project/variable management require Enterprise license
- Base workflow features work without license
- Clear error messages for license requirements
## What Not To Do
1. **No Overcomplication**
- Don't create complex directory structures
- Don't add unnecessary dependencies
- Use built-in fetch instead of importing it
- Check if functionality exists before adding imports
2. **No Speculative Documentation**
- Don't document unimplemented features
- Don't maintain *public* planning documents
- Don't commit planning docs as implementation
3. **No Feature Creep**
- Add features only when fully designed
- Follow github repo's simple approach
- Focus on core functionality first
4. **No Roadmaps**
- Document only what exists
- Keep focus on current functionality
- Clear, concise documentation
```
--------------------------------------------------------------------------------
/TYPEKIT_MCP_SDK.md:
--------------------------------------------------------------------------------
```markdown
# MCP TypeScript SDK  
## Table of Contents
- [Overview](#overview)
- [Installation](#installation)
- [Quickstart](#quickstart)
- [What is MCP?](#what-is-mcp)
- [Core Concepts](#core-concepts)
- [Server](#server)
- [Resources](#resources)
- [Tools](#tools)
- [Prompts](#prompts)
- [Running Your Server](#running-your-server)
- [stdio](#stdio)
- [HTTP with SSE](#http-with-sse)
- [Testing and Debugging](#testing-and-debugging)
- [Examples](#examples)
- [Echo Server](#echo-server)
- [SQLite Explorer](#sqlite-explorer)
- [Advanced Usage](#advanced-usage)
- [Low-Level Server](#low-level-server)
- [Writing MCP Clients](#writing-mcp-clients)
- [Server Capabilities](#server-capabilities)
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio and SSE
- Handle all MCP protocol messages and lifecycle events
## Installation
```bash
npm install @modelcontextprotocol/sdk
```
## Quick Start
Let's create a simple MCP server that exposes a calculator tool and some data:
```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
version: "1.0.0"
});
// Add an addition tool
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
```
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
```typescript
const server = new McpServer({
name: "My App",
version: "1.0.0"
});
```
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
```typescript
// Static resource
server.resource(
"config",
"config://app",
async (uri) => ({
contents: [{
uri: uri.href,
text: "App configuration here"
}]
})
);
// Dynamic resource with parameters
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
contents: [{
uri: uri.href,
text: `Profile data for user ${userId}`
}]
})
);
```
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
```typescript
// Simple tool with parameters
server.tool(
"calculate-bmi",
{
weightKg: z.number(),
heightM: z.number()
},
async ({ weightKg, heightM }) => ({
content: [{
type: "text",
text: String(weightKg / (heightM * heightM))
}]
})
);
// Async tool with external API call
server.tool(
"fetch-weather",
{ city: z.string() },
async ({ city }) => {
const response = await fetch(`https://api.weather.com/${city}`);
const data = await response.text();
return {
content: [{ type: "text", text: data }]
};
}
);
```
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
```typescript
server.prompt(
"review-code",
{ code: z.string() },
({ code }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please review this code:\n\n${code}`
}
}]
})
);
```
## Running Your Server
MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport:
### stdio
For command-line tools and direct integrations:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### HTTP with SSE
For remote servers, start a web server with a Server-Sent Events (SSE) endpoint, and a separate endpoint for the client to send its messages to:
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const app = express();
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/messages", res);
await server.connect(transport);
});
app.post("/messages", async (req, res) => {
// Note: to support multiple simultaneous connections, these messages will
// need to be routed to a specific matching transport. (This logic isn't
// implemented here, for simplicity.)
await transport.handlePostMessage(req, res);
});
app.listen(3001);
```
### Testing and Debugging
To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information.
## Examples
### Echo Server
A simple server demonstrating resources, tools, and prompts:
```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "Echo",
version: "1.0.0"
});
server.resource(
"echo",
new ResourceTemplate("echo://{message}", { list: undefined }),
async (uri, { message }) => ({
contents: [{
uri: uri.href,
text: `Resource echo: ${message}`
}]
})
);
server.tool(
"echo",
{ message: z.string() },
async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }]
})
);
server.prompt(
"echo",
{ message: z.string() },
({ message }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please process this message: ${message}`
}
}]
})
);
```
### SQLite Explorer
A more complex example showing database integration:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import sqlite3 from "sqlite3";
import { promisify } from "util";
import { z } from "zod";
const server = new McpServer({
name: "SQLite Explorer",
version: "1.0.0"
});
// Helper to create DB connection
const getDb = () => {
const db = new sqlite3.Database("database.db");
return {
all: promisify<string, any[]>(db.all.bind(db)),
close: promisify(db.close.bind(db))
};
};
server.resource(
"schema",
"schema://main",
async (uri) => {
const db = getDb();
try {
const tables = await db.all(
"SELECT sql FROM sqlite_master WHERE type='table'"
);
return {
contents: [{
uri: uri.href,
text: tables.map((t: {sql: string}) => t.sql).join("\n")
}]
};
} finally {
await db.close();
}
}
);
server.tool(
"query",
{ sql: z.string() },
async ({ sql }) => {
const db = getDb();
try {
const results = await db.all(sql);
return {
content: [{
type: "text",
text: JSON.stringify(results, null, 2)
}]
};
} catch (err: unknown) {
const error = err as Error;
return {
content: [{
type: "text",
text: `Error: ${error.message}`
}],
isError: true
};
} finally {
await db.close();
}
}
);
```
## Advanced Usage
### Low-Level Server
For more control, you can use the low-level Server class directly:
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListPromptsRequestSchema,
GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{
name: "example-server",
version: "1.0.0"
},
{
capabilities: {
prompts: {}
}
}
);
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [{
name: "example-prompt",
description: "An example prompt template",
arguments: [{
name: "arg1",
description: "Example argument",
required: true
}]
}]
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
if (request.params.name !== "example-prompt") {
throw new Error("Unknown prompt");
}
return {
description: "Example prompt",
messages: [{
role: "user",
content: {
type: "text",
text: "Example prompt text"
}
}]
};
});
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Writing MCP Clients
The SDK provides a high-level client interface:
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
},
{
capabilities: {
prompts: {},
resources: {},
tools: {}
}
}
);
await client.connect(transport);
// List prompts
const prompts = await client.listPrompts();
// Get a prompt
const prompt = await client.getPrompt("example-prompt", {
arg1: "value"
});
// List resources
const resources = await client.listResources();
// Read a resource
const resource = await client.readResource("file:///example.txt");
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
```
## Documentation
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [MCP Specification](https://spec.modelcontextprotocol.io)
- [Example Servers](https://github.com/modelcontextprotocol/servers)
## Contributing
Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk.
## License
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.
```
--------------------------------------------------------------------------------
/N8N_API.yml:
--------------------------------------------------------------------------------
```yaml
openapi: 3.0.0
info:
title: n8n Public API
description: n8n Public API
termsOfService: https://n8n.io/legal/terms
contact:
email: [email protected]
license:
name: Sustainable Use License
url: https://github.com/n8n-io/n8n/blob/master/LICENSE.md
version: 1.1.1
servers:
- url: /api/v1
security:
- ApiKeyAuth: []
tags:
- name: User
description: Operations about users
- name: Audit
description: Operations about security audit
- name: Execution
description: Operations about executions
- name: Workflow
description: Operations about workflows
- name: Credential
description: Operations about credentials
- name: Tags
description: Operations about tags
- name: SourceControl
description: Operations about source control
- name: Variables
description: Operations about variables
- name: Projects
description: Operations about projects
externalDocs:
description: n8n API documentation
url: https://docs.n8n.io/api/
paths:
/audit:
post:
x-eov-operation-id: generateAudit
x-eov-operation-handler: v1/handlers/audit/audit.handler
tags:
- Audit
summary: Generate an audit
description: Generate a security audit for your n8n instance.
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
additionalOptions:
type: object
properties:
daysAbandonedWorkflow:
type: integer
description: Days for a workflow to be considered abandoned if not executed
categories:
type: array
items:
type: string
enum:
- credentials
- database
- nodes
- filesystem
- instance
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/audit'
'401':
$ref: '#/components/responses/unauthorized'
'500':
description: Internal server error.
/credentials:
post:
x-eov-operation-id: createCredential
x-eov-operation-handler: v1/handlers/credentials/credentials.handler
tags:
- Credential
summary: Create a credential
description: Creates a credential that can be used by nodes of the specified type.
requestBody:
description: Credential to be created.
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/credential'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/credential'
'401':
$ref: '#/components/responses/unauthorized'
'415':
description: Unsupported media type.
/credentials/{id}:
delete:
x-eov-operation-id: deleteCredential
x-eov-operation-handler: v1/handlers/credentials/credentials.handler
tags:
- Credential
summary: Delete credential by ID
description: Deletes a credential from your instance. You must be the owner of the credentials
operationId: deleteCredential
parameters:
- name: id
in: path
description: The credential ID that needs to be deleted
required: true
schema:
type: string
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/credential'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/credentials/schema/{credentialTypeName}:
get:
x-eov-operation-id: getCredentialType
x-eov-operation-handler: v1/handlers/credentials/credentials.handler
tags:
- Credential
summary: Show credential data schema
parameters:
- name: credentialTypeName
in: path
description: The credential type name that you want to get the schema for
required: true
schema:
type: string
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
type: object
examples:
freshdeskApi:
value:
additionalProperties: false
type: object
properties:
apiKey:
type: string
domain:
type: string
required:
- apiKey
- domain
slackOAuth2Api:
value:
additionalProperties: false
type: object
properties:
clientId:
type: string
clientSecret:
type: string
required:
- clientId
- clientSecret
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/executions:
get:
x-eov-operation-id: getExecutions
x-eov-operation-handler: v1/handlers/executions/executions.handler
tags:
- Execution
summary: Retrieve all executions
description: Retrieve all executions from your instance.
parameters:
- $ref: '#/components/parameters/includeData'
- name: status
in: query
description: Status to filter the executions by.
required: false
schema:
type: string
enum:
- error
- success
- waiting
- name: workflowId
in: query
description: Workflow to filter the executions by.
required: false
schema:
type: string
example: '1000'
- name: projectId
in: query
required: false
explode: false
allowReserved: true
schema:
type: string
example: VmwOO9HeTEj20kxM
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/executionList'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/executions/{id}:
get:
x-eov-operation-id: getExecution
x-eov-operation-handler: v1/handlers/executions/executions.handler
tags:
- Execution
summary: Retrieve an execution
description: Retrieve an execution from your instance.
parameters:
- $ref: '#/components/parameters/executionId'
- $ref: '#/components/parameters/includeData'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/execution'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
delete:
x-eov-operation-id: deleteExecution
x-eov-operation-handler: v1/handlers/executions/executions.handler
tags:
- Execution
summary: Delete an execution
description: Deletes an execution from your instance.
parameters:
- $ref: '#/components/parameters/executionId'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/execution'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/tags:
post:
x-eov-operation-id: createTag
x-eov-operation-handler: v1/handlers/tags/tags.handler
tags:
- Tags
summary: Create a tag
description: Create a tag in your instance.
requestBody:
description: Created tag object.
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
required: true
responses:
'201':
description: A tag object
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'409':
$ref: '#/components/responses/conflict'
get:
x-eov-operation-id: getTags
x-eov-operation-handler: v1/handlers/tags/tags.handler
tags:
- Tags
summary: Retrieve all tags
description: Retrieve all tags from your instance.
parameters:
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/tagList'
'401':
$ref: '#/components/responses/unauthorized'
/tags/{id}:
get:
x-eov-operation-id: getTag
x-eov-operation-handler: v1/handlers/tags/tags.handler
tags:
- Tags
summary: Retrieves a tag
description: Retrieves a tag.
parameters:
- $ref: '#/components/parameters/tagId'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
delete:
x-eov-operation-id: deleteTag
x-eov-operation-handler: v1/handlers/tags/tags.handler
tags:
- Tags
summary: Delete a tag
description: Deletes a tag.
parameters:
- $ref: '#/components/parameters/tagId'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/notFound'
put:
x-eov-operation-id: updateTag
x-eov-operation-handler: v1/handlers/tags/tags.handler
tags:
- Tags
summary: Update a tag
description: Update a tag.
parameters:
- $ref: '#/components/parameters/tagId'
requestBody:
description: Updated tag object.
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
required: true
responses:
'200':
description: Tag object
content:
application/json:
schema:
$ref: '#/components/schemas/tag'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
'409':
$ref: '#/components/responses/conflict'
/workflows:
post:
x-eov-operation-id: createWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Create a workflow
description: Create a workflow in your instance.
requestBody:
description: Created workflow object.
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
required: true
responses:
'200':
description: A workflow object
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
get:
x-eov-operation-id: getWorkflows
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Retrieve all workflows
description: Retrieve all workflows from your instance.
parameters:
- name: active
in: query
schema:
type: boolean
example: true
- name: tags
in: query
required: false
explode: false
allowReserved: true
schema:
type: string
example: test,production
- name: name
in: query
required: false
explode: false
allowReserved: true
schema:
type: string
example: My Workflow
- name: projectId
in: query
required: false
explode: false
allowReserved: true
schema:
type: string
example: VmwOO9HeTEj20kxM
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/workflowList'
'401':
$ref: '#/components/responses/unauthorized'
/workflows/{id}:
get:
x-eov-operation-id: getWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Retrieves a workflow
description: Retrieves a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
delete:
x-eov-operation-id: deleteWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Delete a workflow
description: Deletes a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
put:
x-eov-operation-id: updateWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Update a workflow
description: Update a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
requestBody:
description: Updated workflow object.
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
required: true
responses:
'200':
description: Workflow object
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/workflows/{id}/activate:
post:
x-eov-operation-id: activateWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Activate a workflow
description: Active a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
responses:
'200':
description: Workflow object
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/workflows/{id}/deactivate:
post:
x-eov-operation-id: deactivateWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Deactivate a workflow
description: Deactivate a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
responses:
'200':
description: Workflow object
content:
application/json:
schema:
$ref: '#/components/schemas/workflow'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/workflows/{id}/transfer:
put:
x-eov-operation-id: transferWorkflow
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Transfer a workflow to another project.
description: Transfer a workflow to another project.
parameters:
- $ref: '#/components/parameters/workflowId'
requestBody:
description: Destination project information for the workflow transfer.
content:
application/json:
schema:
type: object
properties:
destinationProjectId:
type: string
description: The ID of the project to transfer the workflow to.
required:
- destinationProjectId
required: true
responses:
'200':
description: Operation successful.
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/credentials/{id}/transfer:
put:
x-eov-operation-id: transferCredential
x-eov-operation-handler: v1/handlers/credentials/credentials.handler
tags:
- Workflow
summary: Transfer a credential to another project.
description: Transfer a credential to another project.
parameters:
- $ref: '#/components/parameters/credentialId'
requestBody:
description: Destination project for the credential transfer.
content:
application/json:
schema:
type: object
properties:
destinationProjectId:
type: string
description: The ID of the project to transfer the credential to.
required:
- destinationProjectId
required: true
responses:
'200':
description: Operation successful.
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/workflows/{id}/tags:
get:
x-eov-operation-id: getWorkflowTags
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Get workflow tags
description: Get workflow tags.
parameters:
- $ref: '#/components/parameters/workflowId'
responses:
'200':
description: List of tags
content:
application/json:
schema:
$ref: '#/components/schemas/workflowTags'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
put:
x-eov-operation-id: updateWorkflowTags
x-eov-operation-handler: v1/handlers/workflows/workflows.handler
tags:
- Workflow
summary: Update tags of a workflow
description: Update tags of a workflow.
parameters:
- $ref: '#/components/parameters/workflowId'
requestBody:
description: List of tags
content:
application/json:
schema:
$ref: '#/components/schemas/tagIds'
required: true
responses:
'200':
description: List of tags after add the tag
content:
application/json:
schema:
$ref: '#/components/schemas/workflowTags'
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/users:
get:
x-eov-operation-id: getUsers
x-eov-operation-handler: v1/handlers/users/users.handler.ee
tags:
- User
summary: Retrieve all users
description: Retrieve all users from your instance. Only available for the instance owner.
parameters:
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
- $ref: '#/components/parameters/includeRole'
- name: projectId
in: query
required: false
explode: false
allowReserved: true
schema:
type: string
example: VmwOO9HeTEj20kxM
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/userList'
'401':
$ref: '#/components/responses/unauthorized'
post:
x-eov-operation-id: createUser
x-eov-operation-handler: v1/handlers/users/users.handler.ee
tags:
- User
summary: Create multiple users
description: Create one or more users.
requestBody:
description: Array of users to be created.
required: true
content:
application/json:
schema:
type: array
items:
type: object
properties:
email:
type: string
format: email
role:
type: string
enum:
- global:admin
- global:member
required:
- email
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
type: object
properties:
user:
type: object
properties:
id:
type: string
email:
type: string
inviteAcceptUrl:
type: string
emailSent:
type: boolean
error:
type: string
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
/users/{id}:
get:
x-eov-operation-id: getUser
x-eov-operation-handler: v1/handlers/users/users.handler.ee
tags:
- User
summary: Get user by ID/Email
description: Retrieve a user from your instance. Only available for the instance owner.
parameters:
- $ref: '#/components/parameters/userIdentifier'
- $ref: '#/components/parameters/includeRole'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/user'
'401':
$ref: '#/components/responses/unauthorized'
delete:
x-eov-operation-id: deleteUser
x-eov-operation-handler: v1/handlers/users/users.handler.ee
tags:
- User
summary: Delete a user
description: Delete a user from your instance.
parameters:
- $ref: '#/components/parameters/userIdentifier'
responses:
'204':
description: Operation successful.
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/notFound'
/users/{id}/role:
patch:
x-eov-operation-id: changeRole
x-eov-operation-handler: v1/handlers/users/users.handler.ee
tags:
- User
summary: Change a user's global role
description: Change a user's global role
parameters:
- $ref: '#/components/parameters/userIdentifier'
requestBody:
description: New role for the user
required: true
content:
application/json:
schema:
type: object
properties:
newRoleName:
type: string
enum:
- global:admin
- global:member
required:
- newRoleName
responses:
'200':
description: Operation successful.
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/notFound'
/source-control/pull:
post:
x-eov-operation-id: pull
x-eov-operation-handler: v1/handlers/sourceControl/sourceControl.handler
tags:
- SourceControl
summary: Pull changes from the remote repository
description: Requires the Source Control feature to be licensed and connected to a repository.
requestBody:
description: Pull options
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/pull'
responses:
'200':
description: Import result
content:
application/json:
schema:
$ref: '#/components/schemas/importResult'
'400':
$ref: '#/components/responses/badRequest'
'409':
$ref: '#/components/responses/conflict'
/variables:
post:
x-eov-operation-id: createVariable
x-eov-operation-handler: v1/handlers/variables/variables.handler
tags:
- Variables
summary: Create a variable
description: Create a variable in your instance.
requestBody:
description: Payload for variable to create.
content:
application/json:
schema:
$ref: '#/components/schemas/variable'
required: true
responses:
'201':
description: Operation successful.
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
get:
x-eov-operation-id: getVariables
x-eov-operation-handler: v1/handlers/variables/variables.handler
tags:
- Variables
summary: Retrieve variables
description: Retrieve variables from your instance.
parameters:
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/variableList'
'401':
$ref: '#/components/responses/unauthorized'
/variables/{id}:
delete:
x-eov-operation-id: deleteVariable
x-eov-operation-handler: v1/handlers/variables/variables.handler
tags:
- Variables
summary: Delete a variable
description: Delete a variable from your instance.
parameters:
- $ref: '#/components/parameters/variableId'
responses:
'204':
description: Operation successful.
'401':
$ref: '#/components/responses/unauthorized'
'404':
$ref: '#/components/responses/notFound'
/projects:
post:
x-eov-operation-id: createProject
x-eov-operation-handler: v1/handlers/projects/projects.handler
tags:
- Projects
summary: Create a project
description: Create a project in your instance.
requestBody:
description: Payload for project to create.
content:
application/json:
schema:
$ref: '#/components/schemas/project'
required: true
responses:
'201':
description: Operation successful.
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
get:
x-eov-operation-id: getProjects
x-eov-operation-handler: v1/handlers/projects/projects.handler
tags:
- Projects
summary: Retrieve projects
description: Retrieve projects from your instance.
parameters:
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/cursor'
responses:
'200':
description: Operation successful.
content:
application/json:
schema:
$ref: '#/components/schemas/projectList'
'401':
$ref: '#/components/responses/unauthorized'
/projects/{projectId}:
delete:
x-eov-operation-id: deleteProject
x-eov-operation-handler: v1/handlers/projects/projects.handler
tags:
- Projects
summary: Delete a project
description: Delete a project from your instance.
parameters:
- $ref: '#/components/parameters/projectId'
responses:
'204':
description: Operation successful.
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/notFound'
put:
x-eov-operation-id: updateProject
x-eov-operation-handler: v1/handlers/projects/projects.handler
tags:
- Project
summary: Update a project
description: Update a project.
requestBody:
description: Updated project object.
content:
application/json:
schema:
$ref: '#/components/schemas/project'
required: true
responses:
'204':
description: Operation successful.
'400':
$ref: '#/components/responses/badRequest'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/notFound'
components:
schemas:
audit:
type: object
properties:
Credentials Risk Report:
type: object
example:
risk: credentials
sections:
- title: Credentials not used in any workflow
description: These credentials are not used in any workflow. Keeping unused credentials in your instance is an unneeded security risk.
recommendation: Consider deleting these credentials if you no longer need them.
location:
- kind: credential
id: '1'
name: My Test Account
Database Risk Report:
type: object
example:
risk: database
sections:
- title: Expressions in "Execute Query" fields in SQL nodes
description: This SQL node has an expression in the "Query" field of an "Execute Query" operation. Building a SQL query with an expression may lead to a SQL injection attack.
recommendation: Consider using the "Query Parameters" field to pass parameters to the query
or validating the input of the expression in the "Query" field.: null
location:
- kind: node
workflowId: '1'
workflowName: My Workflow
nodeId: 51eb5852-ce0b-4806-b4ff-e41322a4041a
nodeName: MySQL
nodeType: n8n-nodes-base.mySql
Filesystem Risk Report:
type: object
example:
risk: filesystem
sections:
- title: Nodes that interact with the filesystem
description: This node reads from and writes to any accessible file in the host filesystem. Sensitive file content may be manipulated through a node operation.
recommendation: Consider protecting any sensitive files in the host filesystem
or refactoring the workflow so that it does not require host filesystem interaction.: null
location:
- kind: node
workflowId: '1'
workflowName: My Workflow
nodeId: 51eb5852-ce0b-4806-b4ff-e41322a4041a
nodeName: Ready Binary file
nodeType: n8n-nodes-base.readBinaryFile
Nodes Risk Report:
type: object
example:
risk: nodes
sections:
- title: Community nodes
description: This node is sourced from the community. Community nodes are not vetted by the n8n team and have full access to the host system.
recommendation: Consider reviewing the source code in any community nodes installed in this n8n instance
and uninstalling any community nodes no longer used.: null
location:
- kind: community
nodeType: n8n-nodes-test.test
packageUrl: https://www.npmjs.com/package/n8n-nodes-test
Instance Risk Report:
type: object
example:
risk: execution
sections:
- title: Unprotected webhooks in instance
description: These webhook nodes have the "Authentication" field set to "None" and are not directly connected to a node to validate the payload. Every unprotected webhook allows your workflow to be called by any third party who knows the webhook URL.
recommendation: Consider setting the "Authentication" field to an option other than "None"
or validating the payload with one of the following nodes.: null
location:
- kind: community
nodeType: n8n-nodes-test.test
packageUrl: https://www.npmjs.com/package/n8n-nodes-test
credential:
required:
- name
- type
- data
type: object
properties:
id:
type: string
readOnly: true
example: R2DjclaysHbqn778
name:
type: string
example: Joe's Github Credentials
type:
type: string
example: github
data:
type: object
writeOnly: true
example:
token: ada612vad6fa5df4adf5a5dsf4389adsf76da7s
createdAt:
type: string
format: date-time
readOnly: true
example: '2022-04-29T11:02:29.842Z'
updatedAt:
type: string
format: date-time
readOnly: true
example: '2022-04-29T11:02:29.842Z'
execution:
type: object
properties:
id:
type: number
example: 1000
data:
type: object
finished:
type: boolean
example: true
mode:
type: string
enum:
- cli
- error
- integrated
- internal
- manual
- retry
- trigger
- webhook
retryOf:
type: number
nullable: true
retrySuccessId:
type: number
nullable: true
example: '2'
startedAt:
type: string
format: date-time
stoppedAt:
type: string
format: date-time
workflowId:
type: number
example: '1000'
waitTill:
type: string
nullable: true
format: date-time
customData:
type: object
executionList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/execution'
nextCursor:
type: string
description: Paginate through executions by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
tag:
type: object
additionalProperties: false
required:
- name
properties:
id:
type: string
readOnly: true
example: 2tUt1wbLX592XDdX
name:
type: string
example: Production
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
tagList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/tag'
nextCursor:
type: string
description: Paginate through tags by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
node:
type: object
additionalProperties: false
properties:
id:
type: string
example: 0f5532f9-36ba-4bef-86c7-30d607400b15
name:
type: string
example: Jira
webhookId:
type: string
disabled:
type: boolean
notesInFlow:
type: boolean
notes:
type: string
type:
type: string
example: n8n-nodes-base.Jira
typeVersion:
type: number
example: 1
executeOnce:
type: boolean
example: false
alwaysOutputData:
type: boolean
example: false
retryOnFail:
type: boolean
example: false
maxTries:
type: number
waitBetweenTries:
type: number
continueOnFail:
type: boolean
example: false
description: use onError instead
deprecated: true
onError:
type: string
example: stopWorkflow
position:
type: array
items:
type: number
example:
- -100
- 80
parameters:
type: object
example:
additionalProperties: {}
credentials:
type: object
example:
jiraSoftwareCloudApi:
id: '35'
name: jiraApi
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
workflowSettings:
type: object
additionalProperties: false
properties:
saveExecutionProgress:
type: boolean
saveManualExecutions:
type: boolean
saveDataErrorExecution:
type: string
enum:
- all
- none
saveDataSuccessExecution:
type: string
enum:
- all
- none
executionTimeout:
type: number
example: 3600
maxLength: 3600
errorWorkflow:
type: string
example: VzqKEW0ShTXA5vPj
description: The ID of the workflow that contains the error trigger node.
timezone:
type: string
example: America/New_York
executionOrder:
type: string
example: v1
workflow:
type: object
additionalProperties: false
required:
- name
- nodes
- connections
- settings
properties:
id:
type: string
readOnly: true
example: 2tUt1wbLX592XDdX
name:
type: string
example: Workflow 1
active:
type: boolean
readOnly: true
createdAt:
type: string
format: date-time
readOnly: true
updatedAt:
type: string
format: date-time
readOnly: true
nodes:
type: array
items:
$ref: '#/components/schemas/node'
connections:
type: object
example:
main:
- node: Jira
type: main
index: 0
settings:
$ref: '#/components/schemas/workflowSettings'
staticData:
example:
lastId: 1
anyOf:
- type: string
format: jsonString
nullable: true
- type: object
nullable: true
tags:
type: array
items:
$ref: '#/components/schemas/tag'
readOnly: true
workflowList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/workflow'
nextCursor:
type: string
description: Paginate through workflows by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
workflowTags:
type: array
items:
$ref: '#/components/schemas/tag'
tagIds:
type: array
items:
type: object
additionalProperties: false
required:
- id
properties:
id:
type: string
example: 2tUt1wbLX592XDdX
user:
required:
- email
type: object
properties:
id:
type: string
readOnly: true
example: 123e4567-e89b-12d3-a456-426614174000
email:
type: string
format: email
example: [email protected]
firstName:
maxLength: 32
type: string
description: User's first name
readOnly: true
example: john
lastName:
maxLength: 32
type: string
description: User's last name
readOnly: true
example: Doe
isPending:
type: boolean
description: Whether the user finished setting up their account in response to the invitation (true) or not (false).
readOnly: true
createdAt:
type: string
description: Time the user was created.
format: date-time
readOnly: true
updatedAt:
type: string
description: Last time the user was updated.
format: date-time
readOnly: true
role:
type: string
example: owner
readOnly: true
userList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/user'
nextCursor:
type: string
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
pull:
type: object
properties:
force:
type: boolean
example: true
variables:
type: object
example:
foo: bar
importResult:
type: object
additionalProperties: true
properties:
variables:
type: object
properties:
added:
type: array
items:
type: string
changed:
type: array
items:
type: string
credentials:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
type:
type: string
workflows:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
tags:
type: object
properties:
tags:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
mappings:
type: array
items:
type: object
properties:
workflowId:
type: string
tagId:
type: string
variable:
type: object
additionalProperties: false
required:
- key
- value
properties:
id:
type: string
readOnly: true
key:
type: string
value:
type: string
example: test
type:
type: string
readOnly: true
variableList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/variable'
nextCursor:
type: string
description: Paginate through variables by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
project:
type: object
additionalProperties: false
required:
- name
properties:
id:
type: string
readOnly: true
name:
type: string
type:
type: string
readOnly: true
projectList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/project'
nextCursor:
type: string
description: Paginate through projects by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
nullable: true
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
error:
required:
- message
type: object
properties:
code:
type: string
message:
type: string
description:
type: string
role:
readOnly: true
type: object
properties:
id:
type: number
readOnly: true
example: 1
name:
type: string
example: owner
readOnly: true
scope:
type: string
readOnly: true
example: global
createdAt:
type: string
description: Time the role was created.
format: date-time
readOnly: true
updatedAt:
type: string
description: Last time the role was updated.
format: date-time
readOnly: true
credentialType:
type: object
properties:
displayName:
type: string
readOnly: true
example: Email
name:
type: string
readOnly: true
example: email
type:
type: string
readOnly: true
example: string
default:
type: string
readOnly: true
example: string
Error:
$ref: '#/components/schemas/error'
Role:
$ref: '#/components/schemas/role'
Execution:
$ref: '#/components/schemas/execution'
Node:
$ref: '#/components/schemas/node'
Tag:
$ref: '#/components/schemas/tag'
Workflow:
$ref: '#/components/schemas/workflow'
WorkflowSettings:
$ref: '#/components/schemas/workflowSettings'
ExecutionList:
$ref: '#/components/schemas/executionList'
WorkflowList:
$ref: '#/components/schemas/workflowList'
Credential:
$ref: '#/components/schemas/credential'
CredentialType:
$ref: '#/components/schemas/credentialType'
Audit:
$ref: '#/components/schemas/audit'
Pull:
$ref: '#/components/schemas/pull'
ImportResult:
$ref: '#/components/schemas/importResult'
UserList:
$ref: '#/components/schemas/userList'
User:
$ref: '#/components/schemas/user'
responses:
unauthorized:
description: Unauthorized
notFound:
description: The specified resource was not found.
badRequest:
description: The request is invalid or provides malformed data.
conflict:
description: Conflict
forbidden:
description: Forbidden
NotFound:
$ref: '#/components/responses/notFound'
Unauthorized:
$ref: '#/components/responses/unauthorized'
BadRequest:
$ref: '#/components/responses/badRequest'
Conflict:
$ref: '#/components/responses/conflict'
Forbidden:
$ref: '#/components/responses/forbidden'
parameters:
includeData:
name: includeData
in: query
description: Whether or not to include the execution's detailed data.
required: false
schema:
type: boolean
limit:
name: limit
in: query
description: The maximum number of items to return.
required: false
schema:
type: number
example: 100
default: 100
maximum: 250
cursor:
name: cursor
in: query
description: Paginate by setting the cursor parameter to the nextCursor attribute returned by the previous request's response. Default value fetches the first "page" of the collection. See pagination for more detail.
required: false
style: form
schema:
type: string
executionId:
name: id
in: path
description: The ID of the execution.
required: true
schema:
type: number
tagId:
name: id
in: path
description: The ID of the tag.
required: true
schema:
type: string
workflowId:
name: id
in: path
description: The ID of the workflow.
required: true
schema:
type: string
credentialId:
name: id
in: path
description: The ID of the credential.
required: true
schema:
type: string
includeRole:
name: includeRole
in: query
description: Whether to include the user's role or not.
required: false
schema:
type: boolean
example: true
default: false
userIdentifier:
name: id
in: path
description: The ID or email of the user.
required: true
schema:
type: string
format: identifier
variableId:
name: id
in: path
description: The ID of the variable.
required: true
schema:
type: string
projectId:
name: projectId
in: path
description: The ID of the project.
required: true
schema:
type: string
Cursor:
$ref: '#/components/parameters/cursor'
Limit:
$ref: '#/components/parameters/limit'
ExecutionId:
$ref: '#/components/parameters/executionId'
WorkflowId:
$ref: '#/components/parameters/workflowId'
TagId:
$ref: '#/components/parameters/tagId'
IncludeData:
$ref: '#/components/parameters/includeData'
UserIdentifier:
$ref: '#/components/parameters/userIdentifier'
IncludeRole:
$ref: '#/components/parameters/includeRole'
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-N8N-API-KEY
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import fetch from 'node-fetch';
// Type definitions for n8n API responses
interface N8nUser {
id: string;
email: string;
firstName?: string;
lastName?: string;
isPending: boolean;
role?: string;
createdAt: string;
updatedAt: string;
}
interface N8nUserList {
data: N8nUser[];
nextCursor?: string;
}
interface N8nWorkflow {
id: number;
name: string;
active: boolean;
createdAt: string;
updatedAt: string;
tags: string[];
}
interface N8nWorkflowList {
data: N8nWorkflow[];
nextCursor?: string;
}
interface N8nProject {
id: string;
name: string;
type?: string;
}
interface N8nProjectList {
data: N8nProject[];
nextCursor?: string;
}
interface N8nVariable {
id: string;
key: string;
value: string;
type?: string;
}
interface N8nVariableList {
data: N8nVariable[];
nextCursor?: string;
}
interface N8nExecution {
id: number;
data?: any;
finished: boolean;
mode: string;
retryOf?: number;
retrySuccessId?: number;
startedAt: string;
stoppedAt?: string;
workflowId: number;
waitTill?: string;
}
interface N8nExecutionList {
data: N8nExecution[];
nextCursor?: string;
}
interface N8nTag {
id: string;
name: string;
createdAt?: string;
updatedAt?: string;
}
interface N8nTagList {
data: N8nTag[];
nextCursor?: string;
}
interface N8nAuditResult {
'Credentials Risk Report'?: any;
'Database Risk Report'?: any;
'Filesystem Risk Report'?: any;
'Nodes Risk Report'?: any;
'Instance Risk Report'?: any;
}
class N8nClient {
constructor(
private baseUrl: string,
private apiKey: string
) {
// Remove trailing slash if present
this.baseUrl = baseUrl.replace(/\/$/, '');
}
private async makeRequest<T>(endpoint: string, options: any = {}): Promise<T> {
const url = `${this.baseUrl}/api/v1${endpoint}`;
const headers = {
'X-N8N-API-KEY': this.apiKey,
'Accept': 'application/json',
'Content-Type': 'application/json',
};
try {
const response = await fetch(url, {
...options,
headers: {
...headers,
...options.headers,
},
});
if (!response.ok) {
const errorText = await response.text();
let errorMessage: string;
try {
const errorJson = JSON.parse(errorText);
// Check for license-related errors
if (errorJson.message && errorJson.message.includes('license')) {
errorMessage = `This operation requires an n8n Enterprise license with project management features enabled. Error: ${errorJson.message}`;
} else {
errorMessage = errorJson.message || errorText;
}
} catch {
errorMessage = errorText;
}
throw new Error(`N8N API error: ${errorMessage}`);
}
// Handle 204 No Content responses
if (response.status === 204) {
return {} as T;
}
return await response.json() as T;
} catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to connect to n8n: ${error.message}`);
}
throw error;
}
}
async listWorkflows(): Promise<N8nWorkflowList> {
return this.makeRequest<N8nWorkflowList>('/workflows');
}
async getWorkflow(id: string): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>(`/workflows/${id}`);
}
async createWorkflow(name: string, nodes: any[] = [], connections: any = {}): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>('/workflows', {
method: 'POST',
body: JSON.stringify({
name,
nodes,
connections,
settings: {
saveManualExecutions: true,
saveExecutionProgress: true,
},
}),
});
}
async updateWorkflow(id: string, workflow: Partial<N8nWorkflow>): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>(`/workflows/${id}`, {
method: 'PUT',
body: JSON.stringify(workflow),
});
}
async deleteWorkflow(id: string): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>(`/workflows/${id}`, {
method: 'DELETE',
});
}
async activateWorkflow(id: string): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>(`/workflows/${id}/activate`, {
method: 'POST',
});
}
async deactivateWorkflow(id: string): Promise<N8nWorkflow> {
return this.makeRequest<N8nWorkflow>(`/workflows/${id}/deactivate`, {
method: 'POST',
});
}
// Project management methods (requires n8n Enterprise license)
async listProjects(): Promise<N8nProjectList> {
return this.makeRequest<N8nProjectList>('/projects');
}
async createProject(name: string): Promise<void> {
return this.makeRequest<void>('/projects', {
method: 'POST',
body: JSON.stringify({ name }),
});
}
async deleteProject(projectId: string): Promise<void> {
return this.makeRequest<void>(`/projects/${projectId}`, {
method: 'DELETE',
});
}
async updateProject(projectId: string, name: string): Promise<void> {
return this.makeRequest<void>(`/projects/${projectId}`, {
method: 'PUT',
body: JSON.stringify({ name }),
});
}
// User management methods
async listUsers(): Promise<N8nUserList> {
return this.makeRequest<N8nUserList>('/users');
}
async createUsers(users: Array<{ email: string; role?: 'global:admin' | 'global:member' }>): Promise<any> {
return this.makeRequest('/users', {
method: 'POST',
body: JSON.stringify(users),
});
}
async getUser(idOrEmail: string): Promise<N8nUser> {
return this.makeRequest<N8nUser>(`/users/${idOrEmail}`);
}
async deleteUser(idOrEmail: string): Promise<void> {
return this.makeRequest<void>(`/users/${idOrEmail}`, {
method: 'DELETE',
});
}
// Variable management methods
async listVariables(): Promise<N8nVariableList> {
return this.makeRequest<N8nVariableList>('/variables');
}
async createVariable(key: string, value: string): Promise<void> {
return this.makeRequest<void>('/variables', {
method: 'POST',
body: JSON.stringify({ key, value }),
});
}
async deleteVariable(id: string): Promise<void> {
return this.makeRequest<void>(`/variables/${id}`, {
method: 'DELETE',
});
}
// Execution management methods
async getExecutions(options: {
includeData?: boolean;
status?: 'error' | 'success' | 'waiting';
workflowId?: string;
limit?: number;
} = {}): Promise<N8nExecutionList> {
const params = new URLSearchParams();
if (options.includeData !== undefined) params.append('includeData', String(options.includeData));
if (options.status) params.append('status', options.status);
if (options.workflowId) params.append('workflowId', options.workflowId);
if (options.limit) params.append('limit', String(options.limit));
return this.makeRequest<N8nExecutionList>(`/executions?${params.toString()}`);
}
async getExecution(id: number, includeData: boolean = false): Promise<N8nExecution> {
const params = new URLSearchParams();
if (includeData) params.append('includeData', 'true');
return this.makeRequest<N8nExecution>(`/executions/${id}?${params.toString()}`);
}
async deleteExecution(id: number): Promise<N8nExecution> {
return this.makeRequest<N8nExecution>(`/executions/${id}`, {
method: 'DELETE',
});
}
// Tag management methods
async createTag(name: string): Promise<N8nTag> {
return this.makeRequest<N8nTag>('/tags', {
method: 'POST',
body: JSON.stringify({ name }),
});
}
async getTags(options: { limit?: number } = {}): Promise<N8nTagList> {
const params = new URLSearchParams();
if (options.limit) params.append('limit', String(options.limit));
return this.makeRequest<N8nTagList>(`/tags?${params.toString()}`);
}
async getTag(id: string): Promise<N8nTag> {
return this.makeRequest<N8nTag>(`/tags/${id}`);
}
async updateTag(id: string, name: string): Promise<N8nTag> {
return this.makeRequest<N8nTag>(`/tags/${id}`, {
method: 'PUT',
body: JSON.stringify({ name }),
});
}
async deleteTag(id: string): Promise<N8nTag> {
return this.makeRequest<N8nTag>(`/tags/${id}`, {
method: 'DELETE',
});
}
async getWorkflowTags(workflowId: string): Promise<N8nTag[]> {
return this.makeRequest<N8nTag[]>(`/workflows/${workflowId}/tags`);
}
async updateWorkflowTags(workflowId: string, tagIds: { id: string }[]): Promise<N8nTag[]> {
return this.makeRequest<N8nTag[]>(`/workflows/${workflowId}/tags`, {
method: 'PUT',
body: JSON.stringify(tagIds),
});
}
// Security audit method
async generateAudit(options: {
daysAbandonedWorkflow?: number;
categories?: Array<'credentials' | 'database' | 'nodes' | 'filesystem' | 'instance'>;
} = {}): Promise<N8nAuditResult> {
return this.makeRequest<N8nAuditResult>('/audit', {
method: 'POST',
body: JSON.stringify({
additionalOptions: {
daysAbandonedWorkflow: options.daysAbandonedWorkflow,
categories: options.categories,
},
}),
});
}
// Credential management methods
async createCredential(name: string, type: string, data: Record<string, any>): Promise<any> {
return this.makeRequest('/credentials', {
method: 'POST',
body: JSON.stringify({
name,
type,
data
}),
});
}
async deleteCredential(id: string): Promise<any> {
return this.makeRequest(`/credentials/${id}`, {
method: 'DELETE',
});
}
async getCredentialSchema(credentialTypeName: string): Promise<any> {
return this.makeRequest(`/credentials/schema/${credentialTypeName}`);
}
}
// Create an MCP server
const server = new Server(
{
name: "n8n-integration",
version: "1.0.0"
},
{
capabilities: {
tools: {}
}
}
);
// Store client instances
const clients = new Map<string, N8nClient>();
// List tools handler
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "init-n8n",
description: "Initialize connection to n8n instance. Use this tool whenever an n8n URL and API key are shared to establish the connection. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
url: { type: "string" },
apiKey: { type: "string" }
},
required: ["url", "apiKey"]
}
},
{
name: "list-workflows",
description: "List all workflows from n8n. Use after init-n8n to see available workflows. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" }
},
required: ["clientId"]
}
},
{
name: "get-workflow",
description: "Retrieve a workflow by ID. Use after list-workflows to get detailed information about a specific workflow. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "create-workflow",
description: "Create a new workflow in n8n. Use to set up a new workflow with optional nodes and connections. IMPORTANT: 1) Arguments must be provided as compact, single-line JSON without whitespace or newlines. 2) Must provide full workflow structure including nodes and connections arrays, even if empty. The 'active' property should not be included as it is read-only.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
name: { type: "string" },
nodes: { type: "array" },
connections: { type: "object" }
},
required: ["clientId", "name"]
}
},
{
name: "update-workflow",
description: "Update an existing workflow in n8n. Use after get-workflow to modify a workflow's properties, nodes, or connections. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" },
workflow: {
type: "object",
properties: {
name: { type: "string" },
active: { type: "boolean" },
nodes: { type: "array" },
connections: { type: "object" },
settings: { type: "object" }
}
}
},
required: ["clientId", "id", "workflow"]
}
},
{
name: "delete-workflow",
description: "Delete a workflow by ID. This action cannot be undone. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "activate-workflow",
description: "Activate a workflow by ID. This will enable the workflow to run. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "deactivate-workflow",
description: "Deactivate a workflow by ID. This will prevent the workflow from running. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "list-projects",
description: "List all projects from n8n. NOTE: Requires n8n Enterprise license with project management features enabled. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" }
},
required: ["clientId"]
}
},
{
name: "create-project",
description: "Create a new project in n8n. NOTE: Requires n8n Enterprise license with project management features enabled. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
name: { type: "string" }
},
required: ["clientId", "name"]
}
},
{
name: "delete-project",
description: "Delete a project by ID. NOTE: Requires n8n Enterprise license with project management features enabled. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
projectId: { type: "string" }
},
required: ["clientId", "projectId"]
}
},
{
name: "update-project",
description: "Update a project's name. NOTE: Requires n8n Enterprise license with project management features enabled. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
projectId: { type: "string" },
name: { type: "string" }
},
required: ["clientId", "projectId", "name"]
}
},
{
name: "list-users",
description: "Retrieve all users from your instance. Only available for the instance owner.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" }
},
required: ["clientId"]
}
},
{
name: "create-users",
description: "Create one or more users in your instance.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
users: {
type: "array",
items: {
type: "object",
properties: {
email: { type: "string" },
role: {
type: "string",
enum: ["global:admin", "global:member"]
}
},
required: ["email"]
}
}
},
required: ["clientId", "users"]
}
},
{
name: "get-user",
description: "Get user by ID or email address.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
idOrEmail: { type: "string" }
},
required: ["clientId", "idOrEmail"]
}
},
{
name: "delete-user",
description: "Delete a user from your instance.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
idOrEmail: { type: "string" }
},
required: ["clientId", "idOrEmail"]
}
},
{
name: "list-variables",
description: "List all variables from n8n. NOTE: Requires n8n Enterprise license with variable management features enabled. Use after init-n8n to see available variables. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" }
},
required: ["clientId"]
}
},
{
name: "create-variable",
description: "Create a new variable in n8n. NOTE: Requires n8n Enterprise license with variable management features enabled. Variables can be used across workflows to store and share data. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
key: { type: "string" },
value: { type: "string" }
},
required: ["clientId", "key", "value"]
}
},
{
name: "delete-variable",
description: "Delete a variable by ID. NOTE: Requires n8n Enterprise license with variable management features enabled. Use after list-variables to get the ID of the variable to delete. This action cannot be undone. IMPORTANT: Arguments must be provided as compact, single-line JSON without whitespace or newlines.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "create-credential",
description: "Create a credential that can be used by nodes of the specified type. The credential type name can be found in the n8n UI when creating credentials (e.g., 'cloudflareApi', 'githubApi', 'slackOAuth2Api'). Use get-credential-schema first to see what fields are required for the credential type you want to create.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
name: { type: "string" },
type: { type: "string" },
data: { type: "object" }
},
required: ["clientId", "name", "type", "data"]
}
},
{
name: "delete-credential",
description: "Delete a credential by ID. You must be the owner of the credentials.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "get-credential-schema",
description: "Show credential data schema for a specific credential type. The credential type name can be found in the n8n UI when creating credentials (e.g., 'cloudflareApi', 'githubApi', 'slackOAuth2Api'). This will show you what fields are required for creating credentials of this type.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
credentialTypeName: { type: "string" }
},
required: ["clientId", "credentialTypeName"]
}
},
// Execution Management Tools
{
name: "list-executions",
description: "Retrieve all executions from your instance with optional filtering.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
includeData: { type: "boolean" },
status: {
type: "string",
enum: ["error", "success", "waiting"]
},
workflowId: { type: "string" },
limit: { type: "number" }
},
required: ["clientId"]
}
},
{
name: "get-execution",
description: "Retrieve a specific execution by ID.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "number" },
includeData: { type: "boolean" }
},
required: ["clientId", "id"]
}
},
{
name: "delete-execution",
description: "Delete a specific execution by ID.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "number" }
},
required: ["clientId", "id"]
}
},
// Tag Management Tools
{
name: "create-tag",
description: "Create a new tag in your instance.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
name: { type: "string" }
},
required: ["clientId", "name"]
}
},
{
name: "list-tags",
description: "Retrieve all tags from your instance.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
limit: { type: "number" }
},
required: ["clientId"]
}
},
{
name: "get-tag",
description: "Retrieve a specific tag by ID.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "update-tag",
description: "Update a tag's name.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" },
name: { type: "string" }
},
required: ["clientId", "id", "name"]
}
},
{
name: "delete-tag",
description: "Delete a tag by ID.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
id: { type: "string" }
},
required: ["clientId", "id"]
}
},
{
name: "get-workflow-tags",
description: "Get tags associated with a workflow.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
workflowId: { type: "string" }
},
required: ["clientId", "workflowId"]
}
},
{
name: "update-workflow-tags",
description: "Update tags associated with a workflow.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
workflowId: { type: "string" },
tagIds: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string" }
},
required: ["id"]
}
}
},
required: ["clientId", "workflowId", "tagIds"]
}
},
// Security Audit Tool
{
name: "generate-audit",
description: "Generate a security audit for your n8n instance.",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
daysAbandonedWorkflow: { type: "number" },
categories: {
type: "array",
items: {
type: "string",
enum: ["credentials", "database", "nodes", "filesystem", "instance"]
}
}
},
required: ["clientId"]
}
}
]
};
});
// Tool execution handler
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "init-n8n": {
const { url, apiKey } = args as { url: string; apiKey: string };
try {
const client = new N8nClient(url, apiKey);
// Test connection by listing workflows
await client.listWorkflows();
// Generate a unique client ID
const clientId = Buffer.from(url).toString('base64');
clients.set(clientId, client);
return {
content: [{
type: "text",
text: `Successfully connected to n8n at ${url}. Use this client ID for future operations: ${clientId}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "list-workflows": {
const { clientId } = args as { clientId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflows = await client.listWorkflows();
const formattedWorkflows = workflows.data.map(wf => ({
id: wf.id,
name: wf.name,
active: wf.active,
created: wf.createdAt,
updated: wf.updatedAt,
tags: wf.tags,
}));
return {
content: [{
type: "text",
text: JSON.stringify(formattedWorkflows, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-workflow": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflow = await client.getWorkflow(id);
return {
content: [{
type: "text",
text: JSON.stringify(workflow, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "update-workflow": {
const { clientId, id, workflow } = args as {
clientId: string;
id: string;
workflow: Partial<N8nWorkflow>;
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const updatedWorkflow = await client.updateWorkflow(id, workflow);
return {
content: [{
type: "text",
text: `Successfully updated workflow:\n${JSON.stringify(updatedWorkflow, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "create-workflow": {
const { clientId, name, nodes = [], connections = {} } = args as {
clientId: string;
name: string;
nodes?: any[];
connections?: Record<string, any>;
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflow = await client.createWorkflow(name, nodes, connections);
return {
content: [{
type: "text",
text: `Successfully created workflow:\n${JSON.stringify(workflow, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-workflow": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflow = await client.deleteWorkflow(id);
return {
content: [{
type: "text",
text: `Successfully deleted workflow:\n${JSON.stringify(workflow, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "activate-workflow": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflow = await client.activateWorkflow(id);
return {
content: [{
type: "text",
text: `Successfully activated workflow:\n${JSON.stringify(workflow, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "deactivate-workflow": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const workflow = await client.deactivateWorkflow(id);
return {
content: [{
type: "text",
text: `Successfully deactivated workflow:\n${JSON.stringify(workflow, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "list-projects": {
const { clientId } = args as { clientId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const projects = await client.listProjects();
return {
content: [{
type: "text",
text: JSON.stringify(projects.data, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "create-project": {
const { clientId, name } = args as { clientId: string; name: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.createProject(name);
return {
content: [{
type: "text",
text: `Successfully created project: ${name}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-project": {
const { clientId, projectId } = args as { clientId: string; projectId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.deleteProject(projectId);
return {
content: [{
type: "text",
text: `Successfully deleted project with ID: ${projectId}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "update-project": {
const { clientId, projectId, name } = args as { clientId: string; projectId: string; name: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.updateProject(projectId, name);
return {
content: [{
type: "text",
text: `Successfully updated project ${projectId} with new name: ${name}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "list-users": {
const { clientId } = args as { clientId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const users = await client.listUsers();
return {
content: [{
type: "text",
text: JSON.stringify(users.data, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "create-users": {
const { clientId, users } = args as {
clientId: string;
users: Array<{
email: string;
role?: 'global:admin' | 'global:member'
}>
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const result = await client.createUsers(users);
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-user": {
const { clientId, idOrEmail } = args as { clientId: string; idOrEmail: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const user = await client.getUser(idOrEmail);
return {
content: [{
type: "text",
text: JSON.stringify(user, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-user": {
const { clientId, idOrEmail } = args as { clientId: string; idOrEmail: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.deleteUser(idOrEmail);
return {
content: [{
type: "text",
text: `Successfully deleted user: ${idOrEmail}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "list-variables": {
const { clientId } = args as { clientId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const variables = await client.listVariables();
return {
content: [{
type: "text",
text: JSON.stringify(variables.data, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "create-variable": {
const { clientId, key, value } = args as { clientId: string; key: string; value: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.createVariable(key, value);
return {
content: [{
type: "text",
text: `Successfully created variable with key: ${key}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-variable": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
await client.deleteVariable(id);
return {
content: [{
type: "text",
text: `Successfully deleted variable with ID: ${id}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "create-credential": {
const { clientId, name, type, data } = args as {
clientId: string;
name: string;
type: string;
data: Record<string, any>;
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const credential = await client.createCredential(name, type, data);
return {
content: [{
type: "text",
text: `Successfully created credential:\n${JSON.stringify(credential, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-credential": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const result = await client.deleteCredential(id);
return {
content: [{
type: "text",
text: `Successfully deleted credential:\n${JSON.stringify(result, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-credential-schema": {
const { clientId, credentialTypeName } = args as { clientId: string; credentialTypeName: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const schema = await client.getCredentialSchema(credentialTypeName);
return {
content: [{
type: "text",
text: JSON.stringify(schema, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
// Execution Management Handlers
case "list-executions": {
const { clientId, includeData, status, workflowId, limit } = args as {
clientId: string;
includeData?: boolean;
status?: 'error' | 'success' | 'waiting';
workflowId?: string;
limit?: number;
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const executions = await client.getExecutions({ includeData, status, workflowId, limit });
return {
content: [{
type: "text",
text: JSON.stringify(executions.data, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-execution": {
const { clientId, id, includeData } = args as { clientId: string; id: number; includeData?: boolean };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const execution = await client.getExecution(id, includeData);
return {
content: [{
type: "text",
text: JSON.stringify(execution, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-execution": {
const { clientId, id } = args as { clientId: string; id: number };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const execution = await client.deleteExecution(id);
return {
content: [{
type: "text",
text: `Successfully deleted execution:\n${JSON.stringify(execution, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
// Tag Management Handlers
case "create-tag": {
const { clientId, name } = args as { clientId: string; name: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tag = await client.createTag(name);
return {
content: [{
type: "text",
text: `Successfully created tag:\n${JSON.stringify(tag, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "list-tags": {
const { clientId, limit } = args as { clientId: string; limit?: number };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tags = await client.getTags({ limit });
return {
content: [{
type: "text",
text: JSON.stringify(tags.data, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-tag": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tag = await client.getTag(id);
return {
content: [{
type: "text",
text: JSON.stringify(tag, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "update-tag": {
const { clientId, id, name } = args as { clientId: string; id: string; name: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tag = await client.updateTag(id, name);
return {
content: [{
type: "text",
text: `Successfully updated tag:\n${JSON.stringify(tag, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "delete-tag": {
const { clientId, id } = args as { clientId: string; id: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tag = await client.deleteTag(id);
return {
content: [{
type: "text",
text: `Successfully deleted tag:\n${JSON.stringify(tag, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "get-workflow-tags": {
const { clientId, workflowId } = args as { clientId: string; workflowId: string };
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tags = await client.getWorkflowTags(workflowId);
return {
content: [{
type: "text",
text: JSON.stringify(tags, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "update-workflow-tags": {
const { clientId, workflowId, tagIds } = args as {
clientId: string;
workflowId: string;
tagIds: { id: string }[];
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const tags = await client.updateWorkflowTags(workflowId, tagIds);
return {
content: [{
type: "text",
text: `Successfully updated workflow tags:\n${JSON.stringify(tags, null, 2)}`,
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
case "generate-audit": {
const { clientId, daysAbandonedWorkflow, categories } = args as {
clientId: string;
daysAbandonedWorkflow?: number;
categories?: Array<'credentials' | 'database' | 'nodes' | 'filesystem' | 'instance'>;
};
const client = clients.get(clientId);
if (!client) {
return {
content: [{
type: "text",
text: "Client not initialized. Please run init-n8n first.",
}],
isError: true
};
}
try {
const audit = await client.generateAudit({ daysAbandonedWorkflow, categories });
return {
content: [{
type: "text",
text: JSON.stringify(audit, null, 2),
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred",
}],
isError: true
};
}
}
default:
return {
content: [{
type: "text",
text: `Unknown tool: ${name}`,
}],
isError: true
};
}
});
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("N8N MCP Server running on stdio");
```