Skip to main content
Glama
server.ts21.9 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import axios from "axios"; // Configuration const N8N_HOST = process.env.N8N_HOST || 'http://localhost:5678'; const N8N_API_KEY = process.env.N8N_API_KEY || ''; console.error("N8N API Configuration:"); console.error("Host:", N8N_HOST); console.error("API Key:", N8N_API_KEY ? `${N8N_API_KEY.substring(0, 4)}****` : 'Not set'); // Create axios instance for n8n API const n8nApi = axios.create({ baseURL: N8N_HOST, headers: { 'X-N8N-API-KEY': N8N_API_KEY, 'Content-Type': 'application/json' } }); // Create MCP server with modern SDK 1.17.0 API const server = new McpServer({ name: "n8n-workflow-builder", version: "0.10.3" }); // Register workflow management tools using modern MCP SDK 1.17.0 API server.tool( "list_workflows", "List all workflows from n8n instance", {}, async () => { try { const response = await n8nApi.get('/workflows'); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "create_workflow", "Create a new workflow in n8n", { workflow: z.object({ name: z.string().describe("Name of the workflow"), nodes: z.array(z.any()).describe("Array of workflow nodes"), connections: z.record(z.string(), z.any()).optional().describe("Node connections"), settings: z.record(z.string(), z.any()).optional().describe("Workflow settings"), tags: z.array(z.any()).optional().describe("Workflow tags") }).describe("Workflow configuration") }, async ({ workflow }) => { try { const response = await n8nApi.post('/workflows', workflow); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "get_workflow", "Get a workflow by ID", { id: z.string().describe("Workflow ID") }, async ({ id }) => { try { const response = await n8nApi.get(`/workflows/${id}`); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "update_workflow", "Update an existing workflow by ID", { id: z.string().describe("Workflow ID"), workflow: z.object({ name: z.string().optional().describe("Name of the workflow"), nodes: z.array(z.any()).optional().describe("Array of workflow nodes"), connections: z.record(z.string(), z.any()).optional().describe("Node connections"), settings: z.record(z.string(), z.any()).optional().describe("Workflow settings"), tags: z.array(z.any()).optional().describe("Workflow tags") }).describe("Updated workflow configuration") }, async ({ id, workflow }) => { try { const response = await n8nApi.put(`/workflows/${id}`, workflow); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "delete_workflow", "Delete a workflow by ID", { id: z.string().describe("Workflow ID") }, async ({ id }) => { try { const response = await n8nApi.delete(`/workflows/${id}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Workflow ${id} deleted successfully`, deletedWorkflow: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "activate_workflow", "Activate a workflow by ID", { id: z.string().describe("Workflow ID") }, async ({ id }) => { try { const response = await n8nApi.post(`/workflows/${id}/activate`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Workflow ${id} activated successfully`, workflow: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "deactivate_workflow", "Deactivate a workflow by ID", { id: z.string().describe("Workflow ID") }, async ({ id }) => { try { const response = await n8nApi.post(`/workflows/${id}/deactivate`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Workflow ${id} deactivated successfully`, workflow: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "execute_workflow", "Execute a workflow manually", { id: z.string().describe("Workflow ID") }, async ({ id }) => { try { const response = await n8nApi.post(`/workflows/${id}/execute`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Workflow ${id} executed successfully`, execution: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "create_workflow_and_activate", "Create a new workflow and immediately activate it", { workflow: z.object({ name: z.string().describe("Name of the workflow"), nodes: z.array(z.any()).describe("Array of workflow nodes"), connections: z.record(z.string(), z.any()).optional().describe("Node connections"), settings: z.record(z.string(), z.any()).optional().describe("Workflow settings"), tags: z.array(z.any()).optional().describe("Workflow tags") }).describe("Workflow configuration") }, async ({ workflow }) => { try { // First create the workflow const createResponse = await n8nApi.post('/workflows', workflow); const workflowId = createResponse.data.id; // Then activate it const activateResponse = await n8nApi.post(`/workflows/${workflowId}/activate`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Workflow created and activated successfully`, workflow: activateResponse.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Execution Management Tools server.tool( "list_executions", "List workflow executions with filtering and pagination support", { includeData: z.boolean().optional().describe("Include execution's detailed data"), status: z.enum(["error", "success", "waiting"]).optional().describe("Filter by execution status"), workflowId: z.string().optional().describe("Filter by specific workflow ID"), projectId: z.string().optional().describe("Filter by project ID"), limit: z.number().min(1).max(250).optional().describe("Number of executions to return (max: 250)"), cursor: z.string().optional().describe("Pagination cursor for next page") }, async ({ includeData, status, workflowId, projectId, limit, cursor }) => { try { const params = new URLSearchParams(); if (includeData !== undefined) params.append('includeData', includeData.toString()); if (status) params.append('status', status); if (workflowId) params.append('workflowId', workflowId); if (projectId) params.append('projectId', projectId); if (limit) params.append('limit', limit.toString()); if (cursor) params.append('cursor', cursor); const response = await n8nApi.get(`/executions?${params.toString()}`); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "get_execution", "Get detailed information about a specific workflow execution", { id: z.string().describe("Execution ID"), includeData: z.boolean().optional().describe("Include detailed execution data") }, async ({ id, includeData }) => { try { const params = new URLSearchParams(); if (includeData !== undefined) params.append('includeData', includeData.toString()); const url = `/executions/${id}${params.toString() ? `?${params.toString()}` : ''}`; const response = await n8nApi.get(url); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "delete_execution", "Delete a workflow execution record from the n8n instance", { id: z.string().describe("Execution ID to delete") }, async ({ id }) => { try { const response = await n8nApi.delete(`/executions/${id}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Execution ${id} deleted successfully`, deletedExecution: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Tag Management Tools server.tool( "list_tags", "List all workflow tags with pagination support", { limit: z.number().min(1).max(250).optional().describe("Number of tags to return (max: 250)"), cursor: z.string().optional().describe("Pagination cursor for next page") }, async ({ limit, cursor }) => { try { const params = new URLSearchParams(); if (limit) params.append('limit', limit.toString()); if (cursor) params.append('cursor', cursor); const response = await n8nApi.get(`/tags?${params.toString()}`); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "create_tag", "Create a new workflow tag for organization and categorization", { name: z.string().describe("Name of the tag to create") }, async ({ name }) => { try { const response = await n8nApi.post('/tags', { name }); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Tag '${name}' created successfully`, tag: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "get_tag", "Retrieve individual tag details by ID", { id: z.string().describe("Tag ID") }, async ({ id }) => { try { const response = await n8nApi.get(`/tags/${id}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, tag: response.data, message: `Tag ${id} retrieved successfully` }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "update_tag", "Modify tag names for better organization", { id: z.string().describe("Tag ID"), name: z.string().describe("New name for the tag") }, async ({ id, name }) => { try { const response = await n8nApi.put(`/tags/${id}`, { name }); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Tag ${id} updated successfully`, tag: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "delete_tag", "Remove unused tags from the system", { id: z.string().describe("Tag ID to delete") }, async ({ id }) => { try { const response = await n8nApi.delete(`/tags/${id}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Tag ${id} deleted successfully`, deletedTag: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "get_workflow_tags", "Get all tags associated with a specific workflow", { workflowId: z.string().describe("Workflow ID") }, async ({ workflowId }) => { try { const response = await n8nApi.get(`/workflows/${workflowId}/tags`); return { content: [{ type: "text", text: JSON.stringify({ success: true, workflowId, tags: response.data, message: `Tags for workflow ${workflowId} retrieved successfully` }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "update_workflow_tags", "Assign or remove tags from workflows", { workflowId: z.string().describe("Workflow ID"), tagIds: z.array(z.string()).describe("Array of tag IDs to assign to the workflow") }, async ({ workflowId, tagIds }) => { try { const response = await n8nApi.put(`/workflows/${workflowId}/tags`, { tagIds }); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Tags for workflow ${workflowId} updated successfully`, workflowId, assignedTags: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Credential Management Tools server.tool( "create_credential", "Create a new credential for workflow authentication. Use get_credential_schema first to understand required fields for the credential type.", { name: z.string().describe("Name for the credential"), type: z.string().describe("Credential type (e.g., 'httpBasicAuth', 'httpHeaderAuth', 'oAuth2Api', etc.)"), data: z.record(z.string(), z.any()).describe("Credential data object with required fields for the credential type") }, async ({ name, type, data }) => { try { const response = await n8nApi.post('/credentials', { name, type, data }); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Credential '${name}' created successfully`, credential: { id: response.data.id, name: response.data.name, type: response.data.type, createdAt: response.data.createdAt } }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "get_credential_schema", "Get the schema for a specific credential type to understand what fields are required when creating credentials.", { credentialType: z.string().describe("Credential type name (e.g., 'httpBasicAuth', 'httpHeaderAuth', 'oAuth2Api', 'githubApi', 'slackApi', etc.)") }, async ({ credentialType }) => { try { const response = await n8nApi.get(`/credentials/schema/${credentialType}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, credentialType, schema: response.data, message: `Schema for credential type '${credentialType}' retrieved successfully` }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); server.tool( "delete_credential", "Delete a credential by ID. This will remove the credential and make it unavailable for workflows. Use with caution as this action cannot be undone.", { id: z.string().describe("Credential ID to delete") }, async ({ id }) => { try { const response = await n8nApi.delete(`/credentials/${id}`); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Credential ${id} deleted successfully`, deletedCredential: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Security Audit Tool server.tool( "generate_audit", "Generate a comprehensive security audit report for the n8n instance", { additionalOptions: z.object({ daysAbandonedWorkflow: z.number().optional().describe("Number of days to consider a workflow abandoned"), categories: z.array(z.enum(["credentials", "database", "nodes", "filesystem", "instance"])).optional().describe("Audit categories to include") }).optional().describe("Additional audit configuration options") }, async ({ additionalOptions }) => { try { const auditPayload: any = {}; if (additionalOptions) { if (additionalOptions.daysAbandonedWorkflow !== undefined) { auditPayload.daysAbandonedWorkflow = additionalOptions.daysAbandonedWorkflow; } if (additionalOptions.categories) { auditPayload.categories = additionalOptions.categories; } } const response = await n8nApi.post('/audit', auditPayload); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Security audit generated successfully", audit: response.data }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("N8N Workflow Builder MCP server v0.10.3 running on stdio"); console.error("Modern SDK 1.17.0 with 23 tools: 9 workflow + 3 execution + 7 tag + 3 credential + 1 audit"); } main().catch((error) => { console.error("Server error:", error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/makafeli/n8n-workflow-builder'

If you have feedback or need assistance with the MCP directory API, please join our Discord server