Skip to main content
Glama

Knowledge MCP Server

by sven-borkert
08-todo.test.tsโ€ข17.7 kB
#!/usr/bin/env tsx import { homedir } from 'os'; import { resolve, join } from 'path'; import { MCPTestClient } from '../utils/test-client.js'; import { TestRunner, assertSuccess, assertFailure, assertEqual, assertArrayLength, setupTestEnvironment, cleanupTestEnvironment, generateTestProjectId, setCurrentRunner, } from '../utils/test-helpers.js'; // Test configuration const TEST_STORAGE_PATH = resolve(join(homedir(), '.knowledge-mcp-test-todo')); const SERVER_PATH = resolve('./dist/knowledge-mcp/index.js'); async function main(): Promise<void> { const runner = new TestRunner(); const client = new MCPTestClient({ serverPath: SERVER_PATH, storagePath: TEST_STORAGE_PATH, }); // Setup setupTestEnvironment(TEST_STORAGE_PATH); await client.connect(); client.setTestRunner(runner); try { runner.setSuite('TODO Management System', 'Task Management'); runner.enableDetailedTracking(); setCurrentRunner(runner); await runner.runTest('list_todos: Empty project', async () => { const projectId = generateTestProjectId('todo-empty'); const result = await client.callToolAndParse('list_todos', { project_id: projectId, }); assertSuccess(result); assertArrayLength(result.todos as any[], 0); }); await runner.runTest('create_todo: Basic TODO creation', async () => { const projectId = generateTestProjectId('todo-create'); const result = await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Implement authentication system', }); assertSuccess(result); assertEqual(result.todo_number, 1); assertEqual(result.message, 'Created TODO #1'); }); await runner.runTest('create_todo: With initial tasks', async () => { const projectId = generateTestProjectId('todo-tasks'); const result = await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Build user interface', tasks: [ { title: 'Design mockups', content: 'Create wireframes and visual designs for the UI' }, { title: 'Create components', content: 'Build React components based on the designs' }, { title: 'Add styling', content: 'Implement CSS styles and responsive design' }, { title: 'Write tests', content: 'Add unit and integration tests for components' }, ], }); assertSuccess(result); assertEqual(result.todo_number, 1); // Verify tasks were created const tasksResult = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); assertSuccess(tasksResult); assertArrayLength(tasksResult.tasks as any[], 4); }); await runner.runTest('list_todos: Multiple TODOs', async () => { const projectId = generateTestProjectId('todo-list'); // Create multiple TODOs for (let i = 1; i <= 3; i++) { await client.callToolAndParse('create_todo', { project_id: projectId, description: `TODO ${i}`, tasks: [ { title: `Task ${i}-1`, content: `Description for task ${i}-1` }, { title: `Task ${i}-2`, content: `Description for task ${i}-2` }, ], }); } const result = await client.callToolAndParse('list_todos', { project_id: projectId, }); assertSuccess(result); const todos = result.todos as any[]; assertArrayLength(todos, 3); // Check ordering (should be in creation order) assertEqual(todos[0].number, 1); assertEqual(todos[1].number, 2); assertEqual(todos[2].number, 3); // Check completion status todos.forEach((todo: any) => { assertEqual(todo.completed_count, 0); assertEqual(todo.task_count, 2); }); }); await runner.runTest('get_todo_tasks: Retrieve tasks', async () => { const projectId = generateTestProjectId('todo-get'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'API Development', tasks: [ { title: 'Design API schema', content: 'Define REST API endpoints and data structures' }, { title: 'Implement endpoints', content: 'Build API endpoints with proper error handling', }, { title: 'Add authentication', content: 'Implement JWT-based authentication system' }, { title: 'Write documentation', content: 'Create API documentation with examples' }, ], }); const result = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); assertSuccess(result); const todo = result.todo as any; assertEqual(todo.number, 1); assertEqual(todo.description, 'API Development'); const tasks = result.tasks as any[]; assertArrayLength(tasks, 4); // Check task structure tasks.forEach((task: any, index: number) => { assertEqual(task.number, index + 1); assertEqual(task.completed, false); }); }); await runner.runTest('add_todo_task: Add task to existing TODO', async () => { const projectId = generateTestProjectId('todo-add-task'); // Create TODO with some tasks await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Feature Development', tasks: [ { title: 'Task 1', content: 'First task description' }, { title: 'Task 2', content: 'Second task description' }, ], }); // Add a new task const result = await client.callToolAndParse('add_todo_task', { project_id: projectId, todo_number: 1, title: 'Task 3 - newly added', content: 'This is the third task added dynamically', }); assertSuccess(result); assertEqual(result.task_number, 3); // Verify task was added const tasksResult = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); assertArrayLength(tasksResult.tasks as any[], 3); const tasks = tasksResult.tasks as any[]; assertEqual(tasks[2].description, 'Task 3 - newly added'); }); await runner.runTest('complete_todo_task: Mark task as completed', async () => { const projectId = generateTestProjectId('todo-complete'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Testing Tasks', tasks: [ { title: 'Write unit tests', content: 'Create unit tests for individual functions' }, { title: 'Write integration tests', content: 'Test component interactions and API calls', }, { title: 'Run test suite', content: 'Execute all tests and ensure 100% pass rate' }, ], }); // Complete the second task const result = await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 2, }); assertSuccess(result); // Verify completion const tasksResult = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); const tasks = tasksResult.tasks as any[]; assertEqual(tasks[0].completed, false); assertEqual(tasks[1].completed, true); assertEqual(tasks[2].completed, false); // Check TODO completion count const listResult = await client.callToolAndParse('list_todos', { project_id: projectId, }); const todo = (listResult.todos as any[])[0]; assertEqual(todo.completed_count, 1); assertEqual(todo.task_count, 3); }); await runner.runTest('get_next_todo_task: Get next incomplete task', async () => { const projectId = generateTestProjectId('todo-next'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Sequential Tasks', tasks: [ { title: 'First task', content: 'Complete the initial setup' }, { title: 'Second task', content: 'Implement core functionality' }, { title: 'Third task', content: 'Add finishing touches' }, ], }); // Initially should get first task let result = await client.callToolAndParse('get_next_todo_task', { project_id: projectId, todo_number: 1, }); assertSuccess(result); const task = result.task as any; assertEqual(task?.number, 1); assertEqual(task?.description, 'First task'); // Complete first task await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 1, }); // Now should get second task result = await client.callToolAndParse('get_next_todo_task', { project_id: projectId, todo_number: 1, }); const nextTask = result.task as any; assertEqual(nextTask?.number, 2); assertEqual(nextTask?.description, 'Second task'); }); await runner.runTest('get_next_todo_task: All tasks completed', async () => { const projectId = generateTestProjectId('todo-all-complete'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Completed TODO', tasks: [ { title: 'Task 1', content: 'First task description' }, { title: 'Task 2', content: 'Second task description' }, ], }); // Complete all tasks await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 1, }); await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 2, }); // Should return no task const result = await client.callToolAndParse('get_next_todo_task', { project_id: projectId, todo_number: 1, }); assertSuccess(result); assertEqual(result.task, undefined); assertEqual(result.message, 'All tasks completed'); }); await runner.runTest('remove_todo_task: Remove existing task', async () => { const projectId = generateTestProjectId('todo-remove'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Task Removal Test', tasks: [ { title: 'Keep this', content: 'This task should remain' }, { title: 'Remove this', content: 'This task will be removed' }, { title: 'Keep this too', content: 'This task should also remain' }, ], }); // Remove the middle task const result = await client.callToolAndParse('remove_todo_task', { project_id: projectId, todo_number: 1, task_number: 2, }); assertSuccess(result); // Verify removal const tasksResult = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); const tasks = tasksResult.tasks as any[]; assertArrayLength(tasks, 2); assertEqual(tasks[0].description, 'Keep this'); assertEqual(tasks[1].description, 'Keep this too'); }); await runner.runTest('delete_todo: Delete entire TODO', async () => { const projectId = generateTestProjectId('todo-delete'); // Create multiple TODOs for (let i = 1; i <= 3; i++) { await client.callToolAndParse('create_todo', { project_id: projectId, description: `TODO ${i}`, }); } // Delete the middle one const result = await client.callToolAndParse('delete_todo', { project_id: projectId, todo_number: 2, }); assertSuccess(result); // Verify deletion const listResult = await client.callToolAndParse('list_todos', { project_id: projectId, }); const todos = listResult.todos as any[]; assertArrayLength(todos, 2); // Remaining TODOs should keep their numbers assertEqual(todos[0].number, 1); assertEqual(todos[1].number, 3); }); await runner.runTest('TODO operations: Non-existent TODO', async () => { const projectId = generateTestProjectId('todo-nonexistent'); // Try operations on non-existent TODO const getResult = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 999, }); assertFailure(getResult); const addResult = await client.callToolAndParse('add_todo_task', { project_id: projectId, todo_number: 999, title: 'Task', content: 'This should fail as TODO does not exist', }); assertFailure(addResult); const deleteResult = await client.callToolAndParse('delete_todo', { project_id: projectId, todo_number: 999, }); assertFailure(deleteResult); }); await runner.runTest('TODO operations: Non-existent task', async () => { const projectId = generateTestProjectId('todo-bad-task'); await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Test TODO', tasks: [ { title: 'Task 1', content: 'First task description' }, { title: 'Task 2', content: 'Second task description' }, ], }); // Try operations on non-existent task const completeResult = await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 999, }); assertFailure(completeResult); const removeResult = await client.callToolAndParse('remove_todo_task', { project_id: projectId, todo_number: 1, task_number: 999, }); assertFailure(removeResult); }); await runner.runTest('TODO persistence: Complex workflow', async () => { const projectId = generateTestProjectId('todo-workflow'); // Create TODO for a feature implementation await client.callToolAndParse('create_todo', { project_id: projectId, description: 'Implement user authentication', tasks: [ { title: 'Design database schema', content: 'Create ERD and define table structures' }, { title: 'Create user model', content: 'Implement User model with validation' }, { title: 'Implement registration endpoint', content: 'Build POST /api/register endpoint', }, { title: 'Implement login endpoint', content: 'Build POST /api/login endpoint with JWT' }, { title: 'Add password hashing', content: 'Implement bcrypt for secure password storage', }, { title: 'Create JWT token generation', content: 'Implement JWT token creation and validation', }, { title: 'Write tests', content: 'Add comprehensive test coverage for auth endpoints' }, ], }); // Simulate working through tasks await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 1, }); await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 2, }); // Add a new task in the middle await client.callToolAndParse('add_todo_task', { project_id: projectId, todo_number: 1, title: 'Add email validation', content: 'Implement email format validation for user registration', }); // Complete more tasks await client.callToolAndParse('complete_todo_task', { project_id: projectId, todo_number: 1, task_number: 3, }); // Check final state const result = await client.callToolAndParse('get_todo_tasks', { project_id: projectId, todo_number: 1, }); // const _todo = result.todo as any; // Unused but available in result const tasks = result.tasks as any[]; assertArrayLength(tasks, 8); // 7 original + 1 added // Count completed const completed = tasks.filter((t: any) => t.completed).length; assertEqual(completed, 3); // Verify TODO summary const listResult = await client.callToolAndParse('list_todos', { project_id: projectId, }); const todoSummary = (listResult.todos as any[])[0]; assertEqual(todoSummary.completed_count, 3); assertEqual(todoSummary.task_count, 8); }); } finally { await client.disconnect(); cleanupTestEnvironment(TEST_STORAGE_PATH); // Export detailed results for HTML reporting const detailedSuiteResult = runner.getDetailedSuiteResult(); if (process.env.EXPORT_DETAILED_RESULTS) { const { writeFileSync, mkdirSync } = await import('fs'); const path = await import('path'); const resultsDir = path.resolve('./test-results/detailed-suites'); mkdirSync(resultsDir, { recursive: true }); const resultPath = path.resolve(resultsDir, '08-todo.json'); writeFileSync(resultPath, JSON.stringify(detailedSuiteResult, null, 2)); } runner.printSummary(); runner.exitWithResults(); } } // Run tests if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error: Error) => { console.error('๐Ÿ’ฅ Test execution failed:', error); process.exit(1); }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sven-borkert/knowledge-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server