Skip to main content
Glama
ce-mcp-tools.test.ts16.1 kB
/** * Tests for CE-MCP Tool Wrappers * * Tests the directive-based versions of high-token-cost tools. * * @see ADR-014: CE-MCP Architecture */ import { createAnalyzeProjectEcosystemDirective, createSuggestAdrsDirective, createGenerateRulesDirective, createAnalyzeEnvironmentDirective, createDeploymentReadinessDirective, shouldUseCEMCPDirective, getCEMCPDirective, formatDirectiveResponse, } from '../../src/tools/ce-mcp-tools.js'; import { isOrchestrationDirective, isStateMachineDirective } from '../../src/types/ce-mcp.js'; describe('CE-MCP Tools', () => { describe('createAnalyzeProjectEcosystemDirective', () => { it('should create valid orchestration directive', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', }); expect(isOrchestrationDirective(directive)).toBe(true); expect(directive.tool).toBe('analyze_project_ecosystem'); expect(directive.version).toBe('1.0'); }); // Skip: loadKnowledge operation removed from directive // TODO: Update test to match current directive operations it.skip('should include all required operations', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', analysisDepth: 'comprehensive', }); const opTypes = directive.sandbox_operations.map(op => op.op); expect(opTypes).toContain('analyzeFiles'); expect(opTypes).toContain('scanEnvironment'); expect(opTypes).toContain('loadKnowledge'); expect(opTypes).toContain('loadPrompt'); expect(opTypes).toContain('generateContext'); expect(opTypes).toContain('cacheResult'); expect(opTypes).toContain('composeResult'); }); it('should estimate ~4K tokens (down from ~12K)', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', }); expect(directive.metadata?.estimated_tokens).toBe(4000); }); it('should adjust maxFiles based on analysis depth', () => { const basicDirective = createAnalyzeProjectEcosystemDirective({ projectPath: '/test', analysisDepth: 'basic', }); const comprehensiveDirective = createAnalyzeProjectEcosystemDirective({ projectPath: '/test', analysisDepth: 'comprehensive', }); const basicAnalyzeOp = basicDirective.sandbox_operations.find(op => op.op === 'analyzeFiles'); const comprehensiveAnalyzeOp = comprehensiveDirective.sandbox_operations.find( op => op.op === 'analyzeFiles' ); expect(basicAnalyzeOp?.args?.maxFiles).toBe(50); expect(comprehensiveAnalyzeOp?.args?.maxFiles).toBe(200); }); it('should include composition directive', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', }); expect(directive.compose).toBeDefined(); expect(directive.compose?.template).toBe('ecosystem_analysis_report'); expect(directive.compose?.format).toBe('markdown'); expect(directive.compose?.sections.length).toBeGreaterThan(0); }); it('should be marked as cacheable', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', }); expect(directive.metadata?.cacheable).toBe(true); expect(directive.metadata?.cache_key).toContain('ecosystem'); }); // Skip: loadKnowledge operation no longer exists in directive // TODO: Update test or remove - technology focus may be handled differently it.skip('should handle technology focus', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test/project', technologyFocus: ['typescript', 'react'], }); const knowledgeOp = directive.sandbox_operations.find(op => op.op === 'loadKnowledge'); expect(knowledgeOp?.args?.technologies).toEqual(['typescript', 'react']); }); }); describe('createSuggestAdrsDirective', () => { it('should create valid state machine directive', () => { const directive = createSuggestAdrsDirective({ projectPath: '/test/project', }); expect(isStateMachineDirective(directive)).toBe(true); expect(directive.version).toBe('1.0'); expect(directive.final_state).toBe('done'); }); it('should have correct transition sequence', () => { const directive = createSuggestAdrsDirective({ projectPath: '/test/project', }); const transitionNames = directive.transitions.map(t => t.name); expect(transitionNames).toEqual([ 'load_adr_knowledge', 'analyze_codebase', 'load_adr_template', 'generate_suggestions', 'validate_suggestions', ]); }); it('should include initial state with all args', () => { const directive = createSuggestAdrsDirective({ projectPath: '/test/project', focusAreas: ['security', 'performance'], maxSuggestions: 10, }); expect(directive.initial_state.projectPath).toBe('/test/project'); expect(directive.initial_state.focusAreas).toEqual(['security', 'performance']); expect(directive.initial_state.maxSuggestions).toBe(10); }); it('should handle validation errors gracefully', () => { const directive = createSuggestAdrsDirective({ projectPath: '/test/project', }); const validateTransition = directive.transitions.find(t => t.name === 'validate_suggestions'); expect(validateTransition?.on_error).toBe('skip'); }); }); describe('createGenerateRulesDirective', () => { it('should create valid orchestration directive', () => { const directive = createGenerateRulesDirective({ projectPath: '/test/project', ruleType: 'code-quality', }); expect(isOrchestrationDirective(directive)).toBe(true); expect(directive.tool).toBe('generate_rules'); }); it('should estimate ~1.5K tokens (down from ~4K)', () => { const directive = createGenerateRulesDirective({ projectPath: '/test/project', ruleType: 'security', }); expect(directive.metadata?.estimated_tokens).toBe(1500); }); it('should support different rule types', () => { const ruleTypes = ['code-quality', 'security', 'architecture', 'testing'] as const; for (const ruleType of ruleTypes) { const directive = createGenerateRulesDirective({ projectPath: '/test', ruleType, }); expect(directive.description).toContain(ruleType); const knowledgeOp = directive.sandbox_operations.find(op => op.op === 'loadKnowledge'); expect(knowledgeOp?.args?.domain).toBe(ruleType); } }); it('should cache rules with longer TTL', () => { const directive = createGenerateRulesDirective({ projectPath: '/test/project', ruleType: 'architecture', }); const cacheOp = directive.sandbox_operations.find(op => op.op === 'cacheResult'); expect(cacheOp?.args?.ttl).toBe(7200); // 2 hours }); it('should adjust file patterns based on target framework', () => { const tsDirective = createGenerateRulesDirective({ projectPath: '/test', ruleType: 'code-quality', targetFramework: 'typescript', }); const analyzeOp = tsDirective.sandbox_operations.find(op => op.op === 'analyzeFiles'); expect(analyzeOp?.args?.patterns).toEqual(['**/*.ts']); }); }); describe('createAnalyzeEnvironmentDirective', () => { it('should create valid orchestration directive', () => { const directive = createAnalyzeEnvironmentDirective({ projectPath: '/test/project', }); expect(isOrchestrationDirective(directive)).toBe(true); expect(directive.tool).toBe('analyze_environment'); }); it('should estimate ~1K tokens (down from ~2.5K)', () => { const directive = createAnalyzeEnvironmentDirective({ projectPath: '/test/project', }); expect(directive.metadata?.estimated_tokens).toBe(1000); }); it('should scan environment config files', () => { const directive = createAnalyzeEnvironmentDirective({ projectPath: '/test/project', }); const analyzeOp = directive.sandbox_operations.find(op => op.op === 'analyzeFiles'); expect(analyzeOp?.args?.patterns).toContain('Dockerfile*'); expect(analyzeOp?.args?.patterns).toContain('docker-compose*.yml'); expect(analyzeOp?.args?.patterns).toContain('package.json'); }); it('should load different prompts based on analysis type', () => { const quickDirective = createAnalyzeEnvironmentDirective({ projectPath: '/test', analysisType: 'quick', }); const comprehensiveDirective = createAnalyzeEnvironmentDirective({ projectPath: '/test', analysisType: 'comprehensive', }); const quickPromptOp = quickDirective.sandbox_operations.find(op => op.op === 'loadPrompt'); const comprehensivePromptOp = comprehensiveDirective.sandbox_operations.find( op => op.op === 'loadPrompt' ); expect(quickPromptOp?.args?.section).toBe('config_validation'); expect(comprehensivePromptOp?.args?.section).toBe('infrastructure_review'); }); }); describe('createDeploymentReadinessDirective', () => { it('should create valid state machine directive', () => { const directive = createDeploymentReadinessDirective({ projectPath: '/test/project', targetEnvironment: 'production', }); expect(isStateMachineDirective(directive)).toBe(true); expect(directive.final_state).toBe('done'); }); it('should abort on validation failure', () => { const directive = createDeploymentReadinessDirective({ projectPath: '/test/project', targetEnvironment: 'staging', }); const validateTransition = directive.transitions.find(t => t.name === 'validate_readiness'); expect(validateTransition?.on_error).toBe('abort'); }); it('should include target environment in initial state', () => { const directive = createDeploymentReadinessDirective({ projectPath: '/test/project', targetEnvironment: 'production', }); expect(directive.initial_state.targetEnvironment).toBe('production'); }); it('should cache results with 30 minute TTL', () => { const directive = createDeploymentReadinessDirective({ projectPath: '/test/project', targetEnvironment: 'staging', }); const cacheTransition = directive.transitions.find(t => t.name === 'cache_result'); const op = cacheTransition?.operation as { args?: { ttl?: number } }; expect(op?.args?.ttl).toBe(1800); }); }); describe('shouldUseCEMCPDirective', () => { it('should return true for supported tools in directive mode', () => { const supportedTools = [ 'analyze_project_ecosystem', 'suggest_adrs', 'generate_rules', 'analyze_environment', 'deployment_readiness', ]; for (const tool of supportedTools) { expect(shouldUseCEMCPDirective(tool, { mode: 'directive' })).toBe(true); expect(shouldUseCEMCPDirective(tool, { mode: 'hybrid' })).toBe(true); } }); it('should return false for unsupported tools', () => { expect(shouldUseCEMCPDirective('some_other_tool', { mode: 'directive' })).toBe(false); }); it('should return false in legacy mode', () => { expect(shouldUseCEMCPDirective('analyze_project_ecosystem', { mode: 'legacy' })).toBe(false); }); }); describe('getCEMCPDirective', () => { it('should return correct directive for each tool', () => { const ecosystemDirective = getCEMCPDirective('analyze_project_ecosystem', { projectPath: '/test', }); expect(isOrchestrationDirective(ecosystemDirective!)).toBe(true); const adrDirective = getCEMCPDirective('suggest_adrs', { projectPath: '/test', }); expect(isStateMachineDirective(adrDirective!)).toBe(true); const rulesDirective = getCEMCPDirective('generate_rules', { projectPath: '/test', ruleType: 'security', }); expect(isOrchestrationDirective(rulesDirective!)).toBe(true); const envDirective = getCEMCPDirective('analyze_environment', { projectPath: '/test', }); expect(isOrchestrationDirective(envDirective!)).toBe(true); const deployDirective = getCEMCPDirective('deployment_readiness', { projectPath: '/test', targetEnvironment: 'production', }); expect(isStateMachineDirective(deployDirective!)).toBe(true); }); it('should return null for unknown tools', () => { const directive = getCEMCPDirective('unknown_tool', {}); expect(directive).toBeNull(); }); }); describe('formatDirectiveResponse', () => { it('should format orchestration directive as MCP response', () => { const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test', }); const response = formatDirectiveResponse(directive); expect(response.content).toHaveLength(1); expect(response.content[0].type).toBe('text'); expect(response.content[0].text).toContain('orchestration_directive'); }); it('should format state machine directive as MCP response', () => { const directive = createSuggestAdrsDirective({ projectPath: '/test', }); const response = formatDirectiveResponse(directive); expect(response.content[0].text).toContain('state_machine_directive'); }); it('should produce valid JSON', () => { const directive = createGenerateRulesDirective({ projectPath: '/test', ruleType: 'security', }); const response = formatDirectiveResponse(directive); const parsed = JSON.parse(response.content[0].text); expect(parsed.type).toBe('orchestration_directive'); expect(parsed.tool).toBe('generate_rules'); }); }); describe('Token Savings', () => { it('should achieve target token reduction for analyzeProjectEcosystem', () => { // Original: ~12K tokens, Target: ~4K tokens (67% reduction) const directive = createAnalyzeProjectEcosystemDirective({ projectPath: '/test', }); const originalTokens = 12000; const newTokens = directive.metadata?.estimated_tokens || 0; const reduction = ((originalTokens - newTokens) / originalTokens) * 100; expect(reduction).toBeGreaterThanOrEqual(60); }); it('should achieve target token reduction for suggest_adrs', () => { // Original: ~3.5K tokens, Target: ~1.5K tokens (~57% reduction) const directive = createSuggestAdrsDirective({ projectPath: '/test', }); // State machine directives have implicit token savings expect(directive.transitions.length).toBeLessThanOrEqual(6); }); it('should achieve target token reduction for generate_rules', () => { // Original: ~4K tokens, Target: ~1.5K tokens (62.5% reduction) const directive = createGenerateRulesDirective({ projectPath: '/test', ruleType: 'code-quality', }); const originalTokens = 4000; const newTokens = directive.metadata?.estimated_tokens || 0; const reduction = ((originalTokens - newTokens) / originalTokens) * 100; expect(reduction).toBeGreaterThanOrEqual(60); }); it('should achieve target token reduction for analyze_environment', () => { // Original: ~2.5K tokens, Target: ~1K tokens (60% reduction) const directive = createAnalyzeEnvironmentDirective({ projectPath: '/test', }); const originalTokens = 2500; const newTokens = directive.metadata?.estimated_tokens || 0; const reduction = ((originalTokens - newTokens) / originalTokens) * 100; expect(reduction).toBeGreaterThanOrEqual(60); }); }); });

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