This is page 1 of 2. Use http://codebase.md/illuminaresolutions/n8n-mcp-server?lines=true&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: -------------------------------------------------------------------------------- ``` 1 | # Build 2 | build/ 3 | dist/ 4 | *.tsbuildinfo 5 | 6 | # Dependencies 7 | node_modules/ 8 | .pnp/ 9 | .pnp.js 10 | .npm/ 11 | 12 | # Environment 13 | .env 14 | .env.local 15 | .env.*.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | # Logs 21 | logs/ 22 | *.log 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | lerna-debug.log* 27 | 28 | # IDE 29 | .idea/ 30 | .vscode/ 31 | *.swp 32 | *.swo 33 | .project 34 | .classpath 35 | .settings/ 36 | *.sublime-workspace 37 | *.sublime-project 38 | 39 | # OS 40 | .DS_Store 41 | .DS_Store? 42 | ._* 43 | .Spotlight-V100 44 | .Trashes 45 | ehthumbs.db 46 | Thumbs.db 47 | Desktop.ini 48 | 49 | # Testing 50 | coverage/ 51 | .nyc_output/ 52 | junit.xml 53 | *.lcov 54 | 55 | # Temporary files 56 | *.tmp 57 | *.temp 58 | .cache/ 59 | .temp/ 60 | tmp/ 61 | 62 | # TypeScript 63 | *.js.map 64 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # n8n MCP Server 2 | 3 | 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. 4 | 5 | ## Installation 6 | 7 | ### Get your n8n API Key 8 | 9 | 1. Log into your n8n instance 10 | 2. Click your user icon in the bottom left 11 | 3. Go to Settings 12 | 4. Select API 13 | 5. Click "Create API Key" 14 | 6. Copy your API key (you won't be able to see it again) 15 | 16 | ### Install the MCP Server 17 | 18 | #### Option 1: Install from npm (Recommended) 19 | 20 | ```bash 21 | npm install -g @illuminaresolutions/n8n-mcp-server 22 | ``` 23 | 24 | #### Option 2: Install from Source 25 | 26 | 1. Clone the repository: 27 | ```bash 28 | git clone https://github.com/illuminaresolutions/n8n-mcp-server.git 29 | cd n8n-mcp-server 30 | ``` 31 | 32 | 2. Install dependencies and build: 33 | ```bash 34 | npm install 35 | npm run build 36 | ``` 37 | 38 | 3. Start the server in the background: 39 | ```bash 40 | nohup npm start > n8n-mcp.log 2>&1 & 41 | ``` 42 | 43 | To stop the server: 44 | ```bash 45 | pkill -f "node build/index.js" 46 | ``` 47 | 48 | Note: When installing from npm, the server will be available as `n8n-mcp-server` in your PATH. 49 | 50 | ## Configuration 51 | 52 | ### Claude Desktop 53 | 54 | 1. Open your Claude Desktop configuration: 55 | ``` 56 | ~/Library/Application Support/Claude/claude_desktop_config.json 57 | ``` 58 | 59 | 2. Add the n8n configuration: 60 | ```json 61 | { 62 | "mcpServers": { 63 | "n8n": { 64 | "command": "n8n-mcp-server", 65 | "env": { 66 | "N8N_HOST": "https://your-n8n-instance.com", 67 | "N8N_API_KEY": "your-api-key-here" 68 | } 69 | } 70 | } 71 | } 72 | ``` 73 | 74 | ### Cline (VS Code) 75 | 76 | 1. Install the server (follow Installation steps above) 77 | 2. Open VS Code 78 | 3. Open the Cline extension from the left sidebar 79 | 4. Click the 'MCP Servers' icon at the top of the pane 80 | 5. Scroll to bottom and click 'Configure MCP Servers' 81 | 6. Add to the opened settings file: 82 | ```json 83 | { 84 | "mcpServers": { 85 | "n8n": { 86 | "command": "n8n-mcp-server", 87 | "env": { 88 | "N8N_HOST": "https://your-n8n-instance.com", 89 | "N8N_API_KEY": "your-api-key-here" 90 | } 91 | } 92 | } 93 | } 94 | ``` 95 | 7. Save the file 96 | 8. Ensure the MCP toggle is enabled (green) and the status indicator is green 97 | 9. Start using MCP commands in Cline 98 | 99 | ### Sage 100 | 101 | Coming soon! The n8n MCP server will be available through: 102 | - Smithery.ai marketplace 103 | - Import from Claude Desktop 104 | 105 | For now, please use Claude Desktop or Cline. 106 | 107 | ## Validation 108 | 109 | After configuration: 110 | 111 | 1. Restart your LLM application 112 | 2. Ask: "List my n8n workflows" 113 | 3. You should see your workflows listed 114 | 115 | If you get an error: 116 | - Check that your n8n instance is running 117 | - Verify your API key has correct permissions 118 | - Ensure N8N_HOST has no trailing slash 119 | 120 | ## Features 121 | 122 | ### Core Features 123 | - List and manage workflows 124 | - View workflow details 125 | - Execute workflows 126 | - Manage credentials 127 | - Handle tags and executions 128 | - Generate security audits 129 | - Manage workflow tags 130 | 131 | ### Enterprise Features 132 | These features require an n8n Enterprise license: 133 | - Project management 134 | - Variable management 135 | - Advanced user management 136 | 137 | ## Troubleshooting 138 | 139 | ### Common Issues 140 | 141 | 1. "Client not initialized" 142 | - Check N8N_HOST and N8N_API_KEY are set correctly 143 | - Ensure n8n instance is accessible 144 | - Verify API key permissions 145 | 146 | 2. "License required" 147 | - You're trying to use an Enterprise feature 148 | - Either upgrade to n8n Enterprise or use core features only 149 | 150 | 3. Connection Issues 151 | - Verify n8n instance is running 152 | - Check URL protocol (http/https) 153 | - Remove trailing slash from N8N_HOST 154 | 155 | ## Security Best Practices 156 | 157 | 1. API Key Management 158 | - Use minimal permissions necessary 159 | - Rotate keys regularly 160 | - Never commit keys to version control 161 | 162 | 2. Instance Access 163 | - Use HTTPS for production 164 | - Enable n8n authentication 165 | - Keep n8n updated 166 | 167 | ## Support 168 | 169 | - [GitHub Issues](https://github.com/illuminaresolutions/n8n-mcp-server/issues) 170 | - [n8n Documentation](https://docs.n8n.io) 171 | 172 | ## License 173 | 174 | [MIT License](LICENSE) 175 | ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ES2022", 5 | "moduleResolution": "node", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "allowJs": true 13 | }, 14 | "include": ["src/**/*"] 15 | } ``` -------------------------------------------------------------------------------- /smithery.yml: -------------------------------------------------------------------------------- ```yaml 1 | name: n8n-mcp-server 2 | version: 1.0.0 3 | description: An MCP server that provides access to n8n workflows, executions, credentials, and more through the Model Context Protocol 4 | 5 | author: Illuminare Solutions 6 | license: MIT 7 | repository: https://github.com/illuminaresolutions/n8n-mcp-server 8 | 9 | type: mcp-server 10 | category: automation 11 | 12 | requirements: 13 | node: ">=18.0.0" 14 | 15 | installation: 16 | npm: "@illuminaresolutions/n8n-mcp-server" 17 | 18 | configuration: 19 | env: 20 | N8N_HOST: 21 | description: "Your n8n instance URL (e.g., https://your-n8n-instance.com)" 22 | required: true 23 | N8N_API_KEY: 24 | description: "Your n8n API key" 25 | required: true 26 | secret: true 27 | 28 | capabilities: 29 | - workflow-management 30 | - credential-management 31 | - execution-monitoring 32 | - tag-management 33 | - security-audit 34 | - user-management 35 | - project-management 36 | - variable-management 37 | 38 | tags: 39 | - n8n 40 | - automation 41 | - workflow 42 | - mcp 43 | - llm 44 | - ai 45 | - claude 46 | 47 | documentation: 48 | getting_started: https://github.com/illuminaresolutions/n8n-mcp-server#installation 49 | configuration: https://github.com/illuminaresolutions/n8n-mcp-server#configuration 50 | api_reference: https://github.com/illuminaresolutions/n8n-mcp-server/blob/main/N8N_API.yml 51 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@illuminaresolutions/n8n-mcp-server", 3 | "description": "An MCP server that provides access to n8n workflows, executions, credentials, and more through the Model Context Protocol", 4 | "version": "1.0.0", 5 | "type": "module", 6 | "bin": { 7 | "n8n-mcp-server": "build/index.js" 8 | }, 9 | "files": [ 10 | "build", 11 | "README.md", 12 | "LICENSE" 13 | ], 14 | "license": "MIT", 15 | "author": "Illuminare Solutions", 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/illuminaresolutions/n8n-mcp-server.git" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/illuminaresolutions/n8n-mcp-server/issues" 25 | }, 26 | "homepage": "https://github.com/illuminaresolutions/n8n-mcp-server#readme", 27 | "engines": { 28 | "node": ">=18.0.0" 29 | }, 30 | "keywords": [ 31 | "n8n", 32 | "mcp", 33 | "automation", 34 | "workflow", 35 | "llm", 36 | "ai", 37 | "claude", 38 | "modelcontextprotocol" 39 | ], 40 | "scripts": { 41 | "build": "tsc && chmod +x build/index.js", 42 | "start": "node build/index.js", 43 | "prepublishOnly": "npm run build", 44 | "clean": "rm -rf build", 45 | "lint": "tsc --noEmit" 46 | }, 47 | "dependencies": { 48 | "@modelcontextprotocol/sdk": "^0.7.0", 49 | "zod": "^3.22.4", 50 | "node-fetch": "^3.3.2" 51 | }, 52 | "devDependencies": { 53 | "@types/node": "^20.11.5", 54 | "typescript": "^5.3.3" 55 | } 56 | } 57 | ``` -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- ```markdown 1 | # Development Guide 2 | 3 | ## Core Principles 4 | 5 | 1. **Keep It Simple** 6 | - Expand src/index.ts as needed - avoid complex directory structures 7 | - Focus on core functionality first 8 | - Use built-in Node.js features when possible 9 | - Check N8N_API.yml for correct endpoints/methods 10 | 11 | 2. **Document Only What Works** 12 | - No *public* "roadmap" or planned features 13 | - Only document implemented functionality 14 | - Keep documentation clear and focused 15 | 16 | 3. **JSON Requirements** 17 | - All tool arguments must be compact, single-line JSON 18 | - Example: `{"clientId":"abc123","id":"workflow123"}` 19 | 20 | 4. **Workflow Creation** 21 | - Include nodes and connections arrays (even if empty) 22 | - 'active' property is read-only 23 | ```json 24 | { 25 | "clientId": "abc123", 26 | "name": "My Workflow", 27 | "nodes": [], 28 | "connections": {} 29 | } 30 | ``` 31 | 32 | 5. **Enterprise Features** 33 | - Project/variable management require Enterprise license 34 | - Base workflow features work without license 35 | - Clear error messages for license requirements 36 | 37 | ## What Not To Do 38 | 39 | 1. **No Overcomplication** 40 | - Don't create complex directory structures 41 | - Don't add unnecessary dependencies 42 | - Use built-in fetch instead of importing it 43 | - Check if functionality exists before adding imports 44 | 45 | 2. **No Speculative Documentation** 46 | - Don't document unimplemented features 47 | - Don't maintain *public* planning documents 48 | - Don't commit planning docs as implementation 49 | 50 | 3. **No Feature Creep** 51 | - Add features only when fully designed 52 | - Follow github repo's simple approach 53 | - Focus on core functionality first 54 | 55 | 4. **No Roadmaps** 56 | - Document only what exists 57 | - Keep focus on current functionality 58 | - Clear, concise documentation 59 | ``` -------------------------------------------------------------------------------- /TYPEKIT_MCP_SDK.md: -------------------------------------------------------------------------------- ```markdown 1 | # MCP TypeScript SDK   2 | 3 | ## Table of Contents 4 | - [Overview](#overview) 5 | - [Installation](#installation) 6 | - [Quickstart](#quickstart) 7 | - [What is MCP?](#what-is-mcp) 8 | - [Core Concepts](#core-concepts) 9 | - [Server](#server) 10 | - [Resources](#resources) 11 | - [Tools](#tools) 12 | - [Prompts](#prompts) 13 | - [Running Your Server](#running-your-server) 14 | - [stdio](#stdio) 15 | - [HTTP with SSE](#http-with-sse) 16 | - [Testing and Debugging](#testing-and-debugging) 17 | - [Examples](#examples) 18 | - [Echo Server](#echo-server) 19 | - [SQLite Explorer](#sqlite-explorer) 20 | - [Advanced Usage](#advanced-usage) 21 | - [Low-Level Server](#low-level-server) 22 | - [Writing MCP Clients](#writing-mcp-clients) 23 | - [Server Capabilities](#server-capabilities) 24 | 25 | ## Overview 26 | 27 | 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: 28 | 29 | - Build MCP clients that can connect to any MCP server 30 | - Create MCP servers that expose resources, prompts and tools 31 | - Use standard transports like stdio and SSE 32 | - Handle all MCP protocol messages and lifecycle events 33 | 34 | ## Installation 35 | 36 | ```bash 37 | npm install @modelcontextprotocol/sdk 38 | ``` 39 | 40 | ## Quick Start 41 | 42 | Let's create a simple MCP server that exposes a calculator tool and some data: 43 | 44 | ```typescript 45 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; 46 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 47 | import { z } from "zod"; 48 | 49 | // Create an MCP server 50 | const server = new McpServer({ 51 | name: "Demo", 52 | version: "1.0.0" 53 | }); 54 | 55 | // Add an addition tool 56 | server.tool("add", 57 | { a: z.number(), b: z.number() }, 58 | async ({ a, b }) => ({ 59 | content: [{ type: "text", text: String(a + b) }] 60 | }) 61 | ); 62 | 63 | // Add a dynamic greeting resource 64 | server.resource( 65 | "greeting", 66 | new ResourceTemplate("greeting://{name}", { list: undefined }), 67 | async (uri, { name }) => ({ 68 | contents: [{ 69 | uri: uri.href, 70 | text: `Hello, ${name}!` 71 | }] 72 | }) 73 | ); 74 | 75 | // Start receiving messages on stdin and sending messages on stdout 76 | const transport = new StdioServerTransport(); 77 | await server.connect(transport); 78 | ``` 79 | 80 | ## What is MCP? 81 | 82 | 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: 83 | 84 | - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context) 85 | - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) 86 | - Define interaction patterns through **Prompts** (reusable templates for LLM interactions) 87 | - And more! 88 | 89 | ## Core Concepts 90 | 91 | ### Server 92 | 93 | The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing: 94 | 95 | ```typescript 96 | const server = new McpServer({ 97 | name: "My App", 98 | version: "1.0.0" 99 | }); 100 | ``` 101 | 102 | ### Resources 103 | 104 | 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: 105 | 106 | ```typescript 107 | // Static resource 108 | server.resource( 109 | "config", 110 | "config://app", 111 | async (uri) => ({ 112 | contents: [{ 113 | uri: uri.href, 114 | text: "App configuration here" 115 | }] 116 | }) 117 | ); 118 | 119 | // Dynamic resource with parameters 120 | server.resource( 121 | "user-profile", 122 | new ResourceTemplate("users://{userId}/profile", { list: undefined }), 123 | async (uri, { userId }) => ({ 124 | contents: [{ 125 | uri: uri.href, 126 | text: `Profile data for user ${userId}` 127 | }] 128 | }) 129 | ); 130 | ``` 131 | 132 | ### Tools 133 | 134 | Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects: 135 | 136 | ```typescript 137 | // Simple tool with parameters 138 | server.tool( 139 | "calculate-bmi", 140 | { 141 | weightKg: z.number(), 142 | heightM: z.number() 143 | }, 144 | async ({ weightKg, heightM }) => ({ 145 | content: [{ 146 | type: "text", 147 | text: String(weightKg / (heightM * heightM)) 148 | }] 149 | }) 150 | ); 151 | 152 | // Async tool with external API call 153 | server.tool( 154 | "fetch-weather", 155 | { city: z.string() }, 156 | async ({ city }) => { 157 | const response = await fetch(`https://api.weather.com/${city}`); 158 | const data = await response.text(); 159 | return { 160 | content: [{ type: "text", text: data }] 161 | }; 162 | } 163 | ); 164 | ``` 165 | 166 | ### Prompts 167 | 168 | Prompts are reusable templates that help LLMs interact with your server effectively: 169 | 170 | ```typescript 171 | server.prompt( 172 | "review-code", 173 | { code: z.string() }, 174 | ({ code }) => ({ 175 | messages: [{ 176 | role: "user", 177 | content: { 178 | type: "text", 179 | text: `Please review this code:\n\n${code}` 180 | } 181 | }] 182 | }) 183 | ); 184 | ``` 185 | 186 | ## Running Your Server 187 | 188 | 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: 189 | 190 | ### stdio 191 | 192 | For command-line tools and direct integrations: 193 | 194 | ```typescript 195 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 196 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 197 | 198 | const server = new McpServer({ 199 | name: "example-server", 200 | version: "1.0.0" 201 | }); 202 | 203 | // ... set up server resources, tools, and prompts ... 204 | 205 | const transport = new StdioServerTransport(); 206 | await server.connect(transport); 207 | ``` 208 | 209 | ### HTTP with SSE 210 | 211 | 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: 212 | 213 | ```typescript 214 | import express from "express"; 215 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 216 | import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; 217 | 218 | const server = new McpServer({ 219 | name: "example-server", 220 | version: "1.0.0" 221 | }); 222 | 223 | // ... set up server resources, tools, and prompts ... 224 | 225 | const app = express(); 226 | 227 | app.get("/sse", async (req, res) => { 228 | const transport = new SSEServerTransport("/messages", res); 229 | await server.connect(transport); 230 | }); 231 | 232 | app.post("/messages", async (req, res) => { 233 | // Note: to support multiple simultaneous connections, these messages will 234 | // need to be routed to a specific matching transport. (This logic isn't 235 | // implemented here, for simplicity.) 236 | await transport.handlePostMessage(req, res); 237 | }); 238 | 239 | app.listen(3001); 240 | ``` 241 | 242 | ### Testing and Debugging 243 | 244 | To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information. 245 | 246 | ## Examples 247 | 248 | ### Echo Server 249 | 250 | A simple server demonstrating resources, tools, and prompts: 251 | 252 | ```typescript 253 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; 254 | import { z } from "zod"; 255 | 256 | const server = new McpServer({ 257 | name: "Echo", 258 | version: "1.0.0" 259 | }); 260 | 261 | server.resource( 262 | "echo", 263 | new ResourceTemplate("echo://{message}", { list: undefined }), 264 | async (uri, { message }) => ({ 265 | contents: [{ 266 | uri: uri.href, 267 | text: `Resource echo: ${message}` 268 | }] 269 | }) 270 | ); 271 | 272 | server.tool( 273 | "echo", 274 | { message: z.string() }, 275 | async ({ message }) => ({ 276 | content: [{ type: "text", text: `Tool echo: ${message}` }] 277 | }) 278 | ); 279 | 280 | server.prompt( 281 | "echo", 282 | { message: z.string() }, 283 | ({ message }) => ({ 284 | messages: [{ 285 | role: "user", 286 | content: { 287 | type: "text", 288 | text: `Please process this message: ${message}` 289 | } 290 | }] 291 | }) 292 | ); 293 | ``` 294 | 295 | ### SQLite Explorer 296 | 297 | A more complex example showing database integration: 298 | 299 | ```typescript 300 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 301 | import sqlite3 from "sqlite3"; 302 | import { promisify } from "util"; 303 | import { z } from "zod"; 304 | 305 | const server = new McpServer({ 306 | name: "SQLite Explorer", 307 | version: "1.0.0" 308 | }); 309 | 310 | // Helper to create DB connection 311 | const getDb = () => { 312 | const db = new sqlite3.Database("database.db"); 313 | return { 314 | all: promisify<string, any[]>(db.all.bind(db)), 315 | close: promisify(db.close.bind(db)) 316 | }; 317 | }; 318 | 319 | server.resource( 320 | "schema", 321 | "schema://main", 322 | async (uri) => { 323 | const db = getDb(); 324 | try { 325 | const tables = await db.all( 326 | "SELECT sql FROM sqlite_master WHERE type='table'" 327 | ); 328 | return { 329 | contents: [{ 330 | uri: uri.href, 331 | text: tables.map((t: {sql: string}) => t.sql).join("\n") 332 | }] 333 | }; 334 | } finally { 335 | await db.close(); 336 | } 337 | } 338 | ); 339 | 340 | server.tool( 341 | "query", 342 | { sql: z.string() }, 343 | async ({ sql }) => { 344 | const db = getDb(); 345 | try { 346 | const results = await db.all(sql); 347 | return { 348 | content: [{ 349 | type: "text", 350 | text: JSON.stringify(results, null, 2) 351 | }] 352 | }; 353 | } catch (err: unknown) { 354 | const error = err as Error; 355 | return { 356 | content: [{ 357 | type: "text", 358 | text: `Error: ${error.message}` 359 | }], 360 | isError: true 361 | }; 362 | } finally { 363 | await db.close(); 364 | } 365 | } 366 | ); 367 | ``` 368 | 369 | ## Advanced Usage 370 | 371 | ### Low-Level Server 372 | 373 | For more control, you can use the low-level Server class directly: 374 | 375 | ```typescript 376 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 377 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 378 | import { 379 | ListPromptsRequestSchema, 380 | GetPromptRequestSchema 381 | } from "@modelcontextprotocol/sdk/types.js"; 382 | 383 | const server = new Server( 384 | { 385 | name: "example-server", 386 | version: "1.0.0" 387 | }, 388 | { 389 | capabilities: { 390 | prompts: {} 391 | } 392 | } 393 | ); 394 | 395 | server.setRequestHandler(ListPromptsRequestSchema, async () => { 396 | return { 397 | prompts: [{ 398 | name: "example-prompt", 399 | description: "An example prompt template", 400 | arguments: [{ 401 | name: "arg1", 402 | description: "Example argument", 403 | required: true 404 | }] 405 | }] 406 | }; 407 | }); 408 | 409 | server.setRequestHandler(GetPromptRequestSchema, async (request) => { 410 | if (request.params.name !== "example-prompt") { 411 | throw new Error("Unknown prompt"); 412 | } 413 | return { 414 | description: "Example prompt", 415 | messages: [{ 416 | role: "user", 417 | content: { 418 | type: "text", 419 | text: "Example prompt text" 420 | } 421 | }] 422 | }; 423 | }); 424 | 425 | const transport = new StdioServerTransport(); 426 | await server.connect(transport); 427 | ``` 428 | 429 | ### Writing MCP Clients 430 | 431 | The SDK provides a high-level client interface: 432 | 433 | ```typescript 434 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; 435 | import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; 436 | 437 | const transport = new StdioClientTransport({ 438 | command: "node", 439 | args: ["server.js"] 440 | }); 441 | 442 | const client = new Client( 443 | { 444 | name: "example-client", 445 | version: "1.0.0" 446 | }, 447 | { 448 | capabilities: { 449 | prompts: {}, 450 | resources: {}, 451 | tools: {} 452 | } 453 | } 454 | ); 455 | 456 | await client.connect(transport); 457 | 458 | // List prompts 459 | const prompts = await client.listPrompts(); 460 | 461 | // Get a prompt 462 | const prompt = await client.getPrompt("example-prompt", { 463 | arg1: "value" 464 | }); 465 | 466 | // List resources 467 | const resources = await client.listResources(); 468 | 469 | // Read a resource 470 | const resource = await client.readResource("file:///example.txt"); 471 | 472 | // Call a tool 473 | const result = await client.callTool({ 474 | name: "example-tool", 475 | arguments: { 476 | arg1: "value" 477 | } 478 | }); 479 | ``` 480 | 481 | ## Documentation 482 | 483 | - [Model Context Protocol documentation](https://modelcontextprotocol.io) 484 | - [MCP Specification](https://spec.modelcontextprotocol.io) 485 | - [Example Servers](https://github.com/modelcontextprotocol/servers) 486 | 487 | ## Contributing 488 | 489 | Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk. 490 | 491 | ## License 492 | 493 | This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details. ``` -------------------------------------------------------------------------------- /N8N_API.yml: -------------------------------------------------------------------------------- ```yaml 1 | openapi: 3.0.0 2 | info: 3 | title: n8n Public API 4 | description: n8n Public API 5 | termsOfService: https://n8n.io/legal/terms 6 | contact: 7 | email: [email protected] 8 | license: 9 | name: Sustainable Use License 10 | url: https://github.com/n8n-io/n8n/blob/master/LICENSE.md 11 | version: 1.1.1 12 | servers: 13 | - url: /api/v1 14 | security: 15 | - ApiKeyAuth: [] 16 | tags: 17 | - name: User 18 | description: Operations about users 19 | - name: Audit 20 | description: Operations about security audit 21 | - name: Execution 22 | description: Operations about executions 23 | - name: Workflow 24 | description: Operations about workflows 25 | - name: Credential 26 | description: Operations about credentials 27 | - name: Tags 28 | description: Operations about tags 29 | - name: SourceControl 30 | description: Operations about source control 31 | - name: Variables 32 | description: Operations about variables 33 | - name: Projects 34 | description: Operations about projects 35 | externalDocs: 36 | description: n8n API documentation 37 | url: https://docs.n8n.io/api/ 38 | paths: 39 | /audit: 40 | post: 41 | x-eov-operation-id: generateAudit 42 | x-eov-operation-handler: v1/handlers/audit/audit.handler 43 | tags: 44 | - Audit 45 | summary: Generate an audit 46 | description: Generate a security audit for your n8n instance. 47 | requestBody: 48 | required: false 49 | content: 50 | application/json: 51 | schema: 52 | type: object 53 | properties: 54 | additionalOptions: 55 | type: object 56 | properties: 57 | daysAbandonedWorkflow: 58 | type: integer 59 | description: Days for a workflow to be considered abandoned if not executed 60 | categories: 61 | type: array 62 | items: 63 | type: string 64 | enum: 65 | - credentials 66 | - database 67 | - nodes 68 | - filesystem 69 | - instance 70 | responses: 71 | '200': 72 | description: Operation successful. 73 | content: 74 | application/json: 75 | schema: 76 | $ref: '#/components/schemas/audit' 77 | '401': 78 | $ref: '#/components/responses/unauthorized' 79 | '500': 80 | description: Internal server error. 81 | /credentials: 82 | post: 83 | x-eov-operation-id: createCredential 84 | x-eov-operation-handler: v1/handlers/credentials/credentials.handler 85 | tags: 86 | - Credential 87 | summary: Create a credential 88 | description: Creates a credential that can be used by nodes of the specified type. 89 | requestBody: 90 | description: Credential to be created. 91 | required: true 92 | content: 93 | application/json: 94 | schema: 95 | $ref: '#/components/schemas/credential' 96 | responses: 97 | '200': 98 | description: Operation successful. 99 | content: 100 | application/json: 101 | schema: 102 | $ref: '#/components/schemas/credential' 103 | '401': 104 | $ref: '#/components/responses/unauthorized' 105 | '415': 106 | description: Unsupported media type. 107 | /credentials/{id}: 108 | delete: 109 | x-eov-operation-id: deleteCredential 110 | x-eov-operation-handler: v1/handlers/credentials/credentials.handler 111 | tags: 112 | - Credential 113 | summary: Delete credential by ID 114 | description: Deletes a credential from your instance. You must be the owner of the credentials 115 | operationId: deleteCredential 116 | parameters: 117 | - name: id 118 | in: path 119 | description: The credential ID that needs to be deleted 120 | required: true 121 | schema: 122 | type: string 123 | responses: 124 | '200': 125 | description: Operation successful. 126 | content: 127 | application/json: 128 | schema: 129 | $ref: '#/components/schemas/credential' 130 | '401': 131 | $ref: '#/components/responses/unauthorized' 132 | '404': 133 | $ref: '#/components/responses/notFound' 134 | /credentials/schema/{credentialTypeName}: 135 | get: 136 | x-eov-operation-id: getCredentialType 137 | x-eov-operation-handler: v1/handlers/credentials/credentials.handler 138 | tags: 139 | - Credential 140 | summary: Show credential data schema 141 | parameters: 142 | - name: credentialTypeName 143 | in: path 144 | description: The credential type name that you want to get the schema for 145 | required: true 146 | schema: 147 | type: string 148 | responses: 149 | '200': 150 | description: Operation successful. 151 | content: 152 | application/json: 153 | schema: 154 | type: object 155 | examples: 156 | freshdeskApi: 157 | value: 158 | additionalProperties: false 159 | type: object 160 | properties: 161 | apiKey: 162 | type: string 163 | domain: 164 | type: string 165 | required: 166 | - apiKey 167 | - domain 168 | slackOAuth2Api: 169 | value: 170 | additionalProperties: false 171 | type: object 172 | properties: 173 | clientId: 174 | type: string 175 | clientSecret: 176 | type: string 177 | required: 178 | - clientId 179 | - clientSecret 180 | '401': 181 | $ref: '#/components/responses/unauthorized' 182 | '404': 183 | $ref: '#/components/responses/notFound' 184 | /executions: 185 | get: 186 | x-eov-operation-id: getExecutions 187 | x-eov-operation-handler: v1/handlers/executions/executions.handler 188 | tags: 189 | - Execution 190 | summary: Retrieve all executions 191 | description: Retrieve all executions from your instance. 192 | parameters: 193 | - $ref: '#/components/parameters/includeData' 194 | - name: status 195 | in: query 196 | description: Status to filter the executions by. 197 | required: false 198 | schema: 199 | type: string 200 | enum: 201 | - error 202 | - success 203 | - waiting 204 | - name: workflowId 205 | in: query 206 | description: Workflow to filter the executions by. 207 | required: false 208 | schema: 209 | type: string 210 | example: '1000' 211 | - name: projectId 212 | in: query 213 | required: false 214 | explode: false 215 | allowReserved: true 216 | schema: 217 | type: string 218 | example: VmwOO9HeTEj20kxM 219 | - $ref: '#/components/parameters/limit' 220 | - $ref: '#/components/parameters/cursor' 221 | responses: 222 | '200': 223 | description: Operation successful. 224 | content: 225 | application/json: 226 | schema: 227 | $ref: '#/components/schemas/executionList' 228 | '401': 229 | $ref: '#/components/responses/unauthorized' 230 | '404': 231 | $ref: '#/components/responses/notFound' 232 | /executions/{id}: 233 | get: 234 | x-eov-operation-id: getExecution 235 | x-eov-operation-handler: v1/handlers/executions/executions.handler 236 | tags: 237 | - Execution 238 | summary: Retrieve an execution 239 | description: Retrieve an execution from your instance. 240 | parameters: 241 | - $ref: '#/components/parameters/executionId' 242 | - $ref: '#/components/parameters/includeData' 243 | responses: 244 | '200': 245 | description: Operation successful. 246 | content: 247 | application/json: 248 | schema: 249 | $ref: '#/components/schemas/execution' 250 | '401': 251 | $ref: '#/components/responses/unauthorized' 252 | '404': 253 | $ref: '#/components/responses/notFound' 254 | delete: 255 | x-eov-operation-id: deleteExecution 256 | x-eov-operation-handler: v1/handlers/executions/executions.handler 257 | tags: 258 | - Execution 259 | summary: Delete an execution 260 | description: Deletes an execution from your instance. 261 | parameters: 262 | - $ref: '#/components/parameters/executionId' 263 | responses: 264 | '200': 265 | description: Operation successful. 266 | content: 267 | application/json: 268 | schema: 269 | $ref: '#/components/schemas/execution' 270 | '401': 271 | $ref: '#/components/responses/unauthorized' 272 | '404': 273 | $ref: '#/components/responses/notFound' 274 | /tags: 275 | post: 276 | x-eov-operation-id: createTag 277 | x-eov-operation-handler: v1/handlers/tags/tags.handler 278 | tags: 279 | - Tags 280 | summary: Create a tag 281 | description: Create a tag in your instance. 282 | requestBody: 283 | description: Created tag object. 284 | content: 285 | application/json: 286 | schema: 287 | $ref: '#/components/schemas/tag' 288 | required: true 289 | responses: 290 | '201': 291 | description: A tag object 292 | content: 293 | application/json: 294 | schema: 295 | $ref: '#/components/schemas/tag' 296 | '400': 297 | $ref: '#/components/responses/badRequest' 298 | '401': 299 | $ref: '#/components/responses/unauthorized' 300 | '409': 301 | $ref: '#/components/responses/conflict' 302 | get: 303 | x-eov-operation-id: getTags 304 | x-eov-operation-handler: v1/handlers/tags/tags.handler 305 | tags: 306 | - Tags 307 | summary: Retrieve all tags 308 | description: Retrieve all tags from your instance. 309 | parameters: 310 | - $ref: '#/components/parameters/limit' 311 | - $ref: '#/components/parameters/cursor' 312 | responses: 313 | '200': 314 | description: Operation successful. 315 | content: 316 | application/json: 317 | schema: 318 | $ref: '#/components/schemas/tagList' 319 | '401': 320 | $ref: '#/components/responses/unauthorized' 321 | /tags/{id}: 322 | get: 323 | x-eov-operation-id: getTag 324 | x-eov-operation-handler: v1/handlers/tags/tags.handler 325 | tags: 326 | - Tags 327 | summary: Retrieves a tag 328 | description: Retrieves a tag. 329 | parameters: 330 | - $ref: '#/components/parameters/tagId' 331 | responses: 332 | '200': 333 | description: Operation successful. 334 | content: 335 | application/json: 336 | schema: 337 | $ref: '#/components/schemas/tag' 338 | '401': 339 | $ref: '#/components/responses/unauthorized' 340 | '404': 341 | $ref: '#/components/responses/notFound' 342 | delete: 343 | x-eov-operation-id: deleteTag 344 | x-eov-operation-handler: v1/handlers/tags/tags.handler 345 | tags: 346 | - Tags 347 | summary: Delete a tag 348 | description: Deletes a tag. 349 | parameters: 350 | - $ref: '#/components/parameters/tagId' 351 | responses: 352 | '200': 353 | description: Operation successful. 354 | content: 355 | application/json: 356 | schema: 357 | $ref: '#/components/schemas/tag' 358 | '401': 359 | $ref: '#/components/responses/unauthorized' 360 | '403': 361 | $ref: '#/components/responses/forbidden' 362 | '404': 363 | $ref: '#/components/responses/notFound' 364 | put: 365 | x-eov-operation-id: updateTag 366 | x-eov-operation-handler: v1/handlers/tags/tags.handler 367 | tags: 368 | - Tags 369 | summary: Update a tag 370 | description: Update a tag. 371 | parameters: 372 | - $ref: '#/components/parameters/tagId' 373 | requestBody: 374 | description: Updated tag object. 375 | content: 376 | application/json: 377 | schema: 378 | $ref: '#/components/schemas/tag' 379 | required: true 380 | responses: 381 | '200': 382 | description: Tag object 383 | content: 384 | application/json: 385 | schema: 386 | $ref: '#/components/schemas/tag' 387 | '400': 388 | $ref: '#/components/responses/badRequest' 389 | '401': 390 | $ref: '#/components/responses/unauthorized' 391 | '404': 392 | $ref: '#/components/responses/notFound' 393 | '409': 394 | $ref: '#/components/responses/conflict' 395 | /workflows: 396 | post: 397 | x-eov-operation-id: createWorkflow 398 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 399 | tags: 400 | - Workflow 401 | summary: Create a workflow 402 | description: Create a workflow in your instance. 403 | requestBody: 404 | description: Created workflow object. 405 | content: 406 | application/json: 407 | schema: 408 | $ref: '#/components/schemas/workflow' 409 | required: true 410 | responses: 411 | '200': 412 | description: A workflow object 413 | content: 414 | application/json: 415 | schema: 416 | $ref: '#/components/schemas/workflow' 417 | '400': 418 | $ref: '#/components/responses/badRequest' 419 | '401': 420 | $ref: '#/components/responses/unauthorized' 421 | get: 422 | x-eov-operation-id: getWorkflows 423 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 424 | tags: 425 | - Workflow 426 | summary: Retrieve all workflows 427 | description: Retrieve all workflows from your instance. 428 | parameters: 429 | - name: active 430 | in: query 431 | schema: 432 | type: boolean 433 | example: true 434 | - name: tags 435 | in: query 436 | required: false 437 | explode: false 438 | allowReserved: true 439 | schema: 440 | type: string 441 | example: test,production 442 | - name: name 443 | in: query 444 | required: false 445 | explode: false 446 | allowReserved: true 447 | schema: 448 | type: string 449 | example: My Workflow 450 | - name: projectId 451 | in: query 452 | required: false 453 | explode: false 454 | allowReserved: true 455 | schema: 456 | type: string 457 | example: VmwOO9HeTEj20kxM 458 | - $ref: '#/components/parameters/limit' 459 | - $ref: '#/components/parameters/cursor' 460 | responses: 461 | '200': 462 | description: Operation successful. 463 | content: 464 | application/json: 465 | schema: 466 | $ref: '#/components/schemas/workflowList' 467 | '401': 468 | $ref: '#/components/responses/unauthorized' 469 | /workflows/{id}: 470 | get: 471 | x-eov-operation-id: getWorkflow 472 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 473 | tags: 474 | - Workflow 475 | summary: Retrieves a workflow 476 | description: Retrieves a workflow. 477 | parameters: 478 | - $ref: '#/components/parameters/workflowId' 479 | responses: 480 | '200': 481 | description: Operation successful. 482 | content: 483 | application/json: 484 | schema: 485 | $ref: '#/components/schemas/workflow' 486 | '401': 487 | $ref: '#/components/responses/unauthorized' 488 | '404': 489 | $ref: '#/components/responses/notFound' 490 | delete: 491 | x-eov-operation-id: deleteWorkflow 492 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 493 | tags: 494 | - Workflow 495 | summary: Delete a workflow 496 | description: Deletes a workflow. 497 | parameters: 498 | - $ref: '#/components/parameters/workflowId' 499 | responses: 500 | '200': 501 | description: Operation successful. 502 | content: 503 | application/json: 504 | schema: 505 | $ref: '#/components/schemas/workflow' 506 | '401': 507 | $ref: '#/components/responses/unauthorized' 508 | '404': 509 | $ref: '#/components/responses/notFound' 510 | put: 511 | x-eov-operation-id: updateWorkflow 512 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 513 | tags: 514 | - Workflow 515 | summary: Update a workflow 516 | description: Update a workflow. 517 | parameters: 518 | - $ref: '#/components/parameters/workflowId' 519 | requestBody: 520 | description: Updated workflow object. 521 | content: 522 | application/json: 523 | schema: 524 | $ref: '#/components/schemas/workflow' 525 | required: true 526 | responses: 527 | '200': 528 | description: Workflow object 529 | content: 530 | application/json: 531 | schema: 532 | $ref: '#/components/schemas/workflow' 533 | '400': 534 | $ref: '#/components/responses/badRequest' 535 | '401': 536 | $ref: '#/components/responses/unauthorized' 537 | '404': 538 | $ref: '#/components/responses/notFound' 539 | /workflows/{id}/activate: 540 | post: 541 | x-eov-operation-id: activateWorkflow 542 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 543 | tags: 544 | - Workflow 545 | summary: Activate a workflow 546 | description: Active a workflow. 547 | parameters: 548 | - $ref: '#/components/parameters/workflowId' 549 | responses: 550 | '200': 551 | description: Workflow object 552 | content: 553 | application/json: 554 | schema: 555 | $ref: '#/components/schemas/workflow' 556 | '401': 557 | $ref: '#/components/responses/unauthorized' 558 | '404': 559 | $ref: '#/components/responses/notFound' 560 | /workflows/{id}/deactivate: 561 | post: 562 | x-eov-operation-id: deactivateWorkflow 563 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 564 | tags: 565 | - Workflow 566 | summary: Deactivate a workflow 567 | description: Deactivate a workflow. 568 | parameters: 569 | - $ref: '#/components/parameters/workflowId' 570 | responses: 571 | '200': 572 | description: Workflow object 573 | content: 574 | application/json: 575 | schema: 576 | $ref: '#/components/schemas/workflow' 577 | '401': 578 | $ref: '#/components/responses/unauthorized' 579 | '404': 580 | $ref: '#/components/responses/notFound' 581 | /workflows/{id}/transfer: 582 | put: 583 | x-eov-operation-id: transferWorkflow 584 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 585 | tags: 586 | - Workflow 587 | summary: Transfer a workflow to another project. 588 | description: Transfer a workflow to another project. 589 | parameters: 590 | - $ref: '#/components/parameters/workflowId' 591 | requestBody: 592 | description: Destination project information for the workflow transfer. 593 | content: 594 | application/json: 595 | schema: 596 | type: object 597 | properties: 598 | destinationProjectId: 599 | type: string 600 | description: The ID of the project to transfer the workflow to. 601 | required: 602 | - destinationProjectId 603 | required: true 604 | responses: 605 | '200': 606 | description: Operation successful. 607 | '400': 608 | $ref: '#/components/responses/badRequest' 609 | '401': 610 | $ref: '#/components/responses/unauthorized' 611 | '404': 612 | $ref: '#/components/responses/notFound' 613 | /credentials/{id}/transfer: 614 | put: 615 | x-eov-operation-id: transferCredential 616 | x-eov-operation-handler: v1/handlers/credentials/credentials.handler 617 | tags: 618 | - Workflow 619 | summary: Transfer a credential to another project. 620 | description: Transfer a credential to another project. 621 | parameters: 622 | - $ref: '#/components/parameters/credentialId' 623 | requestBody: 624 | description: Destination project for the credential transfer. 625 | content: 626 | application/json: 627 | schema: 628 | type: object 629 | properties: 630 | destinationProjectId: 631 | type: string 632 | description: The ID of the project to transfer the credential to. 633 | required: 634 | - destinationProjectId 635 | required: true 636 | responses: 637 | '200': 638 | description: Operation successful. 639 | '400': 640 | $ref: '#/components/responses/badRequest' 641 | '401': 642 | $ref: '#/components/responses/unauthorized' 643 | '404': 644 | $ref: '#/components/responses/notFound' 645 | /workflows/{id}/tags: 646 | get: 647 | x-eov-operation-id: getWorkflowTags 648 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 649 | tags: 650 | - Workflow 651 | summary: Get workflow tags 652 | description: Get workflow tags. 653 | parameters: 654 | - $ref: '#/components/parameters/workflowId' 655 | responses: 656 | '200': 657 | description: List of tags 658 | content: 659 | application/json: 660 | schema: 661 | $ref: '#/components/schemas/workflowTags' 662 | '400': 663 | $ref: '#/components/responses/badRequest' 664 | '401': 665 | $ref: '#/components/responses/unauthorized' 666 | '404': 667 | $ref: '#/components/responses/notFound' 668 | put: 669 | x-eov-operation-id: updateWorkflowTags 670 | x-eov-operation-handler: v1/handlers/workflows/workflows.handler 671 | tags: 672 | - Workflow 673 | summary: Update tags of a workflow 674 | description: Update tags of a workflow. 675 | parameters: 676 | - $ref: '#/components/parameters/workflowId' 677 | requestBody: 678 | description: List of tags 679 | content: 680 | application/json: 681 | schema: 682 | $ref: '#/components/schemas/tagIds' 683 | required: true 684 | responses: 685 | '200': 686 | description: List of tags after add the tag 687 | content: 688 | application/json: 689 | schema: 690 | $ref: '#/components/schemas/workflowTags' 691 | '400': 692 | $ref: '#/components/responses/badRequest' 693 | '401': 694 | $ref: '#/components/responses/unauthorized' 695 | '404': 696 | $ref: '#/components/responses/notFound' 697 | /users: 698 | get: 699 | x-eov-operation-id: getUsers 700 | x-eov-operation-handler: v1/handlers/users/users.handler.ee 701 | tags: 702 | - User 703 | summary: Retrieve all users 704 | description: Retrieve all users from your instance. Only available for the instance owner. 705 | parameters: 706 | - $ref: '#/components/parameters/limit' 707 | - $ref: '#/components/parameters/cursor' 708 | - $ref: '#/components/parameters/includeRole' 709 | - name: projectId 710 | in: query 711 | required: false 712 | explode: false 713 | allowReserved: true 714 | schema: 715 | type: string 716 | example: VmwOO9HeTEj20kxM 717 | responses: 718 | '200': 719 | description: Operation successful. 720 | content: 721 | application/json: 722 | schema: 723 | $ref: '#/components/schemas/userList' 724 | '401': 725 | $ref: '#/components/responses/unauthorized' 726 | post: 727 | x-eov-operation-id: createUser 728 | x-eov-operation-handler: v1/handlers/users/users.handler.ee 729 | tags: 730 | - User 731 | summary: Create multiple users 732 | description: Create one or more users. 733 | requestBody: 734 | description: Array of users to be created. 735 | required: true 736 | content: 737 | application/json: 738 | schema: 739 | type: array 740 | items: 741 | type: object 742 | properties: 743 | email: 744 | type: string 745 | format: email 746 | role: 747 | type: string 748 | enum: 749 | - global:admin 750 | - global:member 751 | required: 752 | - email 753 | responses: 754 | '200': 755 | description: Operation successful. 756 | content: 757 | application/json: 758 | schema: 759 | type: object 760 | properties: 761 | user: 762 | type: object 763 | properties: 764 | id: 765 | type: string 766 | email: 767 | type: string 768 | inviteAcceptUrl: 769 | type: string 770 | emailSent: 771 | type: boolean 772 | error: 773 | type: string 774 | '401': 775 | $ref: '#/components/responses/unauthorized' 776 | '403': 777 | $ref: '#/components/responses/forbidden' 778 | /users/{id}: 779 | get: 780 | x-eov-operation-id: getUser 781 | x-eov-operation-handler: v1/handlers/users/users.handler.ee 782 | tags: 783 | - User 784 | summary: Get user by ID/Email 785 | description: Retrieve a user from your instance. Only available for the instance owner. 786 | parameters: 787 | - $ref: '#/components/parameters/userIdentifier' 788 | - $ref: '#/components/parameters/includeRole' 789 | responses: 790 | '200': 791 | description: Operation successful. 792 | content: 793 | application/json: 794 | schema: 795 | $ref: '#/components/schemas/user' 796 | '401': 797 | $ref: '#/components/responses/unauthorized' 798 | delete: 799 | x-eov-operation-id: deleteUser 800 | x-eov-operation-handler: v1/handlers/users/users.handler.ee 801 | tags: 802 | - User 803 | summary: Delete a user 804 | description: Delete a user from your instance. 805 | parameters: 806 | - $ref: '#/components/parameters/userIdentifier' 807 | responses: 808 | '204': 809 | description: Operation successful. 810 | '401': 811 | $ref: '#/components/responses/unauthorized' 812 | '403': 813 | $ref: '#/components/responses/forbidden' 814 | '404': 815 | $ref: '#/components/responses/notFound' 816 | /users/{id}/role: 817 | patch: 818 | x-eov-operation-id: changeRole 819 | x-eov-operation-handler: v1/handlers/users/users.handler.ee 820 | tags: 821 | - User 822 | summary: Change a user's global role 823 | description: Change a user's global role 824 | parameters: 825 | - $ref: '#/components/parameters/userIdentifier' 826 | requestBody: 827 | description: New role for the user 828 | required: true 829 | content: 830 | application/json: 831 | schema: 832 | type: object 833 | properties: 834 | newRoleName: 835 | type: string 836 | enum: 837 | - global:admin 838 | - global:member 839 | required: 840 | - newRoleName 841 | responses: 842 | '200': 843 | description: Operation successful. 844 | '401': 845 | $ref: '#/components/responses/unauthorized' 846 | '403': 847 | $ref: '#/components/responses/forbidden' 848 | '404': 849 | $ref: '#/components/responses/notFound' 850 | /source-control/pull: 851 | post: 852 | x-eov-operation-id: pull 853 | x-eov-operation-handler: v1/handlers/sourceControl/sourceControl.handler 854 | tags: 855 | - SourceControl 856 | summary: Pull changes from the remote repository 857 | description: Requires the Source Control feature to be licensed and connected to a repository. 858 | requestBody: 859 | description: Pull options 860 | required: true 861 | content: 862 | application/json: 863 | schema: 864 | $ref: '#/components/schemas/pull' 865 | responses: 866 | '200': 867 | description: Import result 868 | content: 869 | application/json: 870 | schema: 871 | $ref: '#/components/schemas/importResult' 872 | '400': 873 | $ref: '#/components/responses/badRequest' 874 | '409': 875 | $ref: '#/components/responses/conflict' 876 | /variables: 877 | post: 878 | x-eov-operation-id: createVariable 879 | x-eov-operation-handler: v1/handlers/variables/variables.handler 880 | tags: 881 | - Variables 882 | summary: Create a variable 883 | description: Create a variable in your instance. 884 | requestBody: 885 | description: Payload for variable to create. 886 | content: 887 | application/json: 888 | schema: 889 | $ref: '#/components/schemas/variable' 890 | required: true 891 | responses: 892 | '201': 893 | description: Operation successful. 894 | '400': 895 | $ref: '#/components/responses/badRequest' 896 | '401': 897 | $ref: '#/components/responses/unauthorized' 898 | get: 899 | x-eov-operation-id: getVariables 900 | x-eov-operation-handler: v1/handlers/variables/variables.handler 901 | tags: 902 | - Variables 903 | summary: Retrieve variables 904 | description: Retrieve variables from your instance. 905 | parameters: 906 | - $ref: '#/components/parameters/limit' 907 | - $ref: '#/components/parameters/cursor' 908 | responses: 909 | '200': 910 | description: Operation successful. 911 | content: 912 | application/json: 913 | schema: 914 | $ref: '#/components/schemas/variableList' 915 | '401': 916 | $ref: '#/components/responses/unauthorized' 917 | /variables/{id}: 918 | delete: 919 | x-eov-operation-id: deleteVariable 920 | x-eov-operation-handler: v1/handlers/variables/variables.handler 921 | tags: 922 | - Variables 923 | summary: Delete a variable 924 | description: Delete a variable from your instance. 925 | parameters: 926 | - $ref: '#/components/parameters/variableId' 927 | responses: 928 | '204': 929 | description: Operation successful. 930 | '401': 931 | $ref: '#/components/responses/unauthorized' 932 | '404': 933 | $ref: '#/components/responses/notFound' 934 | /projects: 935 | post: 936 | x-eov-operation-id: createProject 937 | x-eov-operation-handler: v1/handlers/projects/projects.handler 938 | tags: 939 | - Projects 940 | summary: Create a project 941 | description: Create a project in your instance. 942 | requestBody: 943 | description: Payload for project to create. 944 | content: 945 | application/json: 946 | schema: 947 | $ref: '#/components/schemas/project' 948 | required: true 949 | responses: 950 | '201': 951 | description: Operation successful. 952 | '400': 953 | $ref: '#/components/responses/badRequest' 954 | '401': 955 | $ref: '#/components/responses/unauthorized' 956 | get: 957 | x-eov-operation-id: getProjects 958 | x-eov-operation-handler: v1/handlers/projects/projects.handler 959 | tags: 960 | - Projects 961 | summary: Retrieve projects 962 | description: Retrieve projects from your instance. 963 | parameters: 964 | - $ref: '#/components/parameters/limit' 965 | - $ref: '#/components/parameters/cursor' 966 | responses: 967 | '200': 968 | description: Operation successful. 969 | content: 970 | application/json: 971 | schema: 972 | $ref: '#/components/schemas/projectList' 973 | '401': 974 | $ref: '#/components/responses/unauthorized' 975 | /projects/{projectId}: 976 | delete: 977 | x-eov-operation-id: deleteProject 978 | x-eov-operation-handler: v1/handlers/projects/projects.handler 979 | tags: 980 | - Projects 981 | summary: Delete a project 982 | description: Delete a project from your instance. 983 | parameters: 984 | - $ref: '#/components/parameters/projectId' 985 | responses: 986 | '204': 987 | description: Operation successful. 988 | '401': 989 | $ref: '#/components/responses/unauthorized' 990 | '403': 991 | $ref: '#/components/responses/forbidden' 992 | '404': 993 | $ref: '#/components/responses/notFound' 994 | put: 995 | x-eov-operation-id: updateProject 996 | x-eov-operation-handler: v1/handlers/projects/projects.handler 997 | tags: 998 | - Project 999 | summary: Update a project 1000 | description: Update a project. 1001 | requestBody: 1002 | description: Updated project object. 1003 | content: 1004 | application/json: 1005 | schema: 1006 | $ref: '#/components/schemas/project' 1007 | required: true 1008 | responses: 1009 | '204': 1010 | description: Operation successful. 1011 | '400': 1012 | $ref: '#/components/responses/badRequest' 1013 | '401': 1014 | $ref: '#/components/responses/unauthorized' 1015 | '403': 1016 | $ref: '#/components/responses/forbidden' 1017 | '404': 1018 | $ref: '#/components/responses/notFound' 1019 | components: 1020 | schemas: 1021 | audit: 1022 | type: object 1023 | properties: 1024 | Credentials Risk Report: 1025 | type: object 1026 | example: 1027 | risk: credentials 1028 | sections: 1029 | - title: Credentials not used in any workflow 1030 | description: These credentials are not used in any workflow. Keeping unused credentials in your instance is an unneeded security risk. 1031 | recommendation: Consider deleting these credentials if you no longer need them. 1032 | location: 1033 | - kind: credential 1034 | id: '1' 1035 | name: My Test Account 1036 | Database Risk Report: 1037 | type: object 1038 | example: 1039 | risk: database 1040 | sections: 1041 | - title: Expressions in "Execute Query" fields in SQL nodes 1042 | 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. 1043 | recommendation: Consider using the "Query Parameters" field to pass parameters to the query 1044 | or validating the input of the expression in the "Query" field.: null 1045 | location: 1046 | - kind: node 1047 | workflowId: '1' 1048 | workflowName: My Workflow 1049 | nodeId: 51eb5852-ce0b-4806-b4ff-e41322a4041a 1050 | nodeName: MySQL 1051 | nodeType: n8n-nodes-base.mySql 1052 | Filesystem Risk Report: 1053 | type: object 1054 | example: 1055 | risk: filesystem 1056 | sections: 1057 | - title: Nodes that interact with the filesystem 1058 | 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. 1059 | recommendation: Consider protecting any sensitive files in the host filesystem 1060 | or refactoring the workflow so that it does not require host filesystem interaction.: null 1061 | location: 1062 | - kind: node 1063 | workflowId: '1' 1064 | workflowName: My Workflow 1065 | nodeId: 51eb5852-ce0b-4806-b4ff-e41322a4041a 1066 | nodeName: Ready Binary file 1067 | nodeType: n8n-nodes-base.readBinaryFile 1068 | Nodes Risk Report: 1069 | type: object 1070 | example: 1071 | risk: nodes 1072 | sections: 1073 | - title: Community nodes 1074 | 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. 1075 | recommendation: Consider reviewing the source code in any community nodes installed in this n8n instance 1076 | and uninstalling any community nodes no longer used.: null 1077 | location: 1078 | - kind: community 1079 | nodeType: n8n-nodes-test.test 1080 | packageUrl: https://www.npmjs.com/package/n8n-nodes-test 1081 | Instance Risk Report: 1082 | type: object 1083 | example: 1084 | risk: execution 1085 | sections: 1086 | - title: Unprotected webhooks in instance 1087 | 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. 1088 | recommendation: Consider setting the "Authentication" field to an option other than "None" 1089 | or validating the payload with one of the following nodes.: null 1090 | location: 1091 | - kind: community 1092 | nodeType: n8n-nodes-test.test 1093 | packageUrl: https://www.npmjs.com/package/n8n-nodes-test 1094 | credential: 1095 | required: 1096 | - name 1097 | - type 1098 | - data 1099 | type: object 1100 | properties: 1101 | id: 1102 | type: string 1103 | readOnly: true 1104 | example: R2DjclaysHbqn778 1105 | name: 1106 | type: string 1107 | example: Joe's Github Credentials 1108 | type: 1109 | type: string 1110 | example: github 1111 | data: 1112 | type: object 1113 | writeOnly: true 1114 | example: 1115 | token: ada612vad6fa5df4adf5a5dsf4389adsf76da7s 1116 | createdAt: 1117 | type: string 1118 | format: date-time 1119 | readOnly: true 1120 | example: '2022-04-29T11:02:29.842Z' 1121 | updatedAt: 1122 | type: string 1123 | format: date-time 1124 | readOnly: true 1125 | example: '2022-04-29T11:02:29.842Z' 1126 | execution: 1127 | type: object 1128 | properties: 1129 | id: 1130 | type: number 1131 | example: 1000 1132 | data: 1133 | type: object 1134 | finished: 1135 | type: boolean 1136 | example: true 1137 | mode: 1138 | type: string 1139 | enum: 1140 | - cli 1141 | - error 1142 | - integrated 1143 | - internal 1144 | - manual 1145 | - retry 1146 | - trigger 1147 | - webhook 1148 | retryOf: 1149 | type: number 1150 | nullable: true 1151 | retrySuccessId: 1152 | type: number 1153 | nullable: true 1154 | example: '2' 1155 | startedAt: 1156 | type: string 1157 | format: date-time 1158 | stoppedAt: 1159 | type: string 1160 | format: date-time 1161 | workflowId: 1162 | type: number 1163 | example: '1000' 1164 | waitTill: 1165 | type: string 1166 | nullable: true 1167 | format: date-time 1168 | customData: 1169 | type: object 1170 | executionList: 1171 | type: object 1172 | properties: 1173 | data: 1174 | type: array 1175 | items: 1176 | $ref: '#/components/schemas/execution' 1177 | nextCursor: 1178 | type: string 1179 | 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. 1180 | nullable: true 1181 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1182 | tag: 1183 | type: object 1184 | additionalProperties: false 1185 | required: 1186 | - name 1187 | properties: 1188 | id: 1189 | type: string 1190 | readOnly: true 1191 | example: 2tUt1wbLX592XDdX 1192 | name: 1193 | type: string 1194 | example: Production 1195 | createdAt: 1196 | type: string 1197 | format: date-time 1198 | readOnly: true 1199 | updatedAt: 1200 | type: string 1201 | format: date-time 1202 | readOnly: true 1203 | tagList: 1204 | type: object 1205 | properties: 1206 | data: 1207 | type: array 1208 | items: 1209 | $ref: '#/components/schemas/tag' 1210 | nextCursor: 1211 | type: string 1212 | 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. 1213 | nullable: true 1214 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1215 | node: 1216 | type: object 1217 | additionalProperties: false 1218 | properties: 1219 | id: 1220 | type: string 1221 | example: 0f5532f9-36ba-4bef-86c7-30d607400b15 1222 | name: 1223 | type: string 1224 | example: Jira 1225 | webhookId: 1226 | type: string 1227 | disabled: 1228 | type: boolean 1229 | notesInFlow: 1230 | type: boolean 1231 | notes: 1232 | type: string 1233 | type: 1234 | type: string 1235 | example: n8n-nodes-base.Jira 1236 | typeVersion: 1237 | type: number 1238 | example: 1 1239 | executeOnce: 1240 | type: boolean 1241 | example: false 1242 | alwaysOutputData: 1243 | type: boolean 1244 | example: false 1245 | retryOnFail: 1246 | type: boolean 1247 | example: false 1248 | maxTries: 1249 | type: number 1250 | waitBetweenTries: 1251 | type: number 1252 | continueOnFail: 1253 | type: boolean 1254 | example: false 1255 | description: use onError instead 1256 | deprecated: true 1257 | onError: 1258 | type: string 1259 | example: stopWorkflow 1260 | position: 1261 | type: array 1262 | items: 1263 | type: number 1264 | example: 1265 | - -100 1266 | - 80 1267 | parameters: 1268 | type: object 1269 | example: 1270 | additionalProperties: {} 1271 | credentials: 1272 | type: object 1273 | example: 1274 | jiraSoftwareCloudApi: 1275 | id: '35' 1276 | name: jiraApi 1277 | createdAt: 1278 | type: string 1279 | format: date-time 1280 | readOnly: true 1281 | updatedAt: 1282 | type: string 1283 | format: date-time 1284 | readOnly: true 1285 | workflowSettings: 1286 | type: object 1287 | additionalProperties: false 1288 | properties: 1289 | saveExecutionProgress: 1290 | type: boolean 1291 | saveManualExecutions: 1292 | type: boolean 1293 | saveDataErrorExecution: 1294 | type: string 1295 | enum: 1296 | - all 1297 | - none 1298 | saveDataSuccessExecution: 1299 | type: string 1300 | enum: 1301 | - all 1302 | - none 1303 | executionTimeout: 1304 | type: number 1305 | example: 3600 1306 | maxLength: 3600 1307 | errorWorkflow: 1308 | type: string 1309 | example: VzqKEW0ShTXA5vPj 1310 | description: The ID of the workflow that contains the error trigger node. 1311 | timezone: 1312 | type: string 1313 | example: America/New_York 1314 | executionOrder: 1315 | type: string 1316 | example: v1 1317 | workflow: 1318 | type: object 1319 | additionalProperties: false 1320 | required: 1321 | - name 1322 | - nodes 1323 | - connections 1324 | - settings 1325 | properties: 1326 | id: 1327 | type: string 1328 | readOnly: true 1329 | example: 2tUt1wbLX592XDdX 1330 | name: 1331 | type: string 1332 | example: Workflow 1 1333 | active: 1334 | type: boolean 1335 | readOnly: true 1336 | createdAt: 1337 | type: string 1338 | format: date-time 1339 | readOnly: true 1340 | updatedAt: 1341 | type: string 1342 | format: date-time 1343 | readOnly: true 1344 | nodes: 1345 | type: array 1346 | items: 1347 | $ref: '#/components/schemas/node' 1348 | connections: 1349 | type: object 1350 | example: 1351 | main: 1352 | - node: Jira 1353 | type: main 1354 | index: 0 1355 | settings: 1356 | $ref: '#/components/schemas/workflowSettings' 1357 | staticData: 1358 | example: 1359 | lastId: 1 1360 | anyOf: 1361 | - type: string 1362 | format: jsonString 1363 | nullable: true 1364 | - type: object 1365 | nullable: true 1366 | tags: 1367 | type: array 1368 | items: 1369 | $ref: '#/components/schemas/tag' 1370 | readOnly: true 1371 | workflowList: 1372 | type: object 1373 | properties: 1374 | data: 1375 | type: array 1376 | items: 1377 | $ref: '#/components/schemas/workflow' 1378 | nextCursor: 1379 | type: string 1380 | 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. 1381 | nullable: true 1382 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1383 | workflowTags: 1384 | type: array 1385 | items: 1386 | $ref: '#/components/schemas/tag' 1387 | tagIds: 1388 | type: array 1389 | items: 1390 | type: object 1391 | additionalProperties: false 1392 | required: 1393 | - id 1394 | properties: 1395 | id: 1396 | type: string 1397 | example: 2tUt1wbLX592XDdX 1398 | user: 1399 | required: 1400 | - email 1401 | type: object 1402 | properties: 1403 | id: 1404 | type: string 1405 | readOnly: true 1406 | example: 123e4567-e89b-12d3-a456-426614174000 1407 | email: 1408 | type: string 1409 | format: email 1410 | example: [email protected] 1411 | firstName: 1412 | maxLength: 32 1413 | type: string 1414 | description: User's first name 1415 | readOnly: true 1416 | example: john 1417 | lastName: 1418 | maxLength: 32 1419 | type: string 1420 | description: User's last name 1421 | readOnly: true 1422 | example: Doe 1423 | isPending: 1424 | type: boolean 1425 | description: Whether the user finished setting up their account in response to the invitation (true) or not (false). 1426 | readOnly: true 1427 | createdAt: 1428 | type: string 1429 | description: Time the user was created. 1430 | format: date-time 1431 | readOnly: true 1432 | updatedAt: 1433 | type: string 1434 | description: Last time the user was updated. 1435 | format: date-time 1436 | readOnly: true 1437 | role: 1438 | type: string 1439 | example: owner 1440 | readOnly: true 1441 | userList: 1442 | type: object 1443 | properties: 1444 | data: 1445 | type: array 1446 | items: 1447 | $ref: '#/components/schemas/user' 1448 | nextCursor: 1449 | type: string 1450 | 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. 1451 | nullable: true 1452 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1453 | pull: 1454 | type: object 1455 | properties: 1456 | force: 1457 | type: boolean 1458 | example: true 1459 | variables: 1460 | type: object 1461 | example: 1462 | foo: bar 1463 | importResult: 1464 | type: object 1465 | additionalProperties: true 1466 | properties: 1467 | variables: 1468 | type: object 1469 | properties: 1470 | added: 1471 | type: array 1472 | items: 1473 | type: string 1474 | changed: 1475 | type: array 1476 | items: 1477 | type: string 1478 | credentials: 1479 | type: array 1480 | items: 1481 | type: object 1482 | properties: 1483 | id: 1484 | type: string 1485 | name: 1486 | type: string 1487 | type: 1488 | type: string 1489 | workflows: 1490 | type: array 1491 | items: 1492 | type: object 1493 | properties: 1494 | id: 1495 | type: string 1496 | name: 1497 | type: string 1498 | tags: 1499 | type: object 1500 | properties: 1501 | tags: 1502 | type: array 1503 | items: 1504 | type: object 1505 | properties: 1506 | id: 1507 | type: string 1508 | name: 1509 | type: string 1510 | mappings: 1511 | type: array 1512 | items: 1513 | type: object 1514 | properties: 1515 | workflowId: 1516 | type: string 1517 | tagId: 1518 | type: string 1519 | variable: 1520 | type: object 1521 | additionalProperties: false 1522 | required: 1523 | - key 1524 | - value 1525 | properties: 1526 | id: 1527 | type: string 1528 | readOnly: true 1529 | key: 1530 | type: string 1531 | value: 1532 | type: string 1533 | example: test 1534 | type: 1535 | type: string 1536 | readOnly: true 1537 | variableList: 1538 | type: object 1539 | properties: 1540 | data: 1541 | type: array 1542 | items: 1543 | $ref: '#/components/schemas/variable' 1544 | nextCursor: 1545 | type: string 1546 | 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. 1547 | nullable: true 1548 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1549 | project: 1550 | type: object 1551 | additionalProperties: false 1552 | required: 1553 | - name 1554 | properties: 1555 | id: 1556 | type: string 1557 | readOnly: true 1558 | name: 1559 | type: string 1560 | type: 1561 | type: string 1562 | readOnly: true 1563 | projectList: 1564 | type: object 1565 | properties: 1566 | data: 1567 | type: array 1568 | items: 1569 | $ref: '#/components/schemas/project' 1570 | nextCursor: 1571 | type: string 1572 | 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. 1573 | nullable: true 1574 | example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA 1575 | error: 1576 | required: 1577 | - message 1578 | type: object 1579 | properties: 1580 | code: 1581 | type: string 1582 | message: 1583 | type: string 1584 | description: 1585 | type: string 1586 | role: 1587 | readOnly: true 1588 | type: object 1589 | properties: 1590 | id: 1591 | type: number 1592 | readOnly: true 1593 | example: 1 1594 | name: 1595 | type: string 1596 | example: owner 1597 | readOnly: true 1598 | scope: 1599 | type: string 1600 | readOnly: true 1601 | example: global 1602 | createdAt: 1603 | type: string 1604 | description: Time the role was created. 1605 | format: date-time 1606 | readOnly: true 1607 | updatedAt: 1608 | type: string 1609 | description: Last time the role was updated. 1610 | format: date-time 1611 | readOnly: true 1612 | credentialType: 1613 | type: object 1614 | properties: 1615 | displayName: 1616 | type: string 1617 | readOnly: true 1618 | example: Email 1619 | name: 1620 | type: string 1621 | readOnly: true 1622 | example: email 1623 | type: 1624 | type: string 1625 | readOnly: true 1626 | example: string 1627 | default: 1628 | type: string 1629 | readOnly: true 1630 | example: string 1631 | Error: 1632 | $ref: '#/components/schemas/error' 1633 | Role: 1634 | $ref: '#/components/schemas/role' 1635 | Execution: 1636 | $ref: '#/components/schemas/execution' 1637 | Node: 1638 | $ref: '#/components/schemas/node' 1639 | Tag: 1640 | $ref: '#/components/schemas/tag' 1641 | Workflow: 1642 | $ref: '#/components/schemas/workflow' 1643 | WorkflowSettings: 1644 | $ref: '#/components/schemas/workflowSettings' 1645 | ExecutionList: 1646 | $ref: '#/components/schemas/executionList' 1647 | WorkflowList: 1648 | $ref: '#/components/schemas/workflowList' 1649 | Credential: 1650 | $ref: '#/components/schemas/credential' 1651 | CredentialType: 1652 | $ref: '#/components/schemas/credentialType' 1653 | Audit: 1654 | $ref: '#/components/schemas/audit' 1655 | Pull: 1656 | $ref: '#/components/schemas/pull' 1657 | ImportResult: 1658 | $ref: '#/components/schemas/importResult' 1659 | UserList: 1660 | $ref: '#/components/schemas/userList' 1661 | User: 1662 | $ref: '#/components/schemas/user' 1663 | responses: 1664 | unauthorized: 1665 | description: Unauthorized 1666 | notFound: 1667 | description: The specified resource was not found. 1668 | badRequest: 1669 | description: The request is invalid or provides malformed data. 1670 | conflict: 1671 | description: Conflict 1672 | forbidden: 1673 | description: Forbidden 1674 | NotFound: 1675 | $ref: '#/components/responses/notFound' 1676 | Unauthorized: 1677 | $ref: '#/components/responses/unauthorized' 1678 | BadRequest: 1679 | $ref: '#/components/responses/badRequest' 1680 | Conflict: 1681 | $ref: '#/components/responses/conflict' 1682 | Forbidden: 1683 | $ref: '#/components/responses/forbidden' 1684 | parameters: 1685 | includeData: 1686 | name: includeData 1687 | in: query 1688 | description: Whether or not to include the execution's detailed data. 1689 | required: false 1690 | schema: 1691 | type: boolean 1692 | limit: 1693 | name: limit 1694 | in: query 1695 | description: The maximum number of items to return. 1696 | required: false 1697 | schema: 1698 | type: number 1699 | example: 100 1700 | default: 100 1701 | maximum: 250 1702 | cursor: 1703 | name: cursor 1704 | in: query 1705 | 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. 1706 | required: false 1707 | style: form 1708 | schema: 1709 | type: string 1710 | executionId: 1711 | name: id 1712 | in: path 1713 | description: The ID of the execution. 1714 | required: true 1715 | schema: 1716 | type: number 1717 | tagId: 1718 | name: id 1719 | in: path 1720 | description: The ID of the tag. 1721 | required: true 1722 | schema: 1723 | type: string 1724 | workflowId: 1725 | name: id 1726 | in: path 1727 | description: The ID of the workflow. 1728 | required: true 1729 | schema: 1730 | type: string 1731 | credentialId: 1732 | name: id 1733 | in: path 1734 | description: The ID of the credential. 1735 | required: true 1736 | schema: 1737 | type: string 1738 | includeRole: 1739 | name: includeRole 1740 | in: query 1741 | description: Whether to include the user's role or not. 1742 | required: false 1743 | schema: 1744 | type: boolean 1745 | example: true 1746 | default: false 1747 | userIdentifier: 1748 | name: id 1749 | in: path 1750 | description: The ID or email of the user. 1751 | required: true 1752 | schema: 1753 | type: string 1754 | format: identifier 1755 | variableId: 1756 | name: id 1757 | in: path 1758 | description: The ID of the variable. 1759 | required: true 1760 | schema: 1761 | type: string 1762 | projectId: 1763 | name: projectId 1764 | in: path 1765 | description: The ID of the project. 1766 | required: true 1767 | schema: 1768 | type: string 1769 | Cursor: 1770 | $ref: '#/components/parameters/cursor' 1771 | Limit: 1772 | $ref: '#/components/parameters/limit' 1773 | ExecutionId: 1774 | $ref: '#/components/parameters/executionId' 1775 | WorkflowId: 1776 | $ref: '#/components/parameters/workflowId' 1777 | TagId: 1778 | $ref: '#/components/parameters/tagId' 1779 | IncludeData: 1780 | $ref: '#/components/parameters/includeData' 1781 | UserIdentifier: 1782 | $ref: '#/components/parameters/userIdentifier' 1783 | IncludeRole: 1784 | $ref: '#/components/parameters/includeRole' 1785 | securitySchemes: 1786 | ApiKeyAuth: 1787 | type: apiKey 1788 | in: header 1789 | name: X-N8N-API-KEY 1790 | ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 2 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 3 | import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js"; 4 | import { z } from "zod"; 5 | import fetch from 'node-fetch'; 6 | 7 | // Type definitions for n8n API responses 8 | interface N8nUser { 9 | id: string; 10 | email: string; 11 | firstName?: string; 12 | lastName?: string; 13 | isPending: boolean; 14 | role?: string; 15 | createdAt: string; 16 | updatedAt: string; 17 | } 18 | 19 | interface N8nUserList { 20 | data: N8nUser[]; 21 | nextCursor?: string; 22 | } 23 | 24 | interface N8nWorkflow { 25 | id: number; 26 | name: string; 27 | active: boolean; 28 | createdAt: string; 29 | updatedAt: string; 30 | tags: string[]; 31 | } 32 | 33 | interface N8nWorkflowList { 34 | data: N8nWorkflow[]; 35 | nextCursor?: string; 36 | } 37 | 38 | interface N8nProject { 39 | id: string; 40 | name: string; 41 | type?: string; 42 | } 43 | 44 | interface N8nProjectList { 45 | data: N8nProject[]; 46 | nextCursor?: string; 47 | } 48 | 49 | interface N8nVariable { 50 | id: string; 51 | key: string; 52 | value: string; 53 | type?: string; 54 | } 55 | 56 | interface N8nVariableList { 57 | data: N8nVariable[]; 58 | nextCursor?: string; 59 | } 60 | 61 | interface N8nExecution { 62 | id: number; 63 | data?: any; 64 | finished: boolean; 65 | mode: string; 66 | retryOf?: number; 67 | retrySuccessId?: number; 68 | startedAt: string; 69 | stoppedAt?: string; 70 | workflowId: number; 71 | waitTill?: string; 72 | } 73 | 74 | interface N8nExecutionList { 75 | data: N8nExecution[]; 76 | nextCursor?: string; 77 | } 78 | 79 | interface N8nTag { 80 | id: string; 81 | name: string; 82 | createdAt?: string; 83 | updatedAt?: string; 84 | } 85 | 86 | interface N8nTagList { 87 | data: N8nTag[]; 88 | nextCursor?: string; 89 | } 90 | 91 | interface N8nAuditResult { 92 | 'Credentials Risk Report'?: any; 93 | 'Database Risk Report'?: any; 94 | 'Filesystem Risk Report'?: any; 95 | 'Nodes Risk Report'?: any; 96 | 'Instance Risk Report'?: any; 97 | } 98 | 99 | class N8nClient { 100 | constructor( 101 | private baseUrl: string, 102 | private apiKey: string 103 | ) { 104 | // Remove trailing slash if present 105 | this.baseUrl = baseUrl.replace(/\/$/, ''); 106 | } 107 | 108 | private async makeRequest<T>(endpoint: string, options: any = {}): Promise<T> { 109 | const url = `${this.baseUrl}/api/v1${endpoint}`; 110 | const headers = { 111 | 'X-N8N-API-KEY': this.apiKey, 112 | 'Accept': 'application/json', 113 | 'Content-Type': 'application/json', 114 | }; 115 | 116 | try { 117 | const response = await fetch(url, { 118 | ...options, 119 | headers: { 120 | ...headers, 121 | ...options.headers, 122 | }, 123 | }); 124 | 125 | if (!response.ok) { 126 | const errorText = await response.text(); 127 | let errorMessage: string; 128 | try { 129 | const errorJson = JSON.parse(errorText); 130 | // Check for license-related errors 131 | if (errorJson.message && errorJson.message.includes('license')) { 132 | errorMessage = `This operation requires an n8n Enterprise license with project management features enabled. Error: ${errorJson.message}`; 133 | } else { 134 | errorMessage = errorJson.message || errorText; 135 | } 136 | } catch { 137 | errorMessage = errorText; 138 | } 139 | throw new Error(`N8N API error: ${errorMessage}`); 140 | } 141 | 142 | // Handle 204 No Content responses 143 | if (response.status === 204) { 144 | return {} as T; 145 | } 146 | 147 | return await response.json() as T; 148 | } catch (error) { 149 | if (error instanceof Error) { 150 | throw new Error(`Failed to connect to n8n: ${error.message}`); 151 | } 152 | throw error; 153 | } 154 | } 155 | 156 | async listWorkflows(): Promise<N8nWorkflowList> { 157 | return this.makeRequest<N8nWorkflowList>('/workflows'); 158 | } 159 | 160 | async getWorkflow(id: string): Promise<N8nWorkflow> { 161 | return this.makeRequest<N8nWorkflow>(`/workflows/${id}`); 162 | } 163 | 164 | async createWorkflow(name: string, nodes: any[] = [], connections: any = {}): Promise<N8nWorkflow> { 165 | return this.makeRequest<N8nWorkflow>('/workflows', { 166 | method: 'POST', 167 | body: JSON.stringify({ 168 | name, 169 | nodes, 170 | connections, 171 | settings: { 172 | saveManualExecutions: true, 173 | saveExecutionProgress: true, 174 | }, 175 | }), 176 | }); 177 | } 178 | 179 | async updateWorkflow(id: string, workflow: Partial<N8nWorkflow>): Promise<N8nWorkflow> { 180 | return this.makeRequest<N8nWorkflow>(`/workflows/${id}`, { 181 | method: 'PUT', 182 | body: JSON.stringify(workflow), 183 | }); 184 | } 185 | 186 | async deleteWorkflow(id: string): Promise<N8nWorkflow> { 187 | return this.makeRequest<N8nWorkflow>(`/workflows/${id}`, { 188 | method: 'DELETE', 189 | }); 190 | } 191 | 192 | async activateWorkflow(id: string): Promise<N8nWorkflow> { 193 | return this.makeRequest<N8nWorkflow>(`/workflows/${id}/activate`, { 194 | method: 'POST', 195 | }); 196 | } 197 | 198 | async deactivateWorkflow(id: string): Promise<N8nWorkflow> { 199 | return this.makeRequest<N8nWorkflow>(`/workflows/${id}/deactivate`, { 200 | method: 'POST', 201 | }); 202 | } 203 | 204 | // Project management methods (requires n8n Enterprise license) 205 | async listProjects(): Promise<N8nProjectList> { 206 | return this.makeRequest<N8nProjectList>('/projects'); 207 | } 208 | 209 | async createProject(name: string): Promise<void> { 210 | return this.makeRequest<void>('/projects', { 211 | method: 'POST', 212 | body: JSON.stringify({ name }), 213 | }); 214 | } 215 | 216 | async deleteProject(projectId: string): Promise<void> { 217 | return this.makeRequest<void>(`/projects/${projectId}`, { 218 | method: 'DELETE', 219 | }); 220 | } 221 | 222 | async updateProject(projectId: string, name: string): Promise<void> { 223 | return this.makeRequest<void>(`/projects/${projectId}`, { 224 | method: 'PUT', 225 | body: JSON.stringify({ name }), 226 | }); 227 | } 228 | 229 | // User management methods 230 | async listUsers(): Promise<N8nUserList> { 231 | return this.makeRequest<N8nUserList>('/users'); 232 | } 233 | 234 | async createUsers(users: Array<{ email: string; role?: 'global:admin' | 'global:member' }>): Promise<any> { 235 | return this.makeRequest('/users', { 236 | method: 'POST', 237 | body: JSON.stringify(users), 238 | }); 239 | } 240 | 241 | async getUser(idOrEmail: string): Promise<N8nUser> { 242 | return this.makeRequest<N8nUser>(`/users/${idOrEmail}`); 243 | } 244 | 245 | async deleteUser(idOrEmail: string): Promise<void> { 246 | return this.makeRequest<void>(`/users/${idOrEmail}`, { 247 | method: 'DELETE', 248 | }); 249 | } 250 | 251 | // Variable management methods 252 | async listVariables(): Promise<N8nVariableList> { 253 | return this.makeRequest<N8nVariableList>('/variables'); 254 | } 255 | 256 | async createVariable(key: string, value: string): Promise<void> { 257 | return this.makeRequest<void>('/variables', { 258 | method: 'POST', 259 | body: JSON.stringify({ key, value }), 260 | }); 261 | } 262 | 263 | async deleteVariable(id: string): Promise<void> { 264 | return this.makeRequest<void>(`/variables/${id}`, { 265 | method: 'DELETE', 266 | }); 267 | } 268 | 269 | // Execution management methods 270 | async getExecutions(options: { 271 | includeData?: boolean; 272 | status?: 'error' | 'success' | 'waiting'; 273 | workflowId?: string; 274 | limit?: number; 275 | } = {}): Promise<N8nExecutionList> { 276 | const params = new URLSearchParams(); 277 | if (options.includeData !== undefined) params.append('includeData', String(options.includeData)); 278 | if (options.status) params.append('status', options.status); 279 | if (options.workflowId) params.append('workflowId', options.workflowId); 280 | if (options.limit) params.append('limit', String(options.limit)); 281 | 282 | return this.makeRequest<N8nExecutionList>(`/executions?${params.toString()}`); 283 | } 284 | 285 | async getExecution(id: number, includeData: boolean = false): Promise<N8nExecution> { 286 | const params = new URLSearchParams(); 287 | if (includeData) params.append('includeData', 'true'); 288 | 289 | return this.makeRequest<N8nExecution>(`/executions/${id}?${params.toString()}`); 290 | } 291 | 292 | async deleteExecution(id: number): Promise<N8nExecution> { 293 | return this.makeRequest<N8nExecution>(`/executions/${id}`, { 294 | method: 'DELETE', 295 | }); 296 | } 297 | 298 | // Tag management methods 299 | async createTag(name: string): Promise<N8nTag> { 300 | return this.makeRequest<N8nTag>('/tags', { 301 | method: 'POST', 302 | body: JSON.stringify({ name }), 303 | }); 304 | } 305 | 306 | async getTags(options: { limit?: number } = {}): Promise<N8nTagList> { 307 | const params = new URLSearchParams(); 308 | if (options.limit) params.append('limit', String(options.limit)); 309 | 310 | return this.makeRequest<N8nTagList>(`/tags?${params.toString()}`); 311 | } 312 | 313 | async getTag(id: string): Promise<N8nTag> { 314 | return this.makeRequest<N8nTag>(`/tags/${id}`); 315 | } 316 | 317 | async updateTag(id: string, name: string): Promise<N8nTag> { 318 | return this.makeRequest<N8nTag>(`/tags/${id}`, { 319 | method: 'PUT', 320 | body: JSON.stringify({ name }), 321 | }); 322 | } 323 | 324 | async deleteTag(id: string): Promise<N8nTag> { 325 | return this.makeRequest<N8nTag>(`/tags/${id}`, { 326 | method: 'DELETE', 327 | }); 328 | } 329 | 330 | async getWorkflowTags(workflowId: string): Promise<N8nTag[]> { 331 | return this.makeRequest<N8nTag[]>(`/workflows/${workflowId}/tags`); 332 | } 333 | 334 | async updateWorkflowTags(workflowId: string, tagIds: { id: string }[]): Promise<N8nTag[]> { 335 | return this.makeRequest<N8nTag[]>(`/workflows/${workflowId}/tags`, { 336 | method: 'PUT', 337 | body: JSON.stringify(tagIds), 338 | }); 339 | } 340 | 341 | // Security audit method 342 | async generateAudit(options: { 343 | daysAbandonedWorkflow?: number; 344 | categories?: Array<'credentials' | 'database' | 'nodes' | 'filesystem' | 'instance'>; 345 | } = {}): Promise<N8nAuditResult> { 346 | return this.makeRequest<N8nAuditResult>('/audit', { 347 | method: 'POST', 348 | body: JSON.stringify({ 349 | additionalOptions: { 350 | daysAbandonedWorkflow: options.daysAbandonedWorkflow, 351 | categories: options.categories, 352 | }, 353 | }), 354 | }); 355 | } 356 | 357 | // Credential management methods 358 | async createCredential(name: string, type: string, data: Record<string, any>): Promise<any> { 359 | return this.makeRequest('/credentials', { 360 | method: 'POST', 361 | body: JSON.stringify({ 362 | name, 363 | type, 364 | data 365 | }), 366 | }); 367 | } 368 | 369 | async deleteCredential(id: string): Promise<any> { 370 | return this.makeRequest(`/credentials/${id}`, { 371 | method: 'DELETE', 372 | }); 373 | } 374 | 375 | async getCredentialSchema(credentialTypeName: string): Promise<any> { 376 | return this.makeRequest(`/credentials/schema/${credentialTypeName}`); 377 | } 378 | } 379 | 380 | // Create an MCP server 381 | const server = new Server( 382 | { 383 | name: "n8n-integration", 384 | version: "1.0.0" 385 | }, 386 | { 387 | capabilities: { 388 | tools: {} 389 | } 390 | } 391 | ); 392 | 393 | // Store client instances 394 | const clients = new Map<string, N8nClient>(); 395 | 396 | // List tools handler 397 | server.setRequestHandler(ListToolsRequestSchema, async () => { 398 | return { 399 | tools: [ 400 | { 401 | name: "init-n8n", 402 | 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.", 403 | inputSchema: { 404 | type: "object", 405 | properties: { 406 | url: { type: "string" }, 407 | apiKey: { type: "string" } 408 | }, 409 | required: ["url", "apiKey"] 410 | } 411 | }, 412 | { 413 | name: "list-workflows", 414 | 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.", 415 | inputSchema: { 416 | type: "object", 417 | properties: { 418 | clientId: { type: "string" } 419 | }, 420 | required: ["clientId"] 421 | } 422 | }, 423 | { 424 | name: "get-workflow", 425 | 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.", 426 | inputSchema: { 427 | type: "object", 428 | properties: { 429 | clientId: { type: "string" }, 430 | id: { type: "string" } 431 | }, 432 | required: ["clientId", "id"] 433 | } 434 | }, 435 | { 436 | name: "create-workflow", 437 | 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.", 438 | inputSchema: { 439 | type: "object", 440 | properties: { 441 | clientId: { type: "string" }, 442 | name: { type: "string" }, 443 | nodes: { type: "array" }, 444 | connections: { type: "object" } 445 | }, 446 | required: ["clientId", "name"] 447 | } 448 | }, 449 | { 450 | name: "update-workflow", 451 | 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.", 452 | inputSchema: { 453 | type: "object", 454 | properties: { 455 | clientId: { type: "string" }, 456 | id: { type: "string" }, 457 | workflow: { 458 | type: "object", 459 | properties: { 460 | name: { type: "string" }, 461 | active: { type: "boolean" }, 462 | nodes: { type: "array" }, 463 | connections: { type: "object" }, 464 | settings: { type: "object" } 465 | } 466 | } 467 | }, 468 | required: ["clientId", "id", "workflow"] 469 | } 470 | }, 471 | { 472 | name: "delete-workflow", 473 | 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.", 474 | inputSchema: { 475 | type: "object", 476 | properties: { 477 | clientId: { type: "string" }, 478 | id: { type: "string" } 479 | }, 480 | required: ["clientId", "id"] 481 | } 482 | }, 483 | { 484 | name: "activate-workflow", 485 | 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.", 486 | inputSchema: { 487 | type: "object", 488 | properties: { 489 | clientId: { type: "string" }, 490 | id: { type: "string" } 491 | }, 492 | required: ["clientId", "id"] 493 | } 494 | }, 495 | { 496 | name: "deactivate-workflow", 497 | 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.", 498 | inputSchema: { 499 | type: "object", 500 | properties: { 501 | clientId: { type: "string" }, 502 | id: { type: "string" } 503 | }, 504 | required: ["clientId", "id"] 505 | } 506 | }, 507 | { 508 | name: "list-projects", 509 | 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.", 510 | inputSchema: { 511 | type: "object", 512 | properties: { 513 | clientId: { type: "string" } 514 | }, 515 | required: ["clientId"] 516 | } 517 | }, 518 | { 519 | name: "create-project", 520 | 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.", 521 | inputSchema: { 522 | type: "object", 523 | properties: { 524 | clientId: { type: "string" }, 525 | name: { type: "string" } 526 | }, 527 | required: ["clientId", "name"] 528 | } 529 | }, 530 | { 531 | name: "delete-project", 532 | 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.", 533 | inputSchema: { 534 | type: "object", 535 | properties: { 536 | clientId: { type: "string" }, 537 | projectId: { type: "string" } 538 | }, 539 | required: ["clientId", "projectId"] 540 | } 541 | }, 542 | { 543 | name: "update-project", 544 | 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.", 545 | inputSchema: { 546 | type: "object", 547 | properties: { 548 | clientId: { type: "string" }, 549 | projectId: { type: "string" }, 550 | name: { type: "string" } 551 | }, 552 | required: ["clientId", "projectId", "name"] 553 | } 554 | }, 555 | { 556 | name: "list-users", 557 | description: "Retrieve all users from your instance. Only available for the instance owner.", 558 | inputSchema: { 559 | type: "object", 560 | properties: { 561 | clientId: { type: "string" } 562 | }, 563 | required: ["clientId"] 564 | } 565 | }, 566 | { 567 | name: "create-users", 568 | description: "Create one or more users in your instance.", 569 | inputSchema: { 570 | type: "object", 571 | properties: { 572 | clientId: { type: "string" }, 573 | users: { 574 | type: "array", 575 | items: { 576 | type: "object", 577 | properties: { 578 | email: { type: "string" }, 579 | role: { 580 | type: "string", 581 | enum: ["global:admin", "global:member"] 582 | } 583 | }, 584 | required: ["email"] 585 | } 586 | } 587 | }, 588 | required: ["clientId", "users"] 589 | } 590 | }, 591 | { 592 | name: "get-user", 593 | description: "Get user by ID or email address.", 594 | inputSchema: { 595 | type: "object", 596 | properties: { 597 | clientId: { type: "string" }, 598 | idOrEmail: { type: "string" } 599 | }, 600 | required: ["clientId", "idOrEmail"] 601 | } 602 | }, 603 | { 604 | name: "delete-user", 605 | description: "Delete a user from your instance.", 606 | inputSchema: { 607 | type: "object", 608 | properties: { 609 | clientId: { type: "string" }, 610 | idOrEmail: { type: "string" } 611 | }, 612 | required: ["clientId", "idOrEmail"] 613 | } 614 | }, 615 | { 616 | name: "list-variables", 617 | 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.", 618 | inputSchema: { 619 | type: "object", 620 | properties: { 621 | clientId: { type: "string" } 622 | }, 623 | required: ["clientId"] 624 | } 625 | }, 626 | { 627 | name: "create-variable", 628 | 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.", 629 | inputSchema: { 630 | type: "object", 631 | properties: { 632 | clientId: { type: "string" }, 633 | key: { type: "string" }, 634 | value: { type: "string" } 635 | }, 636 | required: ["clientId", "key", "value"] 637 | } 638 | }, 639 | { 640 | name: "delete-variable", 641 | 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.", 642 | inputSchema: { 643 | type: "object", 644 | properties: { 645 | clientId: { type: "string" }, 646 | id: { type: "string" } 647 | }, 648 | required: ["clientId", "id"] 649 | } 650 | }, 651 | { 652 | name: "create-credential", 653 | 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.", 654 | inputSchema: { 655 | type: "object", 656 | properties: { 657 | clientId: { type: "string" }, 658 | name: { type: "string" }, 659 | type: { type: "string" }, 660 | data: { type: "object" } 661 | }, 662 | required: ["clientId", "name", "type", "data"] 663 | } 664 | }, 665 | { 666 | name: "delete-credential", 667 | description: "Delete a credential by ID. You must be the owner of the credentials.", 668 | inputSchema: { 669 | type: "object", 670 | properties: { 671 | clientId: { type: "string" }, 672 | id: { type: "string" } 673 | }, 674 | required: ["clientId", "id"] 675 | } 676 | }, 677 | { 678 | name: "get-credential-schema", 679 | 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.", 680 | inputSchema: { 681 | type: "object", 682 | properties: { 683 | clientId: { type: "string" }, 684 | credentialTypeName: { type: "string" } 685 | }, 686 | required: ["clientId", "credentialTypeName"] 687 | } 688 | }, 689 | // Execution Management Tools 690 | { 691 | name: "list-executions", 692 | description: "Retrieve all executions from your instance with optional filtering.", 693 | inputSchema: { 694 | type: "object", 695 | properties: { 696 | clientId: { type: "string" }, 697 | includeData: { type: "boolean" }, 698 | status: { 699 | type: "string", 700 | enum: ["error", "success", "waiting"] 701 | }, 702 | workflowId: { type: "string" }, 703 | limit: { type: "number" } 704 | }, 705 | required: ["clientId"] 706 | } 707 | }, 708 | { 709 | name: "get-execution", 710 | description: "Retrieve a specific execution by ID.", 711 | inputSchema: { 712 | type: "object", 713 | properties: { 714 | clientId: { type: "string" }, 715 | id: { type: "number" }, 716 | includeData: { type: "boolean" } 717 | }, 718 | required: ["clientId", "id"] 719 | } 720 | }, 721 | { 722 | name: "delete-execution", 723 | description: "Delete a specific execution by ID.", 724 | inputSchema: { 725 | type: "object", 726 | properties: { 727 | clientId: { type: "string" }, 728 | id: { type: "number" } 729 | }, 730 | required: ["clientId", "id"] 731 | } 732 | }, 733 | // Tag Management Tools 734 | { 735 | name: "create-tag", 736 | description: "Create a new tag in your instance.", 737 | inputSchema: { 738 | type: "object", 739 | properties: { 740 | clientId: { type: "string" }, 741 | name: { type: "string" } 742 | }, 743 | required: ["clientId", "name"] 744 | } 745 | }, 746 | { 747 | name: "list-tags", 748 | description: "Retrieve all tags from your instance.", 749 | inputSchema: { 750 | type: "object", 751 | properties: { 752 | clientId: { type: "string" }, 753 | limit: { type: "number" } 754 | }, 755 | required: ["clientId"] 756 | } 757 | }, 758 | { 759 | name: "get-tag", 760 | description: "Retrieve a specific tag by ID.", 761 | inputSchema: { 762 | type: "object", 763 | properties: { 764 | clientId: { type: "string" }, 765 | id: { type: "string" } 766 | }, 767 | required: ["clientId", "id"] 768 | } 769 | }, 770 | { 771 | name: "update-tag", 772 | description: "Update a tag's name.", 773 | inputSchema: { 774 | type: "object", 775 | properties: { 776 | clientId: { type: "string" }, 777 | id: { type: "string" }, 778 | name: { type: "string" } 779 | }, 780 | required: ["clientId", "id", "name"] 781 | } 782 | }, 783 | { 784 | name: "delete-tag", 785 | description: "Delete a tag by ID.", 786 | inputSchema: { 787 | type: "object", 788 | properties: { 789 | clientId: { type: "string" }, 790 | id: { type: "string" } 791 | }, 792 | required: ["clientId", "id"] 793 | } 794 | }, 795 | { 796 | name: "get-workflow-tags", 797 | description: "Get tags associated with a workflow.", 798 | inputSchema: { 799 | type: "object", 800 | properties: { 801 | clientId: { type: "string" }, 802 | workflowId: { type: "string" } 803 | }, 804 | required: ["clientId", "workflowId"] 805 | } 806 | }, 807 | { 808 | name: "update-workflow-tags", 809 | description: "Update tags associated with a workflow.", 810 | inputSchema: { 811 | type: "object", 812 | properties: { 813 | clientId: { type: "string" }, 814 | workflowId: { type: "string" }, 815 | tagIds: { 816 | type: "array", 817 | items: { 818 | type: "object", 819 | properties: { 820 | id: { type: "string" } 821 | }, 822 | required: ["id"] 823 | } 824 | } 825 | }, 826 | required: ["clientId", "workflowId", "tagIds"] 827 | } 828 | }, 829 | // Security Audit Tool 830 | { 831 | name: "generate-audit", 832 | description: "Generate a security audit for your n8n instance.", 833 | inputSchema: { 834 | type: "object", 835 | properties: { 836 | clientId: { type: "string" }, 837 | daysAbandonedWorkflow: { type: "number" }, 838 | categories: { 839 | type: "array", 840 | items: { 841 | type: "string", 842 | enum: ["credentials", "database", "nodes", "filesystem", "instance"] 843 | } 844 | } 845 | }, 846 | required: ["clientId"] 847 | } 848 | } 849 | ] 850 | }; 851 | }); 852 | 853 | // Tool execution handler 854 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 855 | const { name, arguments: args } = request.params; 856 | 857 | switch (name) { 858 | case "init-n8n": { 859 | const { url, apiKey } = args as { url: string; apiKey: string }; 860 | try { 861 | const client = new N8nClient(url, apiKey); 862 | 863 | // Test connection by listing workflows 864 | await client.listWorkflows(); 865 | 866 | // Generate a unique client ID 867 | const clientId = Buffer.from(url).toString('base64'); 868 | clients.set(clientId, client); 869 | 870 | return { 871 | content: [{ 872 | type: "text", 873 | text: `Successfully connected to n8n at ${url}. Use this client ID for future operations: ${clientId}`, 874 | }] 875 | }; 876 | } catch (error) { 877 | return { 878 | content: [{ 879 | type: "text", 880 | text: error instanceof Error ? error.message : "Unknown error occurred", 881 | }], 882 | isError: true 883 | }; 884 | } 885 | } 886 | 887 | case "list-workflows": { 888 | const { clientId } = args as { clientId: string }; 889 | const client = clients.get(clientId); 890 | if (!client) { 891 | return { 892 | content: [{ 893 | type: "text", 894 | text: "Client not initialized. Please run init-n8n first.", 895 | }], 896 | isError: true 897 | }; 898 | } 899 | 900 | try { 901 | const workflows = await client.listWorkflows(); 902 | const formattedWorkflows = workflows.data.map(wf => ({ 903 | id: wf.id, 904 | name: wf.name, 905 | active: wf.active, 906 | created: wf.createdAt, 907 | updated: wf.updatedAt, 908 | tags: wf.tags, 909 | })); 910 | 911 | return { 912 | content: [{ 913 | type: "text", 914 | text: JSON.stringify(formattedWorkflows, null, 2), 915 | }] 916 | }; 917 | } catch (error) { 918 | return { 919 | content: [{ 920 | type: "text", 921 | text: error instanceof Error ? error.message : "Unknown error occurred", 922 | }], 923 | isError: true 924 | }; 925 | } 926 | } 927 | 928 | case "get-workflow": { 929 | const { clientId, id } = args as { clientId: string; id: string }; 930 | const client = clients.get(clientId); 931 | if (!client) { 932 | return { 933 | content: [{ 934 | type: "text", 935 | text: "Client not initialized. Please run init-n8n first.", 936 | }], 937 | isError: true 938 | }; 939 | } 940 | 941 | try { 942 | const workflow = await client.getWorkflow(id); 943 | return { 944 | content: [{ 945 | type: "text", 946 | text: JSON.stringify(workflow, null, 2), 947 | }] 948 | }; 949 | } catch (error) { 950 | return { 951 | content: [{ 952 | type: "text", 953 | text: error instanceof Error ? error.message : "Unknown error occurred", 954 | }], 955 | isError: true 956 | }; 957 | } 958 | } 959 | 960 | case "update-workflow": { 961 | const { clientId, id, workflow } = args as { 962 | clientId: string; 963 | id: string; 964 | workflow: Partial<N8nWorkflow>; 965 | }; 966 | 967 | const client = clients.get(clientId); 968 | if (!client) { 969 | return { 970 | content: [{ 971 | type: "text", 972 | text: "Client not initialized. Please run init-n8n first.", 973 | }], 974 | isError: true 975 | }; 976 | } 977 | 978 | try { 979 | const updatedWorkflow = await client.updateWorkflow(id, workflow); 980 | return { 981 | content: [{ 982 | type: "text", 983 | text: `Successfully updated workflow:\n${JSON.stringify(updatedWorkflow, null, 2)}`, 984 | }] 985 | }; 986 | } catch (error) { 987 | return { 988 | content: [{ 989 | type: "text", 990 | text: error instanceof Error ? error.message : "Unknown error occurred", 991 | }], 992 | isError: true 993 | }; 994 | } 995 | } 996 | 997 | case "create-workflow": { 998 | const { clientId, name, nodes = [], connections = {} } = args as { 999 | clientId: string; 1000 | name: string; 1001 | nodes?: any[]; 1002 | connections?: Record<string, any>; 1003 | }; 1004 | 1005 | const client = clients.get(clientId); 1006 | if (!client) { 1007 | return { 1008 | content: [{ 1009 | type: "text", 1010 | text: "Client not initialized. Please run init-n8n first.", 1011 | }], 1012 | isError: true 1013 | }; 1014 | } 1015 | 1016 | try { 1017 | const workflow = await client.createWorkflow(name, nodes, connections); 1018 | return { 1019 | content: [{ 1020 | type: "text", 1021 | text: `Successfully created workflow:\n${JSON.stringify(workflow, null, 2)}`, 1022 | }] 1023 | }; 1024 | } catch (error) { 1025 | return { 1026 | content: [{ 1027 | type: "text", 1028 | text: error instanceof Error ? error.message : "Unknown error occurred", 1029 | }], 1030 | isError: true 1031 | }; 1032 | } 1033 | } 1034 | 1035 | case "delete-workflow": { 1036 | const { clientId, id } = args as { clientId: string; id: string }; 1037 | const client = clients.get(clientId); 1038 | if (!client) { 1039 | return { 1040 | content: [{ 1041 | type: "text", 1042 | text: "Client not initialized. Please run init-n8n first.", 1043 | }], 1044 | isError: true 1045 | }; 1046 | } 1047 | 1048 | try { 1049 | const workflow = await client.deleteWorkflow(id); 1050 | return { 1051 | content: [{ 1052 | type: "text", 1053 | text: `Successfully deleted workflow:\n${JSON.stringify(workflow, null, 2)}`, 1054 | }] 1055 | }; 1056 | } catch (error) { 1057 | return { 1058 | content: [{ 1059 | type: "text", 1060 | text: error instanceof Error ? error.message : "Unknown error occurred", 1061 | }], 1062 | isError: true 1063 | }; 1064 | } 1065 | } 1066 | 1067 | case "activate-workflow": { 1068 | const { clientId, id } = args as { clientId: string; id: string }; 1069 | const client = clients.get(clientId); 1070 | if (!client) { 1071 | return { 1072 | content: [{ 1073 | type: "text", 1074 | text: "Client not initialized. Please run init-n8n first.", 1075 | }], 1076 | isError: true 1077 | }; 1078 | } 1079 | 1080 | try { 1081 | const workflow = await client.activateWorkflow(id); 1082 | return { 1083 | content: [{ 1084 | type: "text", 1085 | text: `Successfully activated workflow:\n${JSON.stringify(workflow, null, 2)}`, 1086 | }] 1087 | }; 1088 | } catch (error) { 1089 | return { 1090 | content: [{ 1091 | type: "text", 1092 | text: error instanceof Error ? error.message : "Unknown error occurred", 1093 | }], 1094 | isError: true 1095 | }; 1096 | } 1097 | } 1098 | 1099 | case "deactivate-workflow": { 1100 | const { clientId, id } = args as { clientId: string; id: string }; 1101 | const client = clients.get(clientId); 1102 | if (!client) { 1103 | return { 1104 | content: [{ 1105 | type: "text", 1106 | text: "Client not initialized. Please run init-n8n first.", 1107 | }], 1108 | isError: true 1109 | }; 1110 | } 1111 | 1112 | try { 1113 | const workflow = await client.deactivateWorkflow(id); 1114 | return { 1115 | content: [{ 1116 | type: "text", 1117 | text: `Successfully deactivated workflow:\n${JSON.stringify(workflow, null, 2)}`, 1118 | }] 1119 | }; 1120 | } catch (error) { 1121 | return { 1122 | content: [{ 1123 | type: "text", 1124 | text: error instanceof Error ? error.message : "Unknown error occurred", 1125 | }], 1126 | isError: true 1127 | }; 1128 | } 1129 | } 1130 | 1131 | case "list-projects": { 1132 | const { clientId } = args as { clientId: string }; 1133 | const client = clients.get(clientId); 1134 | if (!client) { 1135 | return { 1136 | content: [{ 1137 | type: "text", 1138 | text: "Client not initialized. Please run init-n8n first.", 1139 | }], 1140 | isError: true 1141 | }; 1142 | } 1143 | 1144 | try { 1145 | const projects = await client.listProjects(); 1146 | return { 1147 | content: [{ 1148 | type: "text", 1149 | text: JSON.stringify(projects.data, null, 2), 1150 | }] 1151 | }; 1152 | } catch (error) { 1153 | return { 1154 | content: [{ 1155 | type: "text", 1156 | text: error instanceof Error ? error.message : "Unknown error occurred", 1157 | }], 1158 | isError: true 1159 | }; 1160 | } 1161 | } 1162 | 1163 | case "create-project": { 1164 | const { clientId, name } = args as { clientId: string; name: string }; 1165 | const client = clients.get(clientId); 1166 | if (!client) { 1167 | return { 1168 | content: [{ 1169 | type: "text", 1170 | text: "Client not initialized. Please run init-n8n first.", 1171 | }], 1172 | isError: true 1173 | }; 1174 | } 1175 | 1176 | try { 1177 | await client.createProject(name); 1178 | return { 1179 | content: [{ 1180 | type: "text", 1181 | text: `Successfully created project: ${name}`, 1182 | }] 1183 | }; 1184 | } catch (error) { 1185 | return { 1186 | content: [{ 1187 | type: "text", 1188 | text: error instanceof Error ? error.message : "Unknown error occurred", 1189 | }], 1190 | isError: true 1191 | }; 1192 | } 1193 | } 1194 | 1195 | case "delete-project": { 1196 | const { clientId, projectId } = args as { clientId: string; projectId: string }; 1197 | const client = clients.get(clientId); 1198 | if (!client) { 1199 | return { 1200 | content: [{ 1201 | type: "text", 1202 | text: "Client not initialized. Please run init-n8n first.", 1203 | }], 1204 | isError: true 1205 | }; 1206 | } 1207 | 1208 | try { 1209 | await client.deleteProject(projectId); 1210 | return { 1211 | content: [{ 1212 | type: "text", 1213 | text: `Successfully deleted project with ID: ${projectId}`, 1214 | }] 1215 | }; 1216 | } catch (error) { 1217 | return { 1218 | content: [{ 1219 | type: "text", 1220 | text: error instanceof Error ? error.message : "Unknown error occurred", 1221 | }], 1222 | isError: true 1223 | }; 1224 | } 1225 | } 1226 | 1227 | case "update-project": { 1228 | const { clientId, projectId, name } = args as { clientId: string; projectId: string; name: string }; 1229 | const client = clients.get(clientId); 1230 | if (!client) { 1231 | return { 1232 | content: [{ 1233 | type: "text", 1234 | text: "Client not initialized. Please run init-n8n first.", 1235 | }], 1236 | isError: true 1237 | }; 1238 | } 1239 | 1240 | try { 1241 | await client.updateProject(projectId, name); 1242 | return { 1243 | content: [{ 1244 | type: "text", 1245 | text: `Successfully updated project ${projectId} with new name: ${name}`, 1246 | }] 1247 | }; 1248 | } catch (error) { 1249 | return { 1250 | content: [{ 1251 | type: "text", 1252 | text: error instanceof Error ? error.message : "Unknown error occurred", 1253 | }], 1254 | isError: true 1255 | }; 1256 | } 1257 | } 1258 | 1259 | case "list-users": { 1260 | const { clientId } = args as { clientId: string }; 1261 | const client = clients.get(clientId); 1262 | if (!client) { 1263 | return { 1264 | content: [{ 1265 | type: "text", 1266 | text: "Client not initialized. Please run init-n8n first.", 1267 | }], 1268 | isError: true 1269 | }; 1270 | } 1271 | 1272 | try { 1273 | const users = await client.listUsers(); 1274 | return { 1275 | content: [{ 1276 | type: "text", 1277 | text: JSON.stringify(users.data, null, 2), 1278 | }] 1279 | }; 1280 | } catch (error) { 1281 | return { 1282 | content: [{ 1283 | type: "text", 1284 | text: error instanceof Error ? error.message : "Unknown error occurred", 1285 | }], 1286 | isError: true 1287 | }; 1288 | } 1289 | } 1290 | 1291 | case "create-users": { 1292 | const { clientId, users } = args as { 1293 | clientId: string; 1294 | users: Array<{ 1295 | email: string; 1296 | role?: 'global:admin' | 'global:member' 1297 | }> 1298 | }; 1299 | const client = clients.get(clientId); 1300 | if (!client) { 1301 | return { 1302 | content: [{ 1303 | type: "text", 1304 | text: "Client not initialized. Please run init-n8n first.", 1305 | }], 1306 | isError: true 1307 | }; 1308 | } 1309 | 1310 | try { 1311 | const result = await client.createUsers(users); 1312 | return { 1313 | content: [{ 1314 | type: "text", 1315 | text: JSON.stringify(result, null, 2), 1316 | }] 1317 | }; 1318 | } catch (error) { 1319 | return { 1320 | content: [{ 1321 | type: "text", 1322 | text: error instanceof Error ? error.message : "Unknown error occurred", 1323 | }], 1324 | isError: true 1325 | }; 1326 | } 1327 | } 1328 | 1329 | case "get-user": { 1330 | const { clientId, idOrEmail } = args as { clientId: string; idOrEmail: string }; 1331 | const client = clients.get(clientId); 1332 | if (!client) { 1333 | return { 1334 | content: [{ 1335 | type: "text", 1336 | text: "Client not initialized. Please run init-n8n first.", 1337 | }], 1338 | isError: true 1339 | }; 1340 | } 1341 | 1342 | try { 1343 | const user = await client.getUser(idOrEmail); 1344 | return { 1345 | content: [{ 1346 | type: "text", 1347 | text: JSON.stringify(user, null, 2), 1348 | }] 1349 | }; 1350 | } catch (error) { 1351 | return { 1352 | content: [{ 1353 | type: "text", 1354 | text: error instanceof Error ? error.message : "Unknown error occurred", 1355 | }], 1356 | isError: true 1357 | }; 1358 | } 1359 | } 1360 | 1361 | case "delete-user": { 1362 | const { clientId, idOrEmail } = args as { clientId: string; idOrEmail: string }; 1363 | const client = clients.get(clientId); 1364 | if (!client) { 1365 | return { 1366 | content: [{ 1367 | type: "text", 1368 | text: "Client not initialized. Please run init-n8n first.", 1369 | }], 1370 | isError: true 1371 | }; 1372 | } 1373 | 1374 | try { 1375 | await client.deleteUser(idOrEmail); 1376 | return { 1377 | content: [{ 1378 | type: "text", 1379 | text: `Successfully deleted user: ${idOrEmail}`, 1380 | }] 1381 | }; 1382 | } catch (error) { 1383 | return { 1384 | content: [{ 1385 | type: "text", 1386 | text: error instanceof Error ? error.message : "Unknown error occurred", 1387 | }], 1388 | isError: true 1389 | }; 1390 | } 1391 | } 1392 | 1393 | case "list-variables": { 1394 | const { clientId } = args as { clientId: string }; 1395 | const client = clients.get(clientId); 1396 | if (!client) { 1397 | return { 1398 | content: [{ 1399 | type: "text", 1400 | text: "Client not initialized. Please run init-n8n first.", 1401 | }], 1402 | isError: true 1403 | }; 1404 | } 1405 | 1406 | try { 1407 | const variables = await client.listVariables(); 1408 | return { 1409 | content: [{ 1410 | type: "text", 1411 | text: JSON.stringify(variables.data, null, 2), 1412 | }] 1413 | }; 1414 | } catch (error) { 1415 | return { 1416 | content: [{ 1417 | type: "text", 1418 | text: error instanceof Error ? error.message : "Unknown error occurred", 1419 | }], 1420 | isError: true 1421 | }; 1422 | } 1423 | } 1424 | 1425 | case "create-variable": { 1426 | const { clientId, key, value } = args as { clientId: string; key: string; value: string }; 1427 | const client = clients.get(clientId); 1428 | if (!client) { 1429 | return { 1430 | content: [{ 1431 | type: "text", 1432 | text: "Client not initialized. Please run init-n8n first.", 1433 | }], 1434 | isError: true 1435 | }; 1436 | } 1437 | 1438 | try { 1439 | await client.createVariable(key, value); 1440 | return { 1441 | content: [{ 1442 | type: "text", 1443 | text: `Successfully created variable with key: ${key}`, 1444 | }] 1445 | }; 1446 | } catch (error) { 1447 | return { 1448 | content: [{ 1449 | type: "text", 1450 | text: error instanceof Error ? error.message : "Unknown error occurred", 1451 | }], 1452 | isError: true 1453 | }; 1454 | } 1455 | } 1456 | 1457 | case "delete-variable": { 1458 | const { clientId, id } = args as { clientId: string; id: string }; 1459 | const client = clients.get(clientId); 1460 | if (!client) { 1461 | return { 1462 | content: [{ 1463 | type: "text", 1464 | text: "Client not initialized. Please run init-n8n first.", 1465 | }], 1466 | isError: true 1467 | }; 1468 | } 1469 | 1470 | try { 1471 | await client.deleteVariable(id); 1472 | return { 1473 | content: [{ 1474 | type: "text", 1475 | text: `Successfully deleted variable with ID: ${id}`, 1476 | }] 1477 | }; 1478 | } catch (error) { 1479 | return { 1480 | content: [{ 1481 | type: "text", 1482 | text: error instanceof Error ? error.message : "Unknown error occurred", 1483 | }], 1484 | isError: true 1485 | }; 1486 | } 1487 | } 1488 | 1489 | case "create-credential": { 1490 | const { clientId, name, type, data } = args as { 1491 | clientId: string; 1492 | name: string; 1493 | type: string; 1494 | data: Record<string, any>; 1495 | }; 1496 | const client = clients.get(clientId); 1497 | if (!client) { 1498 | return { 1499 | content: [{ 1500 | type: "text", 1501 | text: "Client not initialized. Please run init-n8n first.", 1502 | }], 1503 | isError: true 1504 | }; 1505 | } 1506 | 1507 | try { 1508 | const credential = await client.createCredential(name, type, data); 1509 | return { 1510 | content: [{ 1511 | type: "text", 1512 | text: `Successfully created credential:\n${JSON.stringify(credential, null, 2)}`, 1513 | }] 1514 | }; 1515 | } catch (error) { 1516 | return { 1517 | content: [{ 1518 | type: "text", 1519 | text: error instanceof Error ? error.message : "Unknown error occurred", 1520 | }], 1521 | isError: true 1522 | }; 1523 | } 1524 | } 1525 | 1526 | case "delete-credential": { 1527 | const { clientId, id } = args as { clientId: string; id: string }; 1528 | const client = clients.get(clientId); 1529 | if (!client) { 1530 | return { 1531 | content: [{ 1532 | type: "text", 1533 | text: "Client not initialized. Please run init-n8n first.", 1534 | }], 1535 | isError: true 1536 | }; 1537 | } 1538 | 1539 | try { 1540 | const result = await client.deleteCredential(id); 1541 | return { 1542 | content: [{ 1543 | type: "text", 1544 | text: `Successfully deleted credential:\n${JSON.stringify(result, null, 2)}`, 1545 | }] 1546 | }; 1547 | } catch (error) { 1548 | return { 1549 | content: [{ 1550 | type: "text", 1551 | text: error instanceof Error ? error.message : "Unknown error occurred", 1552 | }], 1553 | isError: true 1554 | }; 1555 | } 1556 | } 1557 | 1558 | case "get-credential-schema": { 1559 | const { clientId, credentialTypeName } = args as { clientId: string; credentialTypeName: string }; 1560 | const client = clients.get(clientId); 1561 | if (!client) { 1562 | return { 1563 | content: [{ 1564 | type: "text", 1565 | text: "Client not initialized. Please run init-n8n first.", 1566 | }], 1567 | isError: true 1568 | }; 1569 | } 1570 | 1571 | try { 1572 | const schema = await client.getCredentialSchema(credentialTypeName); 1573 | return { 1574 | content: [{ 1575 | type: "text", 1576 | text: JSON.stringify(schema, null, 2), 1577 | }] 1578 | }; 1579 | } catch (error) { 1580 | return { 1581 | content: [{ 1582 | type: "text", 1583 | text: error instanceof Error ? error.message : "Unknown error occurred", 1584 | }], 1585 | isError: true 1586 | }; 1587 | } 1588 | } 1589 | 1590 | // Execution Management Handlers 1591 | case "list-executions": { 1592 | const { clientId, includeData, status, workflowId, limit } = args as { 1593 | clientId: string; 1594 | includeData?: boolean; 1595 | status?: 'error' | 'success' | 'waiting'; 1596 | workflowId?: string; 1597 | limit?: number; 1598 | }; 1599 | const client = clients.get(clientId); 1600 | if (!client) { 1601 | return { 1602 | content: [{ 1603 | type: "text", 1604 | text: "Client not initialized. Please run init-n8n first.", 1605 | }], 1606 | isError: true 1607 | }; 1608 | } 1609 | 1610 | try { 1611 | const executions = await client.getExecutions({ includeData, status, workflowId, limit }); 1612 | return { 1613 | content: [{ 1614 | type: "text", 1615 | text: JSON.stringify(executions.data, null, 2), 1616 | }] 1617 | }; 1618 | } catch (error) { 1619 | return { 1620 | content: [{ 1621 | type: "text", 1622 | text: error instanceof Error ? error.message : "Unknown error occurred", 1623 | }], 1624 | isError: true 1625 | }; 1626 | } 1627 | } 1628 | 1629 | case "get-execution": { 1630 | const { clientId, id, includeData } = args as { clientId: string; id: number; includeData?: boolean }; 1631 | const client = clients.get(clientId); 1632 | if (!client) { 1633 | return { 1634 | content: [{ 1635 | type: "text", 1636 | text: "Client not initialized. Please run init-n8n first.", 1637 | }], 1638 | isError: true 1639 | }; 1640 | } 1641 | 1642 | try { 1643 | const execution = await client.getExecution(id, includeData); 1644 | return { 1645 | content: [{ 1646 | type: "text", 1647 | text: JSON.stringify(execution, null, 2), 1648 | }] 1649 | }; 1650 | } catch (error) { 1651 | return { 1652 | content: [{ 1653 | type: "text", 1654 | text: error instanceof Error ? error.message : "Unknown error occurred", 1655 | }], 1656 | isError: true 1657 | }; 1658 | } 1659 | } 1660 | 1661 | case "delete-execution": { 1662 | const { clientId, id } = args as { clientId: string; id: number }; 1663 | const client = clients.get(clientId); 1664 | if (!client) { 1665 | return { 1666 | content: [{ 1667 | type: "text", 1668 | text: "Client not initialized. Please run init-n8n first.", 1669 | }], 1670 | isError: true 1671 | }; 1672 | } 1673 | 1674 | try { 1675 | const execution = await client.deleteExecution(id); 1676 | return { 1677 | content: [{ 1678 | type: "text", 1679 | text: `Successfully deleted execution:\n${JSON.stringify(execution, null, 2)}`, 1680 | }] 1681 | }; 1682 | } catch (error) { 1683 | return { 1684 | content: [{ 1685 | type: "text", 1686 | text: error instanceof Error ? error.message : "Unknown error occurred", 1687 | }], 1688 | isError: true 1689 | }; 1690 | } 1691 | } 1692 | 1693 | // Tag Management Handlers 1694 | case "create-tag": { 1695 | const { clientId, name } = args as { clientId: string; name: string }; 1696 | const client = clients.get(clientId); 1697 | if (!client) { 1698 | return { 1699 | content: [{ 1700 | type: "text", 1701 | text: "Client not initialized. Please run init-n8n first.", 1702 | }], 1703 | isError: true 1704 | }; 1705 | } 1706 | 1707 | try { 1708 | const tag = await client.createTag(name); 1709 | return { 1710 | content: [{ 1711 | type: "text", 1712 | text: `Successfully created tag:\n${JSON.stringify(tag, null, 2)}`, 1713 | }] 1714 | }; 1715 | } catch (error) { 1716 | return { 1717 | content: [{ 1718 | type: "text", 1719 | text: error instanceof Error ? error.message : "Unknown error occurred", 1720 | }], 1721 | isError: true 1722 | }; 1723 | } 1724 | } 1725 | 1726 | case "list-tags": { 1727 | const { clientId, limit } = args as { clientId: string; limit?: number }; 1728 | const client = clients.get(clientId); 1729 | if (!client) { 1730 | return { 1731 | content: [{ 1732 | type: "text", 1733 | text: "Client not initialized. Please run init-n8n first.", 1734 | }], 1735 | isError: true 1736 | }; 1737 | } 1738 | 1739 | try { 1740 | const tags = await client.getTags({ limit }); 1741 | return { 1742 | content: [{ 1743 | type: "text", 1744 | text: JSON.stringify(tags.data, null, 2), 1745 | }] 1746 | }; 1747 | } catch (error) { 1748 | return { 1749 | content: [{ 1750 | type: "text", 1751 | text: error instanceof Error ? error.message : "Unknown error occurred", 1752 | }], 1753 | isError: true 1754 | }; 1755 | } 1756 | } 1757 | 1758 | case "get-tag": { 1759 | const { clientId, id } = args as { clientId: string; id: string }; 1760 | const client = clients.get(clientId); 1761 | if (!client) { 1762 | return { 1763 | content: [{ 1764 | type: "text", 1765 | text: "Client not initialized. Please run init-n8n first.", 1766 | }], 1767 | isError: true 1768 | }; 1769 | } 1770 | 1771 | try { 1772 | const tag = await client.getTag(id); 1773 | return { 1774 | content: [{ 1775 | type: "text", 1776 | text: JSON.stringify(tag, null, 2), 1777 | }] 1778 | }; 1779 | } catch (error) { 1780 | return { 1781 | content: [{ 1782 | type: "text", 1783 | text: error instanceof Error ? error.message : "Unknown error occurred", 1784 | }], 1785 | isError: true 1786 | }; 1787 | } 1788 | } 1789 | 1790 | case "update-tag": { 1791 | const { clientId, id, name } = args as { clientId: string; id: string; name: string }; 1792 | const client = clients.get(clientId); 1793 | if (!client) { 1794 | return { 1795 | content: [{ 1796 | type: "text", 1797 | text: "Client not initialized. Please run init-n8n first.", 1798 | }], 1799 | isError: true 1800 | }; 1801 | } 1802 | 1803 | try { 1804 | const tag = await client.updateTag(id, name); 1805 | return { 1806 | content: [{ 1807 | type: "text", 1808 | text: `Successfully updated tag:\n${JSON.stringify(tag, null, 2)}`, 1809 | }] 1810 | }; 1811 | } catch (error) { 1812 | return { 1813 | content: [{ 1814 | type: "text", 1815 | text: error instanceof Error ? error.message : "Unknown error occurred", 1816 | }], 1817 | isError: true 1818 | }; 1819 | } 1820 | } 1821 | 1822 | case "delete-tag": { 1823 | const { clientId, id } = args as { clientId: string; id: string }; 1824 | const client = clients.get(clientId); 1825 | if (!client) { 1826 | return { 1827 | content: [{ 1828 | type: "text", 1829 | text: "Client not initialized. Please run init-n8n first.", 1830 | }], 1831 | isError: true 1832 | }; 1833 | } 1834 | 1835 | try { 1836 | const tag = await client.deleteTag(id); 1837 | return { 1838 | content: [{ 1839 | type: "text", 1840 | text: `Successfully deleted tag:\n${JSON.stringify(tag, null, 2)}`, 1841 | }] 1842 | }; 1843 | } catch (error) { 1844 | return { 1845 | content: [{ 1846 | type: "text", 1847 | text: error instanceof Error ? error.message : "Unknown error occurred", 1848 | }], 1849 | isError: true 1850 | }; 1851 | } 1852 | } 1853 | 1854 | case "get-workflow-tags": { 1855 | const { clientId, workflowId } = args as { clientId: string; workflowId: string }; 1856 | const client = clients.get(clientId); 1857 | if (!client) { 1858 | return { 1859 | content: [{ 1860 | type: "text", 1861 | text: "Client not initialized. Please run init-n8n first.", 1862 | }], 1863 | isError: true 1864 | }; 1865 | } 1866 | 1867 | try { 1868 | const tags = await client.getWorkflowTags(workflowId); 1869 | return { 1870 | content: [{ 1871 | type: "text", 1872 | text: JSON.stringify(tags, null, 2), 1873 | }] 1874 | }; 1875 | } catch (error) { 1876 | return { 1877 | content: [{ 1878 | type: "text", 1879 | text: error instanceof Error ? error.message : "Unknown error occurred", 1880 | }], 1881 | isError: true 1882 | }; 1883 | } 1884 | } 1885 | 1886 | case "update-workflow-tags": { 1887 | const { clientId, workflowId, tagIds } = args as { 1888 | clientId: string; 1889 | workflowId: string; 1890 | tagIds: { id: string }[]; 1891 | }; 1892 | const client = clients.get(clientId); 1893 | if (!client) { 1894 | return { 1895 | content: [{ 1896 | type: "text", 1897 | text: "Client not initialized. Please run init-n8n first.", 1898 | }], 1899 | isError: true 1900 | }; 1901 | } 1902 | 1903 | try { 1904 | const tags = await client.updateWorkflowTags(workflowId, tagIds); 1905 | return { 1906 | content: [{ 1907 | type: "text", 1908 | text: `Successfully updated workflow tags:\n${JSON.stringify(tags, null, 2)}`, 1909 | }] 1910 | }; 1911 | } catch (error) { 1912 | return { 1913 | content: [{ 1914 | type: "text", 1915 | text: error instanceof Error ? error.message : "Unknown error occurred", 1916 | }], 1917 | isError: true 1918 | }; 1919 | } 1920 | } 1921 | 1922 | case "generate-audit": { 1923 | const { clientId, daysAbandonedWorkflow, categories } = args as { 1924 | clientId: string; 1925 | daysAbandonedWorkflow?: number; 1926 | categories?: Array<'credentials' | 'database' | 'nodes' | 'filesystem' | 'instance'>; 1927 | }; 1928 | const client = clients.get(clientId); 1929 | if (!client) { 1930 | return { 1931 | content: [{ 1932 | type: "text", 1933 | text: "Client not initialized. Please run init-n8n first.", 1934 | }], 1935 | isError: true 1936 | }; 1937 | } 1938 | 1939 | try { 1940 | const audit = await client.generateAudit({ daysAbandonedWorkflow, categories }); 1941 | return { 1942 | content: [{ 1943 | type: "text", 1944 | text: JSON.stringify(audit, null, 2), 1945 | }] 1946 | }; 1947 | } catch (error) { 1948 | return { 1949 | content: [{ 1950 | type: "text", 1951 | text: error instanceof Error ? error.message : "Unknown error occurred", 1952 | }], 1953 | isError: true 1954 | }; 1955 | } 1956 | } 1957 | 1958 | default: 1959 | return { 1960 | content: [{ 1961 | type: "text", 1962 | text: `Unknown tool: ${name}`, 1963 | }], 1964 | isError: true 1965 | }; 1966 | } 1967 | }); 1968 | 1969 | // Start the server 1970 | const transport = new StdioServerTransport(); 1971 | await server.connect(transport); 1972 | console.error("N8N MCP Server running on stdio"); 1973 | ```