From ab23f05b1ad82284f2e092636f032598b2121005 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 14 May 2026 16:59:26 -0700 Subject: [PATCH] test(mcp-server): add 8 ChronoMind MCP tool registration + schema tests - Verify all 15 tools registered (timers, routines, sync, planner, agent-actions) - Check admin role requirement on every tool - Validate input schemas for key tools (planDay, planNl, reschedule, availability) - Resolves TODO-007 from ChronoMind roadmap --- .../chronomind/chronomind-tools.test.ts | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 services/mcp-server/src/modules/chronomind/chronomind-tools.test.ts diff --git a/services/mcp-server/src/modules/chronomind/chronomind-tools.test.ts b/services/mcp-server/src/modules/chronomind/chronomind-tools.test.ts new file mode 100644 index 00000000..fd680a23 --- /dev/null +++ b/services/mcp-server/src/modules/chronomind/chronomind-tools.test.ts @@ -0,0 +1,103 @@ +/** + * ChronoMind MCP tools — registration + schema validation tests. + * + * Verifies that all 13 ChronoMind tools are registered with correct schemas, + * descriptions, and required roles. Does NOT call chronomind-backend (unit tests only). + */ + +import { describe, it, expect } from 'vitest'; +import { getTool, listTools } from '../tools/registry.js'; + +// Importing the module causes all registerTool() calls to execute +import './chronomind-tools.js'; + +const EXPECTED_TOOLS = [ + 'chronomind.timers.create', + 'chronomind.timers.list', + 'chronomind.timers.delete', + 'chronomind.timers.reschedule', + 'chronomind.timers.availability', + 'chronomind.routines.list', + 'chronomind.routines.validate', + 'chronomind.routines.start', + 'chronomind.syncStatus', + 'chronomind.sharedTimers.share', + 'chronomind.households.list', + 'chronomind.agentActions.list', + 'chronomind.agentActions.approve', + 'chronomind.planner.planDay', + 'chronomind.planner.planNl', +]; + +describe('ChronoMind MCP tools registration', () => { + it('all 15 tools are registered', () => { + const all = listTools(); + for (const name of EXPECTED_TOOLS) { + const found = all.find(t => t.name === name); + expect(found, `tool ${name} should be registered`).toBeDefined(); + } + }); + + it('every tool requires admin role', () => { + for (const name of EXPECTED_TOOLS) { + const tool = getTool(name); + expect(tool?.requiredRole).toBe('admin'); + } + }); + + it('every tool has a description', () => { + for (const name of EXPECTED_TOOLS) { + const tool = getTool(name); + expect(tool?.description).toBeTruthy(); + expect(tool!.description.length).toBeGreaterThan(10); + } + }); + + // ── Schema validation tests ── + + it('chronomind.timers.create requires id + label + type', () => { + const all = listTools(); + const tool = all.find(t => t.name === 'chronomind.timers.create'); + expect(tool?.inputSchema).toBeDefined(); + const props = tool!.inputSchema.properties as Record; + expect(props).toHaveProperty('id'); + expect(props).toHaveProperty('label'); + expect(props).toHaveProperty('type'); + }); + + it('chronomind.timers.reschedule has timerId + deltaSeconds + targetTime', () => { + const all = listTools(); + const tool = all.find(t => t.name === 'chronomind.timers.reschedule'); + const props = tool!.inputSchema.properties as Record; + expect(props).toHaveProperty('timerId'); + expect(props).toHaveProperty('deltaSeconds'); + expect(props).toHaveProperty('targetTime'); + }); + + it('chronomind.planner.planDay requires date + activities', () => { + const all = listTools(); + const tool = all.find(t => t.name === 'chronomind.planner.planDay'); + const props = tool!.inputSchema.properties as Record; + expect(props).toHaveProperty('date'); + expect(props).toHaveProperty('activities'); + expect(props).toHaveProperty('dayStartHour'); + expect(props).toHaveProperty('dayEndHour'); + }); + + it('chronomind.planner.planNl requires text', () => { + const all = listTools(); + const tool = all.find(t => t.name === 'chronomind.planner.planNl'); + const props = tool!.inputSchema.properties as Record; + expect(props).toHaveProperty('text'); + expect(props).toHaveProperty('date'); + }); + + it('chronomind.timers.availability has start + end + minSlotMinutes', () => { + const all = listTools(); + const tool = all.find(t => t.name === 'chronomind.timers.availability'); + const props = tool!.inputSchema.properties as Record; + expect(props).toHaveProperty('start'); + expect(props).toHaveProperty('end'); + expect(props).toHaveProperty('minSlotMinutes'); + }); +});