Skip to main content
Glama
managementHandlers.test.ts14.9 kB
/** * Tests for management handlers */ import { FlagManager } from '@src/core/flags/flagManager.js'; import { AdapterFactory } from '@src/core/tools/internal/adapters/index.js'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { cleanupManagementHandlers, handleMcpDisable, handleMcpEnable, handleMcpList, handleMcpReload, handleMcpStatus, } from './managementHandlers.js'; // Mock dependencies vi.mock('@src/core/flags/flagManager.js'); vi.mock('@src/logger/logger.js', () => ({ default: { error: vi.fn(), }, debugIf: vi.fn(), infoIf: vi.fn(), warnIf: vi.fn(), errorIf: vi.fn(), logger: { error: vi.fn(), }, })); // Mock adapters vi.mock('@src/core/tools/internal/adapters/index.js', () => ({ AdapterFactory: { getManagementAdapter: vi.fn(), cleanup: vi.fn(), reset: vi.fn(), }, })); describe('managementHandlers', () => { let flagManager: any; let mockManagementAdapter: any; beforeEach(() => { vi.clearAllMocks(); flagManager = { isToolEnabled: vi.fn().mockReturnValue(true), } as any; (FlagManager.getInstance as any).mockReturnValue(flagManager); // Mock management adapter mockManagementAdapter = { listServers: vi.fn(), getServerStatus: vi.fn(), enableServer: vi.fn(), disableServer: vi.fn(), reloadConfiguration: vi.fn(), updateServerConfig: vi.fn(), validateServerConfig: vi.fn(), getServerUrl: vi.fn(), }; (AdapterFactory.getManagementAdapter as any).mockReturnValue(mockManagementAdapter); }); afterEach(() => { cleanupManagementHandlers(); vi.restoreAllMocks(); }); describe('handleMcpEnable', () => { it('should execute enable successfully when enabled', async () => { const mockResult = { success: true, serverName: 'test-server', enabled: true, restarted: true, warnings: [], errors: [], }; mockManagementAdapter.enableServer.mockResolvedValue(mockResult); const args = { name: 'test-server', restart: true, graceful: true, timeout: 30, }; const result = await handleMcpEnable(args); expect(result.status).toBe('success'); expect(result.message).toBe("MCP server 'test-server' enabled successfully"); expect(result.name).toBe('test-server'); expect(result.enabled).toBe(true); expect(result.restarted).toBe(true); expect(result.reloadRecommended).toBe(true); expect(mockManagementAdapter.enableServer).toHaveBeenCalledWith('test-server', { restart: true, graceful: true, timeout: 30, tags: undefined, }); }); it('should return error when management tools are disabled', async () => { flagManager.isToolEnabled.mockReturnValue(false); const args = { name: 'test-server', restart: false, graceful: true, timeout: 30, }; const result = await handleMcpEnable(args); expect(result).toEqual({ name: 'test-server', status: 'failed', message: 'MCP server management is currently disabled by configuration', error: 'Management tools are disabled', }); expect(flagManager.isToolEnabled).toHaveBeenCalledWith('internalTools', 'management', 'enable'); }); it('should handle enable errors', async () => { mockManagementAdapter.enableServer.mockRejectedValue(new Error('Enable failed')); const args = { name: 'test-server', restart: false, graceful: true, timeout: 30, }; const result = await handleMcpEnable(args); expect(result).toEqual({ name: 'test-server', status: 'failed', message: 'Enable operation failed: Enable failed', error: 'Enable failed', }); }); }); describe('handleMcpDisable', () => { it('should execute disable successfully when enabled', async () => { const mockResult = { success: true, serverName: 'test-server', disabled: true, gracefulShutdown: true, warnings: [], errors: [], }; mockManagementAdapter.disableServer.mockResolvedValue(mockResult); const args = { name: 'test-server', graceful: true, timeout: 30, force: false, }; const result = await handleMcpDisable(args); // Direct structured result - no need to parse expect(result.status).toBe('success'); expect(result.message).toBe("MCP server 'test-server' disabled successfully"); expect(result.name).toBe('test-server'); expect(result.disabled).toBe(true); expect(result.gracefulShutdown).toBe(true); expect(result.reloadRecommended).toBe(true); expect(mockManagementAdapter.disableServer).toHaveBeenCalledWith('test-server', { graceful: true, timeout: 30, force: false, tags: undefined, }); }); it('should return error when management tools are disabled', async () => { flagManager.isToolEnabled.mockReturnValue(false); const args = { name: 'test-server', graceful: true, timeout: 30, force: false, }; const result = await handleMcpDisable(args); expect(result).toEqual({ name: 'test-server', status: 'failed', message: 'MCP server management is currently disabled by configuration', error: 'Management tools are disabled', }); expect(flagManager.isToolEnabled).toHaveBeenCalledWith('internalTools', 'management', 'disable'); }); it('should handle disable errors', async () => { mockManagementAdapter.disableServer.mockRejectedValue(new Error('Disable failed')); const args = { name: 'test-server', graceful: true, timeout: 30, force: false, }; const result = await handleMcpDisable(args); expect(result).toEqual({ name: 'test-server', status: 'failed', message: 'Disable operation failed: Disable failed', error: 'Disable failed', }); }); }); describe('handleMcpList', () => { it('should execute list successfully when enabled', async () => { const mockResult = [ { name: 'test-server', status: 'enabled', transport: 'stdio', config: {}, url: 'http://localhost:3000', healthStatus: 'healthy', lastChecked: new Date().toISOString(), metadata: {}, }, ]; mockManagementAdapter.listServers.mockImplementation((_args: unknown) => Promise.resolve(mockResult)); const args = { status: 'enabled' as const, format: 'table' as const, detailed: false, includeCapabilities: false, includeHealth: true, sortBy: 'name' as const, }; const result = await handleMcpList(args); // Direct structured result - no need to parse expect(result.servers).toHaveLength(1); expect(result.servers[0]).toMatchObject({ name: 'test-server', status: 'enabled', transport: 'stdio', }); expect(mockManagementAdapter.listServers).toHaveBeenCalledWith({ status: 'enabled', transport: undefined, // args.transport is not provided in test args detailed: false, tags: undefined, }); }); it('should return error when management tools are disabled', async () => { flagManager.isToolEnabled.mockReturnValue(false); const args = { status: 'enabled' as const, format: 'table' as const, detailed: false, includeCapabilities: false, includeHealth: true, sortBy: 'name' as const, }; const result = await handleMcpList(args); expect(result).toEqual({ servers: [], total: 0, summary: { enabled: 0, disabled: 0, running: 0, stopped: 0, }, }); expect(flagManager.isToolEnabled).toHaveBeenCalledWith('internalTools', 'management', 'list'); }); it('should handle list errors', async () => { mockManagementAdapter.listServers.mockRejectedValue(new Error('List failed')); const args = { status: 'enabled' as const, format: 'table' as const, detailed: false, includeCapabilities: false, includeHealth: true, sortBy: 'name' as const, }; const result = await handleMcpList(args); expect(result).toEqual({ servers: [], total: 0, summary: { enabled: 0, disabled: 0, running: 0, stopped: 0, }, }); }); }); describe('handleMcpStatus', () => { it('should execute status successfully when enabled', async () => { const mockResult = { servers: [ { name: 'test-server', status: 'running', transport: 'stdio', healthStatus: 'healthy', lastChecked: new Date().toISOString(), }, ], timestamp: new Date().toISOString(), }; mockManagementAdapter.getServerStatus.mockResolvedValue(mockResult); const args = { name: 'test-server', details: true, health: true, }; const result = await handleMcpStatus(args); // Direct structured result - no need to parse expect(result.servers).toHaveLength(1); expect(result.servers[0]).toMatchObject({ name: 'test-server', status: 'running', transport: 'stdio', health: { status: 'healthy', }, }); expect(result.timestamp).toBeDefined(); expect(result.overall).toEqual({ total: 1, running: 1, stopped: 0, errors: 0, }); expect(mockManagementAdapter.getServerStatus).toHaveBeenCalledWith(args.name); }); it('should return error when management tools are disabled', async () => { flagManager.isToolEnabled.mockReturnValue(false); const args = { details: false, health: true, name: 'test-server', }; const result = await handleMcpStatus(args); expect(result).toEqual({ servers: [], timestamp: expect.any(String), overall: { total: 0, running: 0, stopped: 0, errors: 0, }, }); expect(flagManager.isToolEnabled).toHaveBeenCalledWith('internalTools', 'management', 'status'); }); it('should handle status errors', async () => { mockManagementAdapter.getServerStatus.mockRejectedValue(new Error('Status failed')); const args = { details: false, health: true, name: 'test-server', }; const result = await handleMcpStatus(args); expect(result).toEqual({ servers: [], timestamp: expect.any(String), overall: { total: 0, running: 0, stopped: 0, errors: 0, }, }); }); it('should return status result directly', async () => { const mockResult = { servers: [ { name: 'test-server', status: 'running', transport: 'stdio', healthStatus: 'healthy', lastChecked: new Date().toISOString(), }, ], timestamp: new Date().toISOString(), }; mockManagementAdapter.getServerStatus.mockResolvedValue(mockResult); const args = { name: 'test-server', details: false, health: true, }; const result = await handleMcpStatus(args); // Direct structured result - no need to parse expect(result.servers).toHaveLength(1); expect(result.servers[0]).toMatchObject({ name: 'test-server', status: 'running', transport: 'stdio', health: { status: 'healthy', }, }); expect(result.timestamp).toBeDefined(); expect(typeof result.timestamp).toBe('string'); expect(result.overall).toEqual({ total: 1, running: 1, stopped: 0, errors: 0, }); }); }); describe('handleMcpReload', () => { it('should execute reload successfully when enabled', async () => { const mockResult = { success: true, target: 'config', action: 'reloaded', timestamp: new Date().toISOString(), reloadedServers: [], warnings: [], errors: [], }; mockManagementAdapter.reloadConfiguration.mockResolvedValue(mockResult); const args = { configOnly: true, graceful: true, timeout: 30000, force: false, }; const result = await handleMcpReload(args); // Direct structured result - no need to parse expect(result.status).toBe('success'); expect(result.message).toBe('Reload completed successfully for config'); expect(result.target).toBe('config'); expect(result.action).toBe('reloaded'); expect(result.timestamp).toBeDefined(); expect(mockManagementAdapter.reloadConfiguration).toHaveBeenCalledWith({ server: undefined, configOnly: true, force: false, timeout: 30000, }); }); it('should return error when management tools are disabled', async () => { flagManager.isToolEnabled.mockReturnValue(false); const args = { configOnly: true, graceful: true, timeout: 30000, force: false, }; const result = await handleMcpReload(args); expect(result).toEqual({ target: 'config', status: 'failed', message: 'MCP server management is currently disabled by configuration', error: 'Management tools are disabled', timestamp: expect.any(String), }); expect(flagManager.isToolEnabled).toHaveBeenCalledWith('internalTools', 'management', 'reload'); }); it('should handle reload errors', async () => { mockManagementAdapter.reloadConfiguration.mockRejectedValue(new Error('Reload failed')); const args = { configOnly: true, graceful: true, timeout: 30000, force: false, }; const result = await handleMcpReload(args); expect(result).toEqual({ target: 'config', status: 'failed', message: 'Reload operation failed: Reload failed', error: 'Reload failed', timestamp: expect.any(String), }); }); }); describe('cleanupManagementHandlers', () => { it('should cleanup without errors', () => { expect(() => cleanupManagementHandlers()).not.toThrow(); }); }); });

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/1mcp-app/agent'

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