fix: resolve WASM file loading issue for npx execution (closes #31)

- Enhanced database adapter to support multiple WASM file resolution strategies
- Added require.resolve() for reliable package location in npm environments
- Made better-sqlite3 an optional dependency
- Improved error handling with clear messages
- Updated version to 2.7.13
- Updated CHANGELOG and README badges
This commit is contained in:
czlonkowski
2025-07-11 08:48:37 +02:00
parent f525303748
commit 1170ad27a6
11 changed files with 213 additions and 5 deletions

View File

@@ -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)

Binary file not shown.

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -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"
}
}

View File

@@ -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));
"

View File

@@ -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();

43
scripts/test-sqljs-fallback.js Executable file
View File

@@ -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();

52
scripts/test-wasm-resolution.js Executable file
View File

@@ -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);
}

View File

@@ -117,14 +117,53 @@ async function createBetterSQLiteAdapter(dbPath: string): Promise<DatabaseAdapte
* Create sql.js adapter with persistence
*/
async function createSQLJSAdapter(dbPath: string): Promise<DatabaseAdapter> {
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;
}

View File

@@ -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"
}
}
}
}