mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 05:23:08 +00:00
fix: update integration tests to use valid tools after v2.25.0 removal
Replaced all references to removed tools in integration tests: - list_nodes -> search_nodes - get_database_statistics -> tools_documentation - list_ai_tools -> search_nodes/tools_documentation - list_tasks -> tools_documentation - get_node_as_tool_info -> removed test section Updated test files: - tests/integration/mcp-protocol/basic-connection.test.ts - tests/integration/mcp-protocol/performance.test.ts - tests/integration/mcp-protocol/session-management.test.ts - tests/integration/mcp-protocol/test-helpers.ts - tests/integration/mcp-protocol/tool-invocation.test.ts - tests/integration/telemetry/mcp-telemetry.test.ts - tests/unit/mcp/disabled-tools.test.ts - tests/unit/mcp/tools-documentation.test.ts Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,49 +5,48 @@ describe('Basic MCP Connection', () => {
|
|||||||
it('should initialize MCP server', async () => {
|
it('should initialize MCP server', async () => {
|
||||||
const server = new N8NDocumentationMCPServer();
|
const server = new N8NDocumentationMCPServer();
|
||||||
|
|
||||||
// Test executeTool directly - it returns raw data
|
// Test executeTool directly - tools_documentation returns a string
|
||||||
const result = await server.executeTool('get_database_statistics', {});
|
const result = await server.executeTool('tools_documentation', {});
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(typeof result).toBe('object');
|
expect(typeof result).toBe('string');
|
||||||
expect(result.totalNodes).toBeDefined();
|
expect(result).toContain('n8n MCP');
|
||||||
expect(result.statistics).toBeDefined();
|
|
||||||
|
|
||||||
await server.shutdown();
|
await server.shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute list_nodes tool', async () => {
|
it('should execute search_nodes tool', async () => {
|
||||||
const server = new N8NDocumentationMCPServer();
|
const server = new N8NDocumentationMCPServer();
|
||||||
|
|
||||||
// First check if we have any nodes in the database
|
try {
|
||||||
const stats = await server.executeTool('get_database_statistics', {});
|
// Search for a common node to verify database has content
|
||||||
const hasNodes = stats.totalNodes > 0;
|
const result = await server.executeTool('search_nodes', { query: 'http', limit: 5 });
|
||||||
|
|
||||||
const result = await server.executeTool('list_nodes', { limit: 5 });
|
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(typeof result).toBe('object');
|
expect(typeof result).toBe('object');
|
||||||
expect(result.nodes).toBeDefined();
|
expect(result.results).toBeDefined();
|
||||||
expect(Array.isArray(result.nodes)).toBe(true);
|
expect(Array.isArray(result.results)).toBe(true);
|
||||||
|
|
||||||
if (hasNodes) {
|
if (result.totalCount > 0) {
|
||||||
// If database has nodes, we should get up to 5
|
// If database has nodes, we should get results
|
||||||
expect(result.nodes.length).toBeLessThanOrEqual(5);
|
expect(result.results.length).toBeLessThanOrEqual(5);
|
||||||
expect(result.nodes.length).toBeGreaterThan(0);
|
expect(result.results.length).toBeGreaterThan(0);
|
||||||
expect(result.nodes[0]).toHaveProperty('nodeType');
|
expect(result.results[0]).toHaveProperty('nodeType');
|
||||||
expect(result.nodes[0]).toHaveProperty('displayName');
|
expect(result.results[0]).toHaveProperty('displayName');
|
||||||
} else {
|
}
|
||||||
// In test environment with empty database, we expect empty results
|
} catch (error: any) {
|
||||||
expect(result.nodes).toHaveLength(0);
|
// In test environment with empty database, expect appropriate error
|
||||||
|
expect(error.message).toContain('Database is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
await server.shutdown();
|
await server.shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search nodes', async () => {
|
it('should search nodes by keyword', async () => {
|
||||||
const server = new N8NDocumentationMCPServer();
|
const server = new N8NDocumentationMCPServer();
|
||||||
|
|
||||||
// First check if we have any nodes in the database
|
try {
|
||||||
const stats = await server.executeTool('get_database_statistics', {});
|
// Search to check if database has nodes
|
||||||
const hasNodes = stats.totalNodes > 0;
|
const searchResult = await server.executeTool('search_nodes', { query: 'set', limit: 1 });
|
||||||
|
const hasNodes = searchResult.totalCount > 0;
|
||||||
|
|
||||||
const result = await server.executeTool('search_nodes', { query: 'webhook' });
|
const result = await server.executeTool('search_nodes', { query: 'webhook' });
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
@@ -64,10 +63,10 @@ describe('Basic MCP Connection', () => {
|
|||||||
const webhookNode = result.results.find((n: any) => n.nodeType === 'nodes-base.webhook');
|
const webhookNode = result.results.find((n: any) => n.nodeType === 'nodes-base.webhook');
|
||||||
expect(webhookNode).toBeDefined();
|
expect(webhookNode).toBeDefined();
|
||||||
expect(webhookNode.displayName).toContain('Webhook');
|
expect(webhookNode.displayName).toContain('Webhook');
|
||||||
} else {
|
}
|
||||||
// In test environment with empty database, we expect empty results
|
} catch (error: any) {
|
||||||
expect(result.results).toHaveLength(0);
|
// In test environment with empty database, expect appropriate error
|
||||||
expect(result.totalCount).toBe(0);
|
expect(error.message).toContain('Database is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
await server.shutdown();
|
await server.shutdown();
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
await client.connect(clientTransport);
|
await client.connect(clientTransport);
|
||||||
|
|
||||||
// Verify database is populated by checking statistics
|
// Verify database is populated by searching for a common node
|
||||||
const statsResponse = await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
const searchResponse = await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 1 } });
|
||||||
if ((statsResponse as any).content && (statsResponse as any).content[0]) {
|
if ((searchResponse as any).content && (searchResponse as any).content[0]) {
|
||||||
const stats = JSON.parse((statsResponse as any).content[0].text);
|
const searchResult = JSON.parse((searchResponse as any).content[0].text);
|
||||||
// Ensure database has nodes for testing
|
// Ensure database has nodes for testing
|
||||||
if (!stats.totalNodes || stats.totalNodes === 0) {
|
if (!searchResult.totalCount || searchResult.totalCount === 0) {
|
||||||
console.error('Database stats:', stats);
|
console.error('Search result:', searchResult);
|
||||||
throw new Error('Test database not properly populated');
|
throw new Error('Test database not properly populated');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,13 +46,13 @@ describe('MCP Performance Tests', () => {
|
|||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = performance.now() - start;
|
const duration = performance.now() - start;
|
||||||
const avgTime = duration / iterations;
|
const avgTime = duration / iterations;
|
||||||
|
|
||||||
console.log(`Average response time for get_database_statistics: ${avgTime.toFixed(2)}ms`);
|
console.log(`Average response time for tools_documentation: ${avgTime.toFixed(2)}ms`);
|
||||||
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
||||||
|
|
||||||
// Environment-aware threshold (relaxed +20% for type safety overhead)
|
// Environment-aware threshold (relaxed +20% for type safety overhead)
|
||||||
@@ -60,18 +60,18 @@ describe('MCP Performance Tests', () => {
|
|||||||
expect(avgTime).toBeLessThan(threshold);
|
expect(avgTime).toBeLessThan(threshold);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle list operations efficiently', async () => {
|
it('should handle search operations efficiently', async () => {
|
||||||
const iterations = 50;
|
const iterations = 50;
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
await client.callTool({ name: 'list_nodes', arguments: { limit: 10 } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 10 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = performance.now() - start;
|
const duration = performance.now() - start;
|
||||||
const avgTime = duration / iterations;
|
const avgTime = duration / iterations;
|
||||||
|
|
||||||
console.log(`Average response time for list_nodes: ${avgTime.toFixed(2)}ms`);
|
console.log(`Average response time for search_nodes: ${avgTime.toFixed(2)}ms`);
|
||||||
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
||||||
|
|
||||||
// Environment-aware threshold
|
// Environment-aware threshold
|
||||||
@@ -137,7 +137,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < concurrentRequests; i++) {
|
for (let i = 0; i < concurrentRequests; i++) {
|
||||||
promises.push(
|
promises.push(
|
||||||
client.callTool({ name: 'list_nodes', arguments: { limit: 5 } })
|
client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 5 } })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,11 +156,11 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
it('should handle mixed concurrent operations', async () => {
|
it('should handle mixed concurrent operations', async () => {
|
||||||
const operations = [
|
const operations = [
|
||||||
{ tool: 'list_nodes', params: { limit: 10 } },
|
{ tool: 'search_nodes', params: { query: 'http', limit: 10 } },
|
||||||
{ tool: 'search_nodes', params: { query: 'http' } },
|
{ tool: 'search_nodes', params: { query: 'webhook' } },
|
||||||
{ tool: 'get_database_statistics', params: {} },
|
{ tool: 'tools_documentation', params: {} },
|
||||||
{ tool: 'list_ai_tools', params: {} },
|
{ tool: 'get_node', params: { nodeType: 'nodes-base.httpRequest' } },
|
||||||
{ tool: 'list_tasks', params: {} }
|
{ tool: 'get_node', params: { nodeType: 'nodes-base.webhook' } }
|
||||||
];
|
];
|
||||||
|
|
||||||
const rounds = 10;
|
const rounds = 10;
|
||||||
@@ -186,16 +186,17 @@ describe('MCP Performance Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Large Data Performance', () => {
|
describe('Large Data Performance', () => {
|
||||||
it('should handle large node lists efficiently', async () => {
|
it('should handle large search results efficiently', async () => {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: {
|
const response = await client.callTool({ name: 'search_nodes', arguments: {
|
||||||
limit: 200 // Get many nodes
|
query: 'n8n', // Broad query to get many results
|
||||||
|
limit: 200
|
||||||
} });
|
} });
|
||||||
|
|
||||||
const duration = performance.now() - start;
|
const duration = performance.now() - start;
|
||||||
|
|
||||||
console.log(`Time to list 200 nodes: ${duration.toFixed(2)}ms`);
|
console.log(`Time to search 200 nodes: ${duration.toFixed(2)}ms`);
|
||||||
|
|
||||||
// Environment-aware threshold
|
// Environment-aware threshold
|
||||||
const threshold = process.env.CI ? 200 : 100;
|
const threshold = process.env.CI ? 200 : 100;
|
||||||
@@ -204,7 +205,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
// Check the response content
|
// Check the response content
|
||||||
expect(response).toBeDefined();
|
expect(response).toBeDefined();
|
||||||
|
|
||||||
let nodes;
|
let results;
|
||||||
if (response.content && Array.isArray(response.content) && response.content[0]) {
|
if (response.content && Array.isArray(response.content) && response.content[0]) {
|
||||||
// MCP standard response format
|
// MCP standard response format
|
||||||
expect(response.content[0].type).toBe('text');
|
expect(response.content[0].type).toBe('text');
|
||||||
@@ -212,8 +213,8 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(response.content[0].text);
|
const parsed = JSON.parse(response.content[0].text);
|
||||||
// list_nodes returns an object with nodes property
|
// search_nodes returns an object with results property
|
||||||
nodes = parsed.nodes || parsed;
|
results = parsed.results || parsed;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to parse JSON:', e);
|
console.error('Failed to parse JSON:', e);
|
||||||
console.error('Response text was:', response.content[0].text);
|
console.error('Response text was:', response.content[0].text);
|
||||||
@@ -221,18 +222,18 @@ describe('MCP Performance Tests', () => {
|
|||||||
}
|
}
|
||||||
} else if (Array.isArray(response)) {
|
} else if (Array.isArray(response)) {
|
||||||
// Direct array response
|
// Direct array response
|
||||||
nodes = response;
|
results = response;
|
||||||
} else if (response.nodes) {
|
} else if (response.results) {
|
||||||
// Object with nodes property
|
// Object with results property
|
||||||
nodes = response.nodes;
|
results = response.results;
|
||||||
} else {
|
} else {
|
||||||
console.error('Unexpected response format:', response);
|
console.error('Unexpected response format:', response);
|
||||||
throw new Error('Unexpected response format');
|
throw new Error('Unexpected response format');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(nodes).toBeDefined();
|
expect(results).toBeDefined();
|
||||||
expect(Array.isArray(nodes)).toBe(true);
|
expect(Array.isArray(results)).toBe(true);
|
||||||
expect(nodes.length).toBeGreaterThan(100);
|
expect(results.length).toBeGreaterThan(50);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle large workflow validation efficiently', async () => {
|
it('should handle large workflow validation efficiently', async () => {
|
||||||
@@ -304,7 +305,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
for (let j = 0; j < batchSize; j++) {
|
for (let j = 0; j < batchSize; j++) {
|
||||||
promises.push(
|
promises.push(
|
||||||
client.callTool({ name: 'get_database_statistics', arguments: {} })
|
client.callTool({ name: 'tools_documentation', arguments: {} })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +331,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
// Perform large operations
|
// Perform large operations
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
await client.callTool({ name: 'list_nodes', arguments: { limit: 200 } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'n8n', limit: 200 } });
|
||||||
await client.callTool({ name: 'get_node', arguments: {
|
await client.callTool({ name: 'get_node', arguments: {
|
||||||
nodeType: 'nodes-base.httpRequest'
|
nodeType: 'nodes-base.httpRequest'
|
||||||
} });
|
} });
|
||||||
@@ -363,7 +364,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < load; i++) {
|
for (let i = 0; i < load; i++) {
|
||||||
promises.push(
|
promises.push(
|
||||||
client.callTool({ name: 'list_nodes', arguments: { limit: 1 } })
|
client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 1 } })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,16 +404,16 @@ describe('MCP Performance Tests', () => {
|
|||||||
const operation = i % 4;
|
const operation = i % 4;
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case 0:
|
case 0:
|
||||||
promises.push(client.callTool({ name: 'list_nodes', arguments: { limit: 5 } }));
|
promises.push(client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 5 } }));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
promises.push(client.callTool({ name: 'search_nodes', arguments: { query: 'test' } }));
|
promises.push(client.callTool({ name: 'search_nodes', arguments: { query: 'test' } }));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
promises.push(client.callTool({ name: 'get_database_statistics', arguments: {} }));
|
promises.push(client.callTool({ name: 'tools_documentation', arguments: {} }));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
promises.push(client.callTool({ name: 'list_ai_tools', arguments: {} }));
|
promises.push(client.callTool({ name: 'get_node', arguments: { nodeType: 'nodes-base.set' } }));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,10 +432,10 @@ describe('MCP Performance Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Critical Path Optimization', () => {
|
describe('Critical Path Optimization', () => {
|
||||||
it('should optimize tool listing performance', async () => {
|
it('should optimize search performance', async () => {
|
||||||
// Warm up with multiple calls to ensure everything is initialized
|
// Warm up with multiple calls to ensure everything is initialized
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
await client.callTool({ name: 'list_nodes', arguments: { limit: 1 } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 1 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
const iterations = 100;
|
const iterations = 100;
|
||||||
@@ -442,7 +443,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++) {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
await client.callTool({ name: 'list_nodes', arguments: { limit: 20 } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 20 } });
|
||||||
times.push(performance.now() - start);
|
times.push(performance.now() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +455,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
const minTime = Math.min(...trimmedTimes);
|
const minTime = Math.min(...trimmedTimes);
|
||||||
const maxTime = Math.max(...trimmedTimes);
|
const maxTime = Math.max(...trimmedTimes);
|
||||||
|
|
||||||
console.log(`list_nodes performance - Avg: ${avgTime.toFixed(2)}ms, Min: ${minTime.toFixed(2)}ms, Max: ${maxTime.toFixed(2)}ms`);
|
console.log(`search_nodes performance - Avg: ${avgTime.toFixed(2)}ms, Min: ${minTime.toFixed(2)}ms, Max: ${maxTime.toFixed(2)}ms`);
|
||||||
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
console.log(`Environment: ${process.env.CI ? 'CI' : 'Local'}`);
|
||||||
|
|
||||||
// Environment-aware thresholds
|
// Environment-aware thresholds
|
||||||
@@ -467,7 +468,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
expect(maxTime).toBeLessThan(avgTime * maxMultiplier);
|
expect(maxTime).toBeLessThan(avgTime * maxMultiplier);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should optimize search performance', async () => {
|
it('should handle varied search queries efficiently', async () => {
|
||||||
// Warm up with multiple calls
|
// Warm up with multiple calls
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
await client.callTool({ name: 'search_nodes', arguments: { query: 'test' } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'test' } });
|
||||||
@@ -542,7 +543,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
|
|
||||||
while (performance.now() - start < duration) {
|
while (performance.now() - start < duration) {
|
||||||
try {
|
try {
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
requestCount++;
|
requestCount++;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorCount++;
|
errorCount++;
|
||||||
@@ -591,7 +592,7 @@ describe('MCP Performance Tests', () => {
|
|||||||
const recoveryTimes: number[] = [];
|
const recoveryTimes: number[] = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
recoveryTimes.push(performance.now() - start);
|
recoveryTimes.push(performance.now() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client.connect(clientTransport);
|
await client.connect(clientTransport);
|
||||||
|
|
||||||
// Make some requests
|
// Make some requests
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
await client.callTool({ name: 'list_nodes', arguments: { limit: 5 } });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 5 } });
|
||||||
|
|
||||||
// Clean termination
|
// Clean termination
|
||||||
await client.close();
|
await client.close();
|
||||||
@@ -109,7 +109,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
|
|
||||||
// Client should be closed
|
// Client should be closed
|
||||||
try {
|
try {
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect.fail('Should not be able to make requests after close');
|
expect.fail('Should not be able to make requests after close');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
@@ -133,7 +133,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client.connect(clientTransport);
|
await client.connect(clientTransport);
|
||||||
|
|
||||||
// Make a request to ensure connection is active
|
// Make a request to ensure connection is active
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
|
|
||||||
// Simulate abrupt disconnection by closing transport
|
// Simulate abrupt disconnection by closing transport
|
||||||
await clientTransport.close();
|
await clientTransport.close();
|
||||||
@@ -141,7 +141,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
|
|
||||||
// Further operations should fail
|
// Further operations should fail
|
||||||
try {
|
try {
|
||||||
await client.callTool({ name: 'list_nodes', arguments: {} });
|
await client.callTool({ name: 'search_nodes', arguments: { query: 'http' } });
|
||||||
expect.fail('Should not be able to make requests after transport close');
|
expect.fail('Should not be able to make requests after transport close');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error).toBeDefined();
|
expect(error).toBeDefined();
|
||||||
@@ -179,14 +179,14 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client1.connect(ct1);
|
await client1.connect(ct1);
|
||||||
|
|
||||||
// First session operations
|
// First session operations
|
||||||
const response1 = await client1.callTool({ name: 'list_nodes', arguments: { limit: 3 } });
|
const response1 = await client1.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 3 } });
|
||||||
expect(response1).toBeDefined();
|
expect(response1).toBeDefined();
|
||||||
expect((response1 as any).content).toBeDefined();
|
expect((response1 as any).content).toBeDefined();
|
||||||
expect((response1 as any).content[0]).toHaveProperty('type', 'text');
|
expect((response1 as any).content[0]).toHaveProperty('type', 'text');
|
||||||
const data1 = JSON.parse(((response1 as any).content[0] as any).text);
|
const data1 = JSON.parse(((response1 as any).content[0] as any).text);
|
||||||
// Handle both array response and object with nodes property
|
// Handle both array response and object with results property
|
||||||
const nodes1 = Array.isArray(data1) ? data1 : data1.nodes;
|
const results1 = Array.isArray(data1) ? data1 : data1.results;
|
||||||
expect(nodes1).toHaveLength(3);
|
expect(results1.length).toBeLessThanOrEqual(3);
|
||||||
|
|
||||||
// Close first session completely
|
// Close first session completely
|
||||||
await client1.close();
|
await client1.close();
|
||||||
@@ -204,14 +204,14 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client2.connect(ct2);
|
await client2.connect(ct2);
|
||||||
|
|
||||||
// Second session operations
|
// Second session operations
|
||||||
const response2 = await client2.callTool({ name: 'list_nodes', arguments: { limit: 5 } });
|
const response2 = await client2.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 5 } });
|
||||||
expect(response2).toBeDefined();
|
expect(response2).toBeDefined();
|
||||||
expect((response2 as any).content).toBeDefined();
|
expect((response2 as any).content).toBeDefined();
|
||||||
expect((response2 as any).content[0]).toHaveProperty('type', 'text');
|
expect((response2 as any).content[0]).toHaveProperty('type', 'text');
|
||||||
const data2 = JSON.parse(((response2 as any).content[0] as any).text);
|
const data2 = JSON.parse(((response2 as any).content[0] as any).text);
|
||||||
// Handle both array response and object with nodes property
|
// Handle both array response and object with results property
|
||||||
const nodes2 = Array.isArray(data2) ? data2 : data2.nodes;
|
const results2 = Array.isArray(data2) ? data2 : data2.results;
|
||||||
expect(nodes2).toHaveLength(5);
|
expect(results2.length).toBeLessThanOrEqual(5);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
await client2.close();
|
await client2.close();
|
||||||
@@ -228,7 +228,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
const client1 = new Client({ name: 'multi-seq-1', version: '1.0.0' }, {});
|
const client1 = new Client({ name: 'multi-seq-1', version: '1.0.0' }, {});
|
||||||
await client1.connect(ct1);
|
await client1.connect(ct1);
|
||||||
|
|
||||||
const resp1 = await client1.callTool({ name: 'get_database_statistics', arguments: {} });
|
const resp1 = await client1.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(resp1).toBeDefined();
|
expect(resp1).toBeDefined();
|
||||||
|
|
||||||
await client1.close();
|
await client1.close();
|
||||||
@@ -240,7 +240,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
const client2 = new Client({ name: 'multi-seq-2', version: '1.0.0' }, {});
|
const client2 = new Client({ name: 'multi-seq-2', version: '1.0.0' }, {});
|
||||||
await client2.connect(ct2);
|
await client2.connect(ct2);
|
||||||
|
|
||||||
const resp2 = await client2.callTool({ name: 'get_database_statistics', arguments: {} });
|
const resp2 = await client2.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(resp2).toBeDefined();
|
expect(resp2).toBeDefined();
|
||||||
|
|
||||||
await client2.close();
|
await client2.close();
|
||||||
@@ -261,7 +261,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client1.connect(ct1);
|
await client1.connect(ct1);
|
||||||
|
|
||||||
// Make some requests
|
// Make some requests
|
||||||
await client1.callTool({ name: 'list_nodes', arguments: { limit: 10 } });
|
await client1.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 10 } });
|
||||||
await client1.close();
|
await client1.close();
|
||||||
await mcpServer1.close();
|
await mcpServer1.close();
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client2.connect(ct2);
|
await client2.connect(ct2);
|
||||||
|
|
||||||
// Should work normally
|
// Should work normally
|
||||||
const response = await client2.callTool({ name: 'get_database_statistics', arguments: {} });
|
const response = await client2.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(response).toBeDefined();
|
expect(response).toBeDefined();
|
||||||
|
|
||||||
await client2.close();
|
await client2.close();
|
||||||
@@ -299,7 +299,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client.connect(clientTransport);
|
await client.connect(clientTransport);
|
||||||
|
|
||||||
// Quick operation
|
// Quick operation
|
||||||
const response = await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
const response = await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(response).toBeDefined();
|
expect(response).toBeDefined();
|
||||||
|
|
||||||
// Explicit cleanup for each iteration
|
// Explicit cleanup for each iteration
|
||||||
@@ -392,7 +392,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
|
|
||||||
// Light operation
|
// Light operation
|
||||||
if (i % 10 === 0) {
|
if (i % 10 === 0) {
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicit cleanup
|
// Explicit cleanup
|
||||||
@@ -420,8 +420,8 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
for (let i = 0; i < requestCount; i++) {
|
for (let i = 0; i < requestCount; i++) {
|
||||||
const toolName = i % 2 === 0 ? 'list_nodes' : 'get_database_statistics';
|
const toolName = i % 2 === 0 ? 'search_nodes' : 'tools_documentation';
|
||||||
const params = toolName === 'list_nodes' ? { limit: 1 } : {};
|
const params = toolName === 'search_nodes' ? { query: 'http', limit: 1 } : {};
|
||||||
promises.push(client.callTool({ name: toolName as any, arguments: params }));
|
promises.push(client.callTool({ name: toolName as any, arguments: params }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Session should still be active
|
// Session should still be active
|
||||||
const response = await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
const response = await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(response).toBeDefined();
|
expect(response).toBeDefined();
|
||||||
|
|
||||||
await client.close();
|
await client.close();
|
||||||
@@ -496,7 +496,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Session should still work
|
// Session should still work
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: { limit: 1 } });
|
const response = await client.callTool({ name: 'search_nodes', arguments: { query: 'http', limit: 1 } });
|
||||||
expect(response).toBeDefined();
|
expect(response).toBeDefined();
|
||||||
|
|
||||||
await client.close();
|
await client.close();
|
||||||
@@ -539,7 +539,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
resources.clients.push(client);
|
resources.clients.push(client);
|
||||||
|
|
||||||
// Make a request to ensure connection is active
|
// Make a request to ensure connection is active
|
||||||
await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify all resources are active
|
// Verify all resources are active
|
||||||
@@ -586,7 +586,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
// 3. Verify cleanup by attempting operations (should fail)
|
// 3. Verify cleanup by attempting operations (should fail)
|
||||||
for (let i = 0; i < resources.clients.length; i++) {
|
for (let i = 0; i < resources.clients.length; i++) {
|
||||||
try {
|
try {
|
||||||
await resources.clients[i].callTool({ name: 'get_database_statistics', arguments: {} });
|
await resources.clients[i].callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect.fail('Client should be closed');
|
expect.fail('Client should be closed');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Expected - client is closed
|
// Expected - client is closed
|
||||||
@@ -645,7 +645,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
await client.connect(ct1);
|
await client.connect(ct1);
|
||||||
|
|
||||||
// Initial request
|
// Initial request
|
||||||
const response1 = await client.callTool({ name: 'get_database_statistics', arguments: {} });
|
const response1 = await client.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
expect(response1).toBeDefined();
|
expect(response1).toBeDefined();
|
||||||
|
|
||||||
// Close first client
|
// Close first client
|
||||||
@@ -680,7 +680,7 @@ describe('MCP Session Management', { timeout: 15000 }, () => {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response2 = await newClient.callTool({ name: 'get_database_statistics', arguments: {} });
|
const response2 = await newClient.callTool({ name: 'tools_documentation', arguments: {} });
|
||||||
clearTimeout(callTimeout);
|
clearTimeout(callTimeout);
|
||||||
expect(response2).toBeDefined();
|
expect(response2).toBeDefined();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export class TestableN8NMCPServer {
|
|||||||
// The MCP server initializes its database lazily
|
// The MCP server initializes its database lazily
|
||||||
// We can trigger initialization by calling executeTool
|
// We can trigger initialization by calling executeTool
|
||||||
try {
|
try {
|
||||||
await this.mcpServer.executeTool('get_database_statistics', {});
|
await this.mcpServer.executeTool('tools_documentation', {});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore errors, we just want to trigger initialization
|
// Ignore errors, we just want to trigger initialization
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,66 +30,6 @@ describe('MCP Tool Invocation', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Node Discovery Tools', () => {
|
describe('Node Discovery Tools', () => {
|
||||||
describe('list_nodes', () => {
|
|
||||||
it('should list nodes with default parameters', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: {} });
|
|
||||||
|
|
||||||
expect((response as any).content).toHaveLength(1);
|
|
||||||
expect((response as any).content[0].type).toBe('text');
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
// The result is an object with nodes array and totalCount
|
|
||||||
expect(result).toHaveProperty('nodes');
|
|
||||||
expect(result).toHaveProperty('totalCount');
|
|
||||||
|
|
||||||
const nodes = result.nodes;
|
|
||||||
expect(Array.isArray(nodes)).toBe(true);
|
|
||||||
expect(nodes.length).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
// Check node structure
|
|
||||||
const firstNode = nodes[0];
|
|
||||||
expect(firstNode).toHaveProperty('nodeType');
|
|
||||||
expect(firstNode).toHaveProperty('displayName');
|
|
||||||
expect(firstNode).toHaveProperty('category');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter nodes by category', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: {
|
|
||||||
category: 'trigger'
|
|
||||||
}});
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
const nodes = result.nodes;
|
|
||||||
expect(nodes.length).toBeGreaterThan(0);
|
|
||||||
nodes.forEach((node: any) => {
|
|
||||||
expect(node.category).toBe('trigger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should limit results', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: {
|
|
||||||
limit: 5
|
|
||||||
}});
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
const nodes = result.nodes;
|
|
||||||
expect(nodes).toHaveLength(5);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter by package', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_nodes', arguments: {
|
|
||||||
package: 'n8n-nodes-base'
|
|
||||||
}});
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
const nodes = result.nodes;
|
|
||||||
expect(nodes.length).toBeGreaterThan(0);
|
|
||||||
nodes.forEach((node: any) => {
|
|
||||||
expect(node.package).toBe('n8n-nodes-base');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('search_nodes', () => {
|
describe('search_nodes', () => {
|
||||||
it('should search nodes by keyword', async () => {
|
it('should search nodes by keyword', async () => {
|
||||||
const response = await client.callTool({ name: 'search_nodes', arguments: {
|
const response = await client.callTool({ name: 'search_nodes', arguments: {
|
||||||
@@ -427,85 +367,8 @@ describe('MCP Tool Invocation', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AI Tools', () => {
|
// AI Tools section removed - list_ai_tools and get_node_as_tool_info were removed in v2.25.0
|
||||||
describe('list_ai_tools', () => {
|
// Use search_nodes with query for finding AI-capable nodes
|
||||||
it('should list AI-capable nodes', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_ai_tools', arguments: {} });
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
expect(result).toHaveProperty('tools');
|
|
||||||
const aiTools = result.tools;
|
|
||||||
expect(Array.isArray(aiTools)).toBe(true);
|
|
||||||
expect(aiTools.length).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
// All should have nodeType and displayName
|
|
||||||
aiTools.forEach((tool: any) => {
|
|
||||||
expect(tool).toHaveProperty('nodeType');
|
|
||||||
expect(tool).toHaveProperty('displayName');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('get_node_as_tool_info', () => {
|
|
||||||
it('should provide AI tool usage information', async () => {
|
|
||||||
const response = await client.callTool({ name: 'get_node_as_tool_info', arguments: {
|
|
||||||
nodeType: 'nodes-base.slack'
|
|
||||||
}});
|
|
||||||
|
|
||||||
const info = JSON.parse(((response as any).content[0]).text);
|
|
||||||
expect(info).toHaveProperty('nodeType');
|
|
||||||
expect(info).toHaveProperty('isMarkedAsAITool');
|
|
||||||
expect(info).toHaveProperty('aiToolCapabilities');
|
|
||||||
expect(info.aiToolCapabilities).toHaveProperty('commonUseCases');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Task Templates', () => {
|
|
||||||
// get_node_for_task was removed in v2.15.0
|
|
||||||
// Use search_nodes({ includeExamples: true }) instead for real-world examples
|
|
||||||
|
|
||||||
describe('list_tasks', () => {
|
|
||||||
it('should list all available tasks', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_tasks', arguments: {} });
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
expect(result).toHaveProperty('totalTasks');
|
|
||||||
expect(result).toHaveProperty('categories');
|
|
||||||
expect(result.totalTasks).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
// Check categories structure
|
|
||||||
const categories = result.categories;
|
|
||||||
expect(typeof categories).toBe('object');
|
|
||||||
|
|
||||||
// Check at least one category has tasks
|
|
||||||
const hasTasksInCategories = Object.values(categories).some((tasks: any) =>
|
|
||||||
Array.isArray(tasks) && tasks.length > 0
|
|
||||||
);
|
|
||||||
expect(hasTasksInCategories).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter by category', async () => {
|
|
||||||
const response = await client.callTool({ name: 'list_tasks', arguments: {
|
|
||||||
category: 'HTTP/API'
|
|
||||||
}});
|
|
||||||
|
|
||||||
const result = JSON.parse(((response as any).content[0]).text);
|
|
||||||
expect(result).toHaveProperty('category', 'HTTP/API');
|
|
||||||
expect(result).toHaveProperty('tasks');
|
|
||||||
|
|
||||||
const httpTasks = result.tasks;
|
|
||||||
expect(Array.isArray(httpTasks)).toBe(true);
|
|
||||||
expect(httpTasks.length).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
httpTasks.forEach((task: any) => {
|
|
||||||
expect(task).toHaveProperty('task');
|
|
||||||
expect(task).toHaveProperty('description');
|
|
||||||
expect(task).toHaveProperty('nodeType');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Complex Tool Interactions', () => {
|
describe('Complex Tool Interactions', () => {
|
||||||
it('should handle tool chaining', async () => {
|
it('should handle tool chaining', async () => {
|
||||||
@@ -526,20 +389,20 @@ describe('MCP Tool Invocation', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle parallel tool calls', async () => {
|
it('should handle parallel tool calls', async () => {
|
||||||
const tools = [
|
const toolCalls = [
|
||||||
'list_nodes',
|
{ name: 'search_nodes', arguments: { query: 'http' } },
|
||||||
'get_database_statistics',
|
{ name: 'tools_documentation', arguments: {} },
|
||||||
'list_ai_tools',
|
{ name: 'get_node', arguments: { nodeType: 'nodes-base.httpRequest' } },
|
||||||
'list_tasks'
|
{ name: 'search_nodes', arguments: { query: 'webhook' } }
|
||||||
];
|
];
|
||||||
|
|
||||||
const promises = tools.map(tool =>
|
const promises = toolCalls.map(call =>
|
||||||
client.callTool({ name: tool as any, arguments: {} })
|
client.callTool(call)
|
||||||
);
|
);
|
||||||
|
|
||||||
const responses = await Promise.all(promises);
|
const responses = await Promise.all(promises);
|
||||||
|
|
||||||
expect(responses).toHaveLength(tools.length);
|
expect(responses).toHaveLength(toolCalls.length);
|
||||||
responses.forEach(response => {
|
responses.forEach(response => {
|
||||||
expect(response.content).toHaveLength(1);
|
expect(response.content).toHaveLength(1);
|
||||||
expect(((response as any).content[0]).type).toBe('text');
|
expect(((response as any).content[0]).type).toBe('text');
|
||||||
|
|||||||
@@ -500,15 +500,15 @@ describe.skip('MCP Telemetry Integration', () => {
|
|||||||
const slowToolRequest: CallToolRequest = {
|
const slowToolRequest: CallToolRequest = {
|
||||||
method: 'tools/call',
|
method: 'tools/call',
|
||||||
params: {
|
params: {
|
||||||
name: 'list_nodes',
|
name: 'search_nodes',
|
||||||
arguments: { limit: 1000 }
|
arguments: { query: 'http', limit: 1000 }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mock a slow operation
|
// Mock a slow operation
|
||||||
vi.spyOn(mcpServer as any, 'executeTool').mockImplementation(async () => {
|
vi.spyOn(mcpServer as any, 'executeTool').mockImplementation(async () => {
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay
|
await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay
|
||||||
return { nodes: [], totalCount: 0 };
|
return { results: [], totalCount: 0 };
|
||||||
});
|
});
|
||||||
|
|
||||||
const server = (mcpServer as any).server;
|
const server = (mcpServer as any).server;
|
||||||
@@ -519,7 +519,7 @@ describe.skip('MCP Telemetry Integration', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(telemetry.trackToolUsage).toHaveBeenCalledWith(
|
expect(telemetry.trackToolUsage).toHaveBeenCalledWith(
|
||||||
'list_nodes',
|
'search_nodes',
|
||||||
true,
|
true,
|
||||||
expect.any(Number)
|
expect.any(Number)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -73,14 +73,14 @@ describe('Disabled Tools Feature (Issue #410)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should parse multiple disabled tools correctly', () => {
|
it('should parse multiple disabled tools correctly', () => {
|
||||||
process.env.DISABLED_TOOLS = 'n8n_diagnostic,n8n_health_check,list_nodes';
|
process.env.DISABLED_TOOLS = 'n8n_diagnostic,n8n_health_check,search_nodes';
|
||||||
server = new TestableN8NMCPServer();
|
server = new TestableN8NMCPServer();
|
||||||
const disabledTools = server.testGetDisabledTools();
|
const disabledTools = server.testGetDisabledTools();
|
||||||
|
|
||||||
expect(disabledTools.size).toBe(3);
|
expect(disabledTools.size).toBe(3);
|
||||||
expect(disabledTools.has('n8n_diagnostic')).toBe(true);
|
expect(disabledTools.has('n8n_diagnostic')).toBe(true);
|
||||||
expect(disabledTools.has('n8n_health_check')).toBe(true);
|
expect(disabledTools.has('n8n_health_check')).toBe(true);
|
||||||
expect(disabledTools.has('list_nodes')).toBe(true);
|
expect(disabledTools.has('search_nodes')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should trim whitespace from tool names', () => {
|
it('should trim whitespace from tool names', () => {
|
||||||
@@ -94,14 +94,14 @@ describe('Disabled Tools Feature (Issue #410)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should filter out empty entries from comma-separated list', () => {
|
it('should filter out empty entries from comma-separated list', () => {
|
||||||
process.env.DISABLED_TOOLS = 'n8n_diagnostic,,n8n_health_check,,,list_nodes';
|
process.env.DISABLED_TOOLS = 'n8n_diagnostic,,n8n_health_check,,,search_nodes';
|
||||||
server = new TestableN8NMCPServer();
|
server = new TestableN8NMCPServer();
|
||||||
const disabledTools = server.testGetDisabledTools();
|
const disabledTools = server.testGetDisabledTools();
|
||||||
|
|
||||||
expect(disabledTools.size).toBe(3);
|
expect(disabledTools.size).toBe(3);
|
||||||
expect(disabledTools.has('n8n_diagnostic')).toBe(true);
|
expect(disabledTools.has('n8n_diagnostic')).toBe(true);
|
||||||
expect(disabledTools.has('n8n_health_check')).toBe(true);
|
expect(disabledTools.has('n8n_health_check')).toBe(true);
|
||||||
expect(disabledTools.has('list_nodes')).toBe(true);
|
expect(disabledTools.has('search_nodes')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle single comma correctly', () => {
|
it('should handle single comma correctly', () => {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ vi.mock('@/mcp/tool-docs', () => ({
|
|||||||
performance: 'Instant - uses in-memory index',
|
performance: 'Instant - uses in-memory index',
|
||||||
bestPractices: ['Start with single words', 'Use FUZZY for uncertain names'],
|
bestPractices: ['Start with single words', 'Use FUZZY for uncertain names'],
|
||||||
pitfalls: ['Overly specific queries may return no results'],
|
pitfalls: ['Overly specific queries may return no results'],
|
||||||
relatedTools: ['list_nodes', 'get_node_info']
|
relatedTools: ['get_node', 'get_node_documentation']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
validate_workflow: {
|
validate_workflow: {
|
||||||
@@ -172,7 +172,7 @@ describe('tools-documentation', () => {
|
|||||||
expect(doc).toContain('## Common Pitfalls');
|
expect(doc).toContain('## Common Pitfalls');
|
||||||
expect(doc).toContain('- Overly specific queries');
|
expect(doc).toContain('- Overly specific queries');
|
||||||
expect(doc).toContain('## Related Tools');
|
expect(doc).toContain('## Related Tools');
|
||||||
expect(doc).toContain('- list_nodes');
|
expect(doc).toContain('- get_node');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user