test-connectivity.jsā¢7.55 kB
#!/usr/bin/env node
import 'dotenv/config';
import axios from 'axios';
// Configuration from environment or defaults
const TRILIUM_URL = process.env.TRILIUM_URL || 'http://localhost:8081';
const TRILIUM_AUTH_TOKEN = process.env.TRILIUM_AUTH_TOKEN;
console.log('š TriliumNext API Connectivity Test');
console.log('=====================================');
console.log(`URL: ${TRILIUM_URL}`);
console.log(`Token: ${TRILIUM_AUTH_TOKEN ? TRILIUM_AUTH_TOKEN.substring(0, 10) + '...' : 'Not provided'}`);
console.log('');
async function testConnectivity() {
console.log('1ļøā£ Testing basic connectivity...');
try {
// Test basic server connectivity (without auth)
const response = await axios.get(`${TRILIUM_URL}`, {
timeout: 5000,
validateStatus: () => true // Accept any status code
});
console.log(` ā
Server responded with status: ${response.status}`);
console.log(` š Server headers: ${JSON.stringify(response.headers, null, 2)}`);
if (response.status === 200) {
console.log(' ā
TriliumNext server is running and accessible');
} else {
console.log(` ā ļø Server returned status ${response.status} - this might be normal for the root endpoint`);
}
return true;
} catch (error) {
console.log(` ā Connection failed: ${error.message}`);
if (error.code === 'ECONNREFUSED') {
console.log(' š” Is TriliumNext running? Try starting it first.');
} else if (error.code === 'ENOTFOUND') {
console.log(' š” Check the TRILIUM_URL - hostname not found.');
}
return false;
}
}
async function testETAPIEndpoint() {
console.log('\n2ļøā£ Testing ETAPI endpoint accessibility...');
try {
const response = await axios.get(`${TRILIUM_URL}/etapi`, {
timeout: 5000,
validateStatus: () => true
});
console.log(` ā
ETAPI endpoint responded with status: ${response.status}`);
return response.status < 500; // Accept 4xx but not 5xx errors
} catch (error) {
console.log(` ā ETAPI endpoint failed: ${error.message}`);
return false;
}
}
async function testAuthentication() {
console.log('\n3ļøā£ Testing authentication...');
if (!TRILIUM_AUTH_TOKEN) {
console.log(' ā No authentication token provided');
console.log(' š” Set TRILIUM_AUTH_TOKEN environment variable');
return false;
}
try {
const response = await axios.get(`${TRILIUM_URL}/etapi/notes?search=*&limit=1`, {
headers: {
'Authorization': `Bearer ${TRILIUM_AUTH_TOKEN}`,
'Content-Type': 'application/json'
},
timeout: 10000,
validateStatus: () => true
});
console.log(` ā
Auth request responded with status: ${response.status}`);
if (response.status === 200) {
console.log(' ā
Authentication successful!');
console.log(` š Found ${Array.isArray(response.data) ? response.data.length : 'unknown'} notes`);
return true;
} else if (response.status === 401) {
console.log(' ā Authentication failed - invalid token');
console.log(' š” Check your TRILIUM_AUTH_TOKEN');
return false;
} else if (response.status === 403) {
console.log(' ā Access forbidden - token lacks permissions');
return false;
} else {
console.log(` ā ļø Unexpected status: ${response.status}`);
console.log(` š Response: ${JSON.stringify(response.data, null, 2)}`);
return false;
}
} catch (error) {
console.log(` ā Authentication test failed: ${error.message}`);
return false;
}
}
async function testBasicOperations() {
console.log('\n4ļøā£ Testing basic API operations...');
if (!TRILIUM_AUTH_TOKEN) {
console.log(' āļø Skipping - no auth token');
return false;
}
const headers = {
'Authorization': `Bearer ${TRILIUM_AUTH_TOKEN}`,
'Content-Type': 'application/json'
};
try {
// Test getting notes with search (search parameter is mandatory)
console.log(' š Testing note search...');
const searchResponse = await axios.get(`${TRILIUM_URL}/etapi/notes?search=*&limit=1`, {
headers,
timeout: 10000
});
if (searchResponse.status === 200) {
console.log(' ā
Note search successful');
const notes = searchResponse.data;
if (Array.isArray(notes) && notes.length > 0) {
const testNote = notes[0];
console.log(` š Sample note: "${testNote.title}" (${testNote.noteId})`);
// Test getting specific note content
console.log(' š Testing note content retrieval...');
const contentResponse = await axios.get(`${TRILIUM_URL}/etapi/notes/${testNote.noteId}/content`, {
headers,
timeout: 10000
});
if (contentResponse.status === 200) {
console.log(' ā
Note content retrieval successful');
console.log(` š Content length: ${typeof contentResponse.data === 'string' ? contentResponse.data.length : 'binary'} characters`);
} else {
console.log(` ā ļø Note content failed with status: ${contentResponse.status}`);
}
} else {
console.log(' ā¹ļø No notes found in TriliumNext instance');
}
} else {
console.log(` ā Note search failed with status: ${searchResponse.status}`);
}
return true;
} catch (error) {
console.log(` ā Basic operations test failed: ${error.message}`);
return false;
}
}
async function runDiagnostics() {
console.log('\nš„ Running diagnostics...');
// Check if we're using the right port
if (TRILIUM_URL.includes(':8080')) {
console.log(' ā ļø Using port 8080 - make sure TriliumNext is running on this port');
} else if (TRILIUM_URL.includes(':8081')) {
console.log(' ā¹ļø Using port 8081 - make sure TriliumNext is running on this port');
}
// Check token format
if (TRILIUM_AUTH_TOKEN) {
if (TRILIUM_AUTH_TOKEN.length < 20) {
console.log(' ā ļø Auth token seems short - verify it\'s complete');
} else {
console.log(' ā
Auth token length looks reasonable');
}
}
console.log('\nš” Troubleshooting tips:');
console.log(' ⢠Make sure TriliumNext is running: check http://localhost:8081 in browser');
console.log(' ⢠Verify auth token: go to TriliumNext ā Options ā ETAPI');
console.log(' ⢠Check port: TriliumNext might be on 8080 instead of 8081');
console.log(' ⢠Test manually: curl -H "Authorization: Bearer TOKEN" "http://localhost:8081/etapi/notes?search=*&limit=1"');
}
async function main() {
const tests = [
testConnectivity,
testETAPIEndpoint,
testAuthentication,
testBasicOperations
];
let passed = 0;
for (const test of tests) {
const result = await test();
if (result) passed++;
}
await runDiagnostics();
console.log('\nš Test Results');
console.log('===============');
console.log(`Passed: ${passed}/${tests.length} tests`);
if (passed === tests.length) {
console.log('š All tests passed! TriliumNext API is working correctly.');
console.log('ā
Your MCP server should work fine.');
} else {
console.log('ā Some tests failed. Fix the issues above before using the MCP server.');
}
process.exit(passed === tests.length ? 0 : 1);
}
main().catch(error => {
console.error('š„ Test script crashed:', error);
process.exit(1);
});