Skip to main content
Glama
callToolHandler.test.ts12.1 kB
/** * Test file for the callToolHandler module * Migrated from Jest to Vitest and converted to TypeScript */ import { describe, test, expect, beforeEach, vi } from 'vitest'; import { handleCallToolRequest } from '../callToolHandler.js'; // Define types for the knowledge graph manager interface KnowledgeGraphManager { readGraph: ReturnType<typeof vi.fn>; createEntities: ReturnType<typeof vi.fn>; createRelations: ReturnType<typeof vi.fn>; addObservations: ReturnType<typeof vi.fn>; deleteEntities: ReturnType<typeof vi.fn>; deleteObservations: ReturnType<typeof vi.fn>; deleteRelations: ReturnType<typeof vi.fn>; getRelation: ReturnType<typeof vi.fn>; updateRelation: ReturnType<typeof vi.fn>; searchNodes: ReturnType<typeof vi.fn>; openNodes: ReturnType<typeof vi.fn>; getEntityHistory?: ReturnType<typeof vi.fn>; } // Instead of mocking the tool handler, we mock how it's used inside callToolHandler // by mocking the original knowledge graph manager calls describe('handleCallToolRequest', () => { let mockKnowledgeGraphManager: KnowledgeGraphManager; beforeEach(() => { // Reset all mocks vi.clearAllMocks(); // Create a mock KnowledgeGraphManager with all required methods mockKnowledgeGraphManager = { readGraph: vi.fn().mockResolvedValue({ entities: [], relations: [] }), createEntities: vi.fn().mockResolvedValue({ success: true }), createRelations: vi.fn().mockResolvedValue({ success: true }), addObservations: vi.fn().mockResolvedValue({ success: true }), deleteEntities: vi.fn().mockResolvedValue(undefined), deleteObservations: vi.fn().mockResolvedValue(undefined), deleteRelations: vi.fn().mockResolvedValue(undefined), getRelation: vi .fn() .mockResolvedValue({ from: 'Entity1', to: 'Entity2', relationType: 'KNOWS' }), updateRelation: vi.fn().mockResolvedValue(undefined), searchNodes: vi.fn().mockResolvedValue([]), openNodes: vi.fn().mockResolvedValue([]), }; }); test('should throw an error if no arguments are provided', async () => { // Arrange const request = { params: { name: 'read_graph', arguments: undefined, }, }; // Act & Assert await expect(handleCallToolRequest(request, mockKnowledgeGraphManager)).rejects.toThrow( 'No arguments provided for tool: read_graph' ); }); test('should throw an error for unknown tool', async () => { // Arrange const request = { params: { name: 'unknown_tool', arguments: {}, }, }; // Act & Assert await expect(handleCallToolRequest(request, mockKnowledgeGraphManager)).rejects.toThrow( 'Unknown tool: unknown_tool' ); }); test('should call readGraph and return formatted results for read_graph tool', async () => { // Arrange const request = { params: { name: 'read_graph', arguments: {}, }, }; const graphData = { entities: [{ name: 'Entity1' }], relations: [] }; mockKnowledgeGraphManager.readGraph.mockResolvedValue(graphData); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.readGraph).toHaveBeenCalled(); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify(graphData, null, 2), }, ], }); }); test('should call deleteEntities and return success message for delete_entities tool', async () => { // Arrange const entityNames = ['Entity1', 'Entity2']; const request = { params: { name: 'delete_entities', arguments: { entityNames, }, }, }; // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.deleteEntities).toHaveBeenCalledWith(entityNames); expect(result).toEqual({ content: [ { type: 'text', text: 'Entities deleted successfully', }, ], }); }); test('should call createRelations and return formatted results for create_relations tool', async () => { // Arrange const relations = [{ from: 'Entity1', to: 'Entity2', relationType: 'KNOWS' }]; const request = { params: { name: 'create_relations', arguments: { relations, }, }, }; const createResult = { success: true, count: 1 }; mockKnowledgeGraphManager.createRelations.mockResolvedValue(createResult); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.createRelations).toHaveBeenCalledWith(relations); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify(createResult, null, 2), }, ], }); }); test('should call addObservations and return formatted results for add_observations tool', async () => { // Arrange const observations = [{ entityName: 'Entity1', contents: ['New observation'] }]; const request = { params: { name: 'add_observations', arguments: { observations, }, }, }; const addResult = { success: true, count: 1 }; mockKnowledgeGraphManager.addObservations.mockResolvedValue(addResult); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.addObservations).toHaveBeenCalledWith([ { entityName: 'Entity1', contents: ['New observation'], strength: 0.9, confidence: 0.95, metadata: { source: 'API call' }, }, ]); // Verify content type is correct expect(result.content[0].type).toEqual('text'); // Parse the JSON response const responseObj = JSON.parse(result.content[0].text); // Verify response contains correct result data expect(responseObj.result).toEqual(addResult); // Verify debug information is present expect(responseObj.debug).toBeDefined(); expect(responseObj.debug.timestamp).toBeDefined(); expect(responseObj.debug.input_args).toBeDefined(); expect(responseObj.debug.processed_observations).toBeInstanceOf(Array); expect(responseObj.debug.tool_version).toBeDefined(); }); test('should call deleteObservations and return success message for delete_observations tool', async () => { // Arrange const deletions = [{ entityName: 'Entity1', observations: ['Observation to delete'] }]; const request = { params: { name: 'delete_observations', arguments: { deletions, }, }, }; // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.deleteObservations).toHaveBeenCalledWith(deletions); expect(result).toEqual({ content: [ { type: 'text', text: 'Observations deleted successfully', }, ], }); }); test('should call deleteRelations and return success message for delete_relations tool', async () => { // Arrange const relations = [{ from: 'Entity1', to: 'Entity2', relationType: 'KNOWS' }]; const request = { params: { name: 'delete_relations', arguments: { relations, }, }, }; // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.deleteRelations).toHaveBeenCalledWith(relations); expect(result).toEqual({ content: [ { type: 'text', text: 'Relations deleted successfully', }, ], }); }); test('should call getRelation and return formatted result for get_relation tool', async () => { // Arrange const relationArgs = { from: 'Entity1', to: 'Entity2', relationType: 'KNOWS', }; const request = { params: { name: 'get_relation', arguments: relationArgs, }, }; const relation = { from: 'Entity1', to: 'Entity2', relationType: 'KNOWS', strength: 0.8, }; mockKnowledgeGraphManager.getRelation.mockResolvedValue(relation); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.getRelation).toHaveBeenCalledWith( relationArgs.from, relationArgs.to, relationArgs.relationType ); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify(relation, null, 2), }, ], }); }); test('should handle case when relation is not found for get_relation tool', async () => { // Arrange const relationArgs = { from: 'Entity1', to: 'Entity2', relationType: 'KNOWS', }; const request = { params: { name: 'get_relation', arguments: relationArgs, }, }; // Mock relation not found mockKnowledgeGraphManager.getRelation.mockResolvedValue(null); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.getRelation).toHaveBeenCalledWith( relationArgs.from, relationArgs.to, relationArgs.relationType ); expect(result).toEqual({ content: [ { type: 'text', text: `Relation not found: ${relationArgs.from} -> ${relationArgs.relationType} -> ${relationArgs.to}`, }, ], }); }); test('should call updateRelation and return success message for update_relation tool', async () => { // Arrange const relation = { from: 'Entity1', to: 'Entity2', relationType: 'KNOWS', strength: 0.9, }; const request = { params: { name: 'update_relation', arguments: { relation, }, }, }; // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.updateRelation).toHaveBeenCalledWith(relation); expect(result).toEqual({ content: [ { type: 'text', text: 'Relation updated successfully', }, ], }); }); test('should call searchNodes and return formatted results for search_nodes tool', async () => { // Arrange const query = 'test query'; const request = { params: { name: 'search_nodes', arguments: { query, }, }, }; const searchResults = [{ name: 'Entity1', relevance: 0.9 }]; mockKnowledgeGraphManager.searchNodes.mockResolvedValue(searchResults); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.searchNodes).toHaveBeenCalledWith(query); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify(searchResults, null, 2), }, ], }); }); test('should call openNodes and return formatted results for open_nodes tool', async () => { // Arrange const names = ['Entity1', 'Entity2']; const request = { params: { name: 'open_nodes', arguments: { names, }, }, }; const openResults = [{ name: 'Entity1', observations: ['Observation 1'] }]; mockKnowledgeGraphManager.openNodes.mockResolvedValue(openResults); // Act const result = await handleCallToolRequest(request, mockKnowledgeGraphManager); // Assert expect(mockKnowledgeGraphManager.openNodes).toHaveBeenCalledWith(names); expect(result).toEqual({ content: [ { type: 'text', text: JSON.stringify(openResults, null, 2), }, ], }); }); });

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/gannonh/memento-mcp'

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