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
This commit is contained in:
saravanakumardb1 2026-05-14 16:59:26 -07:00
parent 9c60e5aba0
commit ab23f05b1a

View File

@ -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<string, unknown>;
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<string, unknown>;
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<string, unknown>;
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<string, unknown>;
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<string, unknown>;
expect(props).toHaveProperty('start');
expect(props).toHaveProperty('end');
expect(props).toHaveProperty('minSlotMinutes');
});
});