- MCP server cu stdio transport pentru performanță maximă
- Tool-uri pentru file operations, HTTP requests, system commands
- Suport NATS pentru comunicare inter-module
- Configurare nginx cu API key auth și SSL
- Arhitectură modulară și extensibilă
🤖 Generated with Claude Code
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import { ToolRegistry } from '../../src/registry/ToolRegistry';
|
|
import { NatsClient } from '../../src/nats/NatsClient';
|
|
import { ToolDefinition } from '../../src/types';
|
|
|
|
// Mock NatsClient
|
|
jest.mock('../../src/nats/NatsClient');
|
|
|
|
describe('ToolRegistry', () => {
|
|
let registry: ToolRegistry;
|
|
let mockNatsClient: jest.Mocked<NatsClient>;
|
|
|
|
beforeEach(() => {
|
|
mockNatsClient = new NatsClient() as jest.Mocked<NatsClient>;
|
|
mockNatsClient.subscribe = jest.fn();
|
|
mockNatsClient.request = jest.fn();
|
|
|
|
registry = new ToolRegistry(mockNatsClient);
|
|
});
|
|
|
|
describe('registerTool', () => {
|
|
it('should register a tool', () => {
|
|
const tool: ToolDefinition = {
|
|
name: 'test-tool',
|
|
description: 'Test tool',
|
|
inputSchema: { type: 'object' },
|
|
module: 'test-module',
|
|
permissions: [],
|
|
};
|
|
|
|
registry.registerTool(tool);
|
|
|
|
expect(registry.getTool('test-tool')).toEqual(tool);
|
|
});
|
|
});
|
|
|
|
describe('listTools', () => {
|
|
it('should return all registered tools including built-in tools', async () => {
|
|
const tool1: ToolDefinition = {
|
|
name: 'tool1',
|
|
description: 'Tool 1',
|
|
inputSchema: {},
|
|
module: 'module1',
|
|
permissions: [],
|
|
};
|
|
|
|
const tool2: ToolDefinition = {
|
|
name: 'tool2',
|
|
description: 'Tool 2',
|
|
inputSchema: {},
|
|
module: 'module2',
|
|
permissions: [],
|
|
};
|
|
|
|
// Get initial count (built-in tools)
|
|
const initialTools = await registry.listTools();
|
|
const builtinCount = initialTools.length;
|
|
|
|
registry.registerTool(tool1);
|
|
registry.registerTool(tool2);
|
|
|
|
const tools = await registry.listTools();
|
|
|
|
expect(tools).toHaveLength(builtinCount + 2);
|
|
expect(tools.find(t => t.name === 'tool1')).toBeDefined();
|
|
expect(tools.find(t => t.name === 'tool2')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('executeTool', () => {
|
|
it('should execute a registered tool', async () => {
|
|
const tool: ToolDefinition = {
|
|
name: 'test-tool',
|
|
description: 'Test tool',
|
|
inputSchema: {},
|
|
module: 'test-module',
|
|
permissions: [],
|
|
};
|
|
|
|
registry.registerTool(tool);
|
|
|
|
mockNatsClient.request.mockResolvedValue({
|
|
id: 'test-id',
|
|
status: 'success',
|
|
data: { result: 'test result' },
|
|
duration: 100,
|
|
});
|
|
|
|
const result = await registry.executeTool('test-tool', { input: 'test' });
|
|
|
|
expect(result).toEqual({ result: 'test result' });
|
|
expect(mockNatsClient.request).toHaveBeenCalledWith(
|
|
'tools.test-module.test-tool.execute',
|
|
expect.objectContaining({
|
|
tool: 'test-tool',
|
|
method: 'execute',
|
|
params: { input: 'test' },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should throw error for unknown tool', async () => {
|
|
await expect(registry.executeTool('unknown-tool', {}))
|
|
.rejects.toThrow('Tool not found: unknown-tool');
|
|
});
|
|
|
|
it('should throw error when tool execution fails', async () => {
|
|
const tool: ToolDefinition = {
|
|
name: 'test-tool',
|
|
description: 'Test tool',
|
|
inputSchema: {},
|
|
module: 'test-module',
|
|
permissions: [],
|
|
};
|
|
|
|
registry.registerTool(tool);
|
|
|
|
mockNatsClient.request.mockResolvedValue({
|
|
id: 'test-id',
|
|
status: 'error',
|
|
error: {
|
|
code: 'TEST_ERROR',
|
|
message: 'Test error message',
|
|
},
|
|
duration: 100,
|
|
});
|
|
|
|
await expect(registry.executeTool('test-tool', {}))
|
|
.rejects.toThrow('Test error message');
|
|
});
|
|
});
|
|
}); |