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:
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/czlonkowski/n8n-mcp)
|
||||
[](https://github.com/czlonkowski/n8n-mcp)
|
||||
[](https://github.com/czlonkowski/n8n-mcp)
|
||||
[](https://www.npmjs.com/package/n8n-mcp)
|
||||
[](https://github.com/n8n-io/n8n)
|
||||
[](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
||||
|
||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
"
|
||||
|
||||
38
scripts/test-database-adapter.js
Executable file
38
scripts/test-database-adapter.js
Executable 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
43
scripts/test-sqljs-fallback.js
Executable 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
52
scripts/test-wasm-resolution.js
Executable 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
13
test-claude-desktop-config.json
Normal file
13
test-claude-desktop-config.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user