Skip to main content
Glama
update-knowledge-tool.test.ts9.38 kB
/** * Tests for Update Knowledge Tool */ import { describe, it, expect, _beforeEach, _jest } from 'vitest'; import { updateKnowledge, type UpdateKnowledgeArgs, } from '../../src/tools/update-knowledge-tool.js'; import { KnowledgeGraphManager } from '../../src/utils/knowledge-graph-manager.js'; import type { KnowledgeGraphSnapshot } from '../../src/types/knowledge-graph-schemas.js'; import { createNoOpContext } from '../../src/types/tool-context.js'; describe('Update Knowledge Tool', () => { let mockKgManager: KnowledgeGraphManager; let mockSnapshot: KnowledgeGraphSnapshot; let ctx: ReturnType<typeof createNoOpContext>; beforeEach(() => { ctx = createNoOpContext(); // Create mock knowledge graph snapshot mockSnapshot = { version: '1.0.0', timestamp: '2025-12-16T13:00:00.000Z', intents: [ { intentId: 'intent-1', humanRequest: 'Test intent', parsedGoals: ['Goal 1'], priority: 'medium' as const, timestamp: '2025-12-16T12:00:00.000Z', toolChain: [ { toolName: 'test_tool', parameters: {}, result: {}, todoTasksCreated: [], todoTasksModified: [], executionTime: '2025-12-16T12:05:00.000Z', success: true, }, ], currentStatus: 'completed' as const, todoMdSnapshot: '', }, ], todoSyncState: { lastSyncTimestamp: '2025-12-16T13:00:00.000Z', todoMdHash: 'abc123', knowledgeGraphHash: 'def456', syncStatus: 'synced' as const, lastModifiedBy: 'tool' as const, version: 1, }, analytics: { totalIntents: 1, completedIntents: 1, activeIntents: 0, averageGoalCompletion: 1, mostUsedTools: [], successfulPatterns: [], }, }; // Create mock KnowledgeGraphManager mockKgManager = { loadKnowledgeGraph: vi.fn().mockResolvedValue(mockSnapshot), saveKnowledgeGraph: vi.fn().mockResolvedValue(undefined), createIntent: vi.fn().mockResolvedValue('new-intent-id'), } as any; }); describe('add_entity operation', () => { it('should add a new intent entity', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_entity', entity: 'intent-2', entityType: 'intent', metadata: { title: 'New feature', goals: ['Goal 1', 'Goal 2'], priority: 'high', }, }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe('text'); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(true); expect(response.message).toContain('Successfully executed add_entity'); expect(response.graphState).toBeDefined(); expect(response.graphState.intentCount).toBeGreaterThan(0); // Should have called createIntent expect(mockKgManager.createIntent).toHaveBeenCalledWith( 'New feature', ['Goal 1', 'Goal 2'], 'high' ); }); it('should not add duplicate entity', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_entity', entity: 'intent-1', // Already exists entityType: 'intent', }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.message).toContain('already exists'); }); it('should require entity and entityType parameters', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_entity', // Missing entity and entityType }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.error).toContain('requires entity and entityType'); }); }); describe('remove_entity operation', () => { it('should remove an existing entity', async () => { const args: UpdateKnowledgeArgs = { operation: 'remove_entity', entity: 'intent-1', }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(true); expect(response.message).toContain('Successfully executed remove_entity'); // Should have saved the updated graph expect(mockKgManager.saveKnowledgeGraph).toHaveBeenCalled(); }); it('should fail when entity not found', async () => { const args: UpdateKnowledgeArgs = { operation: 'remove_entity', entity: 'non-existent-intent', }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.message).toContain('not found'); }); it('should require entity parameter', async () => { const args: UpdateKnowledgeArgs = { operation: 'remove_entity', // Missing entity }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.error).toContain('requires entity parameter'); }); }); describe('add_relationship operation', () => { it('should add a relationship between entities', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_relationship', relationship: 'implements', source: 'adr-001', target: 'src/api.ts', }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(true); expect(response.message).toContain('Successfully executed add_relationship'); expect(response.modified).toBe(true); }); it('should require relationship, source, and target parameters', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_relationship', relationship: 'implements', // Missing source and target }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.error).toContain('requires relationship, source, and target'); }); }); describe('remove_relationship operation', () => { it('should remove a relationship between entities', async () => { const args: UpdateKnowledgeArgs = { operation: 'remove_relationship', relationship: 'implements', source: 'adr-001', target: 'src/api.ts', }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(true); expect(response.message).toContain('Successfully executed remove_relationship'); expect(response.modified).toBe(true); }); it('should require relationship, source, and target parameters', async () => { const args: UpdateKnowledgeArgs = { operation: 'remove_relationship', // Missing all required parameters }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.error).toContain('requires relationship, source, and target'); }); }); describe('validation', () => { it('should reject invalid operation', async () => { const args: UpdateKnowledgeArgs = { operation: 'invalid_operation' as any, }; const result = await updateKnowledge(args, ctx, mockKgManager); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text as string); expect(response.success).toBe(false); expect(response.error).toContain('Invalid operation'); }); }); describe('graph summary', () => { it('should return graph summary with counts', async () => { const args: UpdateKnowledgeArgs = { operation: 'add_entity', entity: 'intent-2', entityType: 'intent', metadata: { title: 'Test' }, }; const result = await updateKnowledge(args, ctx, mockKgManager); const response = JSON.parse(result.content[0].text as string); expect(response.graphState).toBeDefined(); expect(response.graphState.nodeCount).toBeDefined(); expect(response.graphState.edgeCount).toBeDefined(); expect(response.graphState.intentCount).toBeDefined(); expect(response.graphState.adrCount).toBeDefined(); expect(response.graphState.lastUpdated).toBeDefined(); }); }); });

Latest Blog Posts

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/tosin2013/mcp-adr-analysis-server'

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