Implement n8n-MCP integration

This commit adds a complete integration between n8n workflow automation and the Model Context Protocol (MCP):

Features:
- MCP server that exposes n8n workflows as tools, resources, and prompts
- Custom n8n node for connecting to MCP servers from workflows
- Bidirectional bridge for data format conversion
- Token-based authentication and credential management
- Comprehensive error handling and logging
- Full test coverage for core components

Infrastructure:
- TypeScript/Node.js project setup with proper build configuration
- Docker support with multi-stage builds
- Development and production docker-compose configurations
- Installation script for n8n custom node deployment

Documentation:
- Detailed README with usage examples and API reference
- Environment configuration templates
- Troubleshooting guide

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-06-07 15:43:02 +00:00
parent b51591a87d
commit 1f8140c45c
28 changed files with 17543 additions and 0 deletions

106
src/utils/logger.ts Normal file
View File

@@ -0,0 +1,106 @@
export enum LogLevel {
ERROR = 0,
WARN = 1,
INFO = 2,
DEBUG = 3,
}
export interface LoggerConfig {
level: LogLevel;
prefix?: string;
timestamp?: boolean;
}
export class Logger {
private config: LoggerConfig;
private static instance: Logger;
constructor(config?: Partial<LoggerConfig>) {
this.config = {
level: LogLevel.INFO,
prefix: 'n8n-mcp',
timestamp: true,
...config,
};
}
static getInstance(config?: Partial<LoggerConfig>): Logger {
if (!Logger.instance) {
Logger.instance = new Logger(config);
}
return Logger.instance;
}
private formatMessage(level: string, message: string): string {
const parts: string[] = [];
if (this.config.timestamp) {
parts.push(`[${new Date().toISOString()}]`);
}
if (this.config.prefix) {
parts.push(`[${this.config.prefix}]`);
}
parts.push(`[${level}]`);
parts.push(message);
return parts.join(' ');
}
private log(level: LogLevel, levelName: string, message: string, ...args: any[]): void {
if (level <= this.config.level) {
const formattedMessage = this.formatMessage(levelName, message);
switch (level) {
case LogLevel.ERROR:
console.error(formattedMessage, ...args);
break;
case LogLevel.WARN:
console.warn(formattedMessage, ...args);
break;
default:
console.log(formattedMessage, ...args);
}
}
}
error(message: string, ...args: any[]): void {
this.log(LogLevel.ERROR, 'ERROR', message, ...args);
}
warn(message: string, ...args: any[]): void {
this.log(LogLevel.WARN, 'WARN', message, ...args);
}
info(message: string, ...args: any[]): void {
this.log(LogLevel.INFO, 'INFO', message, ...args);
}
debug(message: string, ...args: any[]): void {
this.log(LogLevel.DEBUG, 'DEBUG', message, ...args);
}
setLevel(level: LogLevel): void {
this.config.level = level;
}
static parseLogLevel(level: string): LogLevel {
switch (level.toLowerCase()) {
case 'error':
return LogLevel.ERROR;
case 'warn':
return LogLevel.WARN;
case 'debug':
return LogLevel.DEBUG;
case 'info':
default:
return LogLevel.INFO;
}
}
}
// Create a default logger instance
export const logger = Logger.getInstance({
level: Logger.parseLogLevel(process.env.LOG_LEVEL || 'info'),
});