diff --git a/README.md b/README.md index eb8a979..c378944 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![GitHub stars](https://img.shields.io/github/stars/czlonkowski/n8n-mcp?style=social)](https://github.com/czlonkowski/n8n-mcp) -[![Version](https://img.shields.io/badge/version-2.7.12-blue.svg)](https://github.com/czlonkowski/n8n-mcp) +[![Version](https://img.shields.io/badge/version-2.7.13-blue.svg)](https://github.com/czlonkowski/n8n-mcp) [![npm version](https://img.shields.io/npm/v/n8n-mcp.svg)](https://www.npmjs.com/package/n8n-mcp) [![n8n version](https://img.shields.io/badge/n8n-v1.101.1-orange.svg)](https://github.com/n8n-io/n8n) [![Docker](https://img.shields.io/badge/docker-ghcr.io%2Fczlonkowski%2Fn8n--mcp-green.svg)](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp) diff --git a/data/nodes.db b/data/nodes.db index 9b9fa53..96c0038 100644 Binary files a/data/nodes.db and b/data/nodes.db differ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7337c24..9f50f62 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.7.13] - 2025-07-11 + +### Fixed +- **npx Execution**: Fixed WASM file resolution for sql.js when running via `npx n8n-mcp` (Issue #31) + - Enhanced WASM file locator to try multiple path resolution strategies + - Added `require.resolve()` for reliable package location in npm environments + - Made better-sqlite3 an optional dependency to prevent installation failures + - Improved error messages when sql.js fails to load + - The package now works correctly with `npx` without any manual configuration + +### Changed +- **Database Adapter**: Improved path resolution for both local development and npm package contexts + - Supports various npm installation scenarios (global, local, npx cache) + - Better fallback handling for sql.js WebAssembly file loading + ## [2.7.12] - 2025-07-10 ### Updated @@ -565,6 +580,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Basic n8n and MCP integration - Core workflow automation features +[2.7.13]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.12...v2.7.13 [2.7.12]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.11...v2.7.12 [2.7.11]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.10...v2.7.11 [2.7.10]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.8...v2.7.10 diff --git a/package.json b/package.json index 94d5263..da95549 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.7.12", + "version": "2.7.13", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "main": "dist/index.js", "bin": { @@ -103,5 +103,8 @@ "n8n-workflow": "^1.98.0", "sql.js": "^1.13.0", "uuid": "^10.0.0" + }, + "optionalDependencies": { + "better-sqlite3": "^11.10.0" } } diff --git a/package.runtime.json b/package.runtime.json index 5407291..085632b 100644 --- a/package.runtime.json +++ b/package.runtime.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp-runtime", - "version": "2.7.12", + "version": "2.7.13", "description": "n8n MCP Server Runtime Dependencies Only", "private": true, "dependencies": { @@ -15,5 +15,8 @@ }, "engines": { "node": ">=16.0.0" + }, + "optionalDependencies": { + "better-sqlite3": "^11.10.0" } } diff --git a/scripts/publish-npm.sh b/scripts/publish-npm.sh index 5b9d4d3..573777e 100755 --- a/scripts/publish-npm.sh +++ b/scripts/publish-npm.sh @@ -64,6 +64,7 @@ pkg.license = 'MIT'; pkg.bugs = { url: 'https://github.com/czlonkowski/n8n-mcp/issues' }; pkg.homepage = 'https://github.com/czlonkowski/n8n-mcp#readme'; pkg.files = ['dist/**/*', 'data/nodes.db', '.env.example', 'README.md', 'LICENSE']; +// Note: node_modules are automatically included for dependencies delete pkg.private; // Remove private field so we can publish require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2)); " diff --git a/scripts/test-database-adapter.js b/scripts/test-database-adapter.js new file mode 100755 index 0000000..1d50c68 --- /dev/null +++ b/scripts/test-database-adapter.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +const { createDatabaseAdapter } = require('../dist/database/database-adapter'); +const path = require('path'); + +async function testDatabaseAdapter() { + console.log('Testing database adapter initialization...\n'); + + const dbPath = path.join(__dirname, '../data/nodes.db'); + console.log('Database path:', dbPath); + + try { + console.log('Creating database adapter...'); + const adapter = await createDatabaseAdapter(dbPath); + + console.log('\n✅ Database adapter created successfully!'); + + // Test a simple query + console.log('\nTesting database query...'); + const stmt = adapter.prepare('SELECT COUNT(*) as count FROM nodes'); + const result = stmt.get(); + console.log(`✅ Database contains ${result.count} nodes`); + + // Check FTS5 support + console.log('\nChecking FTS5 support...'); + const hasFTS5 = adapter.checkFTS5Support(); + console.log(`FTS5 support: ${hasFTS5 ? '✅ Available' : '❌ Not available'}`); + + adapter.close(); + console.log('\n✅ All tests passed!'); + } catch (error) { + console.error('\n❌ Error:', error.message); + console.error('Stack:', error.stack); + process.exit(1); + } +} + +testDatabaseAdapter(); \ No newline at end of file diff --git a/scripts/test-sqljs-fallback.js b/scripts/test-sqljs-fallback.js new file mode 100755 index 0000000..e884235 --- /dev/null +++ b/scripts/test-sqljs-fallback.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +// Force sql.js usage by temporarily hiding better-sqlite3 +const Module = require('module'); +const originalRequire = Module.prototype.require; + +Module.prototype.require = function(id) { + if (id === 'better-sqlite3') { + throw new Error('Simulating better-sqlite3 not available (NODE_MODULE_VERSION mismatch)'); + } + return originalRequire.apply(this, arguments); +}; + +const { createDatabaseAdapter } = require('../dist/database/database-adapter'); +const path = require('path'); + +async function testSqlJsFallback() { + console.log('Testing sql.js fallback...\n'); + + const dbPath = path.join(__dirname, '../data/nodes.db'); + + try { + console.log('Creating database adapter (better-sqlite3 disabled)...'); + const adapter = await createDatabaseAdapter(dbPath); + + console.log('\n✅ Database adapter created successfully with sql.js!'); + + // Test a simple query + console.log('\nTesting database query...'); + const stmt = adapter.prepare('SELECT COUNT(*) as count FROM nodes'); + const result = stmt.get(); + console.log(`✅ Database contains ${result.count} nodes`); + + adapter.close(); + console.log('\n✅ sql.js fallback works correctly!'); + } catch (error) { + console.error('\n❌ Error:', error.message); + console.error('Stack:', error.stack); + process.exit(1); + } +} + +testSqlJsFallback(); \ No newline at end of file diff --git a/scripts/test-wasm-resolution.js b/scripts/test-wasm-resolution.js new file mode 100755 index 0000000..96a61ae --- /dev/null +++ b/scripts/test-wasm-resolution.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +const path = require('path'); +const fs = require('fs'); + +console.log('Testing WASM file resolution...\n'); + +// Show current environment +console.log('Current directory:', process.cwd()); +console.log('Script directory:', __dirname); +console.log('Node version:', process.version); +console.log(''); + +// Test different path resolutions +const testPaths = [ + // Local development path + path.join(__dirname, '../node_modules/sql.js/dist/sql-wasm.wasm'), + // When installed as npm package + path.join(__dirname, '../../sql.js/dist/sql-wasm.wasm'), + // Alternative npm package path + path.join(process.cwd(), 'node_modules/sql.js/dist/sql-wasm.wasm'), +]; + +console.log('Checking potential WASM file locations:'); +testPaths.forEach((testPath, index) => { + const exists = fs.existsSync(testPath); + console.log(`${index + 1}. ${testPath}`); + console.log(` Exists: ${exists ? '✅' : '❌'}`); +}); + +// Try require.resolve +console.log('\nTrying require.resolve:'); +try { + const wasmPath = require.resolve('sql.js/dist/sql-wasm.wasm'); + console.log('✅ Found via require.resolve:', wasmPath); + console.log(' Exists:', fs.existsSync(wasmPath) ? '✅' : '❌'); +} catch (e) { + console.log('❌ Failed to resolve via require.resolve:', e.message); +} + +// Try to find sql.js package location +console.log('\nTrying to find sql.js package:'); +try { + const sqlJsPath = require.resolve('sql.js'); + console.log('✅ Found sql.js at:', sqlJsPath); + const sqlJsDir = path.dirname(sqlJsPath); + const wasmFromSqlJs = path.join(sqlJsDir, '../dist/sql-wasm.wasm'); + console.log(' Derived WASM path:', wasmFromSqlJs); + console.log(' Exists:', fs.existsSync(wasmFromSqlJs) ? '✅' : '❌'); +} catch (e) { + console.log('❌ Failed to find sql.js package:', e.message); +} \ No newline at end of file diff --git a/src/database/database-adapter.ts b/src/database/database-adapter.ts index 4d4d5e7..d7de1a9 100644 --- a/src/database/database-adapter.ts +++ b/src/database/database-adapter.ts @@ -117,14 +117,53 @@ async function createBetterSQLiteAdapter(dbPath: string): Promise { - const initSqlJs = require('sql.js'); + let initSqlJs; + try { + initSqlJs = require('sql.js'); + } catch (error) { + logger.error('Failed to load sql.js module:', error); + throw new Error('sql.js module not found. This might be an issue with npm package installation.'); + } // Initialize sql.js const SQL = await initSqlJs({ // This will look for the wasm file in node_modules locateFile: (file: string) => { if (file.endsWith('.wasm')) { - return path.join(__dirname, '../../node_modules/sql.js/dist/', file); + // Try multiple paths to find the WASM file + const possiblePaths = [ + // Local development path + path.join(__dirname, '../../node_modules/sql.js/dist/', file), + // When installed as npm package + path.join(__dirname, '../../../sql.js/dist/', file), + // Alternative npm package path + path.join(process.cwd(), 'node_modules/sql.js/dist/', file), + // Try to resolve from require + path.join(path.dirname(require.resolve('sql.js')), '../dist/', file) + ]; + + // Find the first existing path + for (const tryPath of possiblePaths) { + if (fsSync.existsSync(tryPath)) { + if (process.env.MCP_MODE !== 'stdio') { + logger.debug(`Found WASM file at: ${tryPath}`); + } + return tryPath; + } + } + + // If not found, try the last resort - require.resolve + try { + const wasmPath = require.resolve('sql.js/dist/sql-wasm.wasm'); + if (process.env.MCP_MODE !== 'stdio') { + logger.debug(`Found WASM file via require.resolve: ${wasmPath}`); + } + return wasmPath; + } catch (e) { + // Fall back to the default path + logger.warn(`Could not find WASM file, using default path: ${file}`); + return file; + } } return file; } diff --git a/test-claude-desktop-config.json b/test-claude-desktop-config.json new file mode 100644 index 0000000..515a42b --- /dev/null +++ b/test-claude-desktop-config.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "n8n-mcp-local": { + "command": "node", + "args": ["/Users/romualdczlonkowski/Pliki/n8n-mcp/n8n-mcp/dist/mcp/index.js"], + "env": { + "MCP_MODE": "stdio", + "LOG_LEVEL": "error", + "DISABLE_CONSOLE_OUTPUT": "true" + } + } + } +} \ No newline at end of file