learning_ai_common_plat/services/mcp-server/src/modules/chronomind/chronomind-tools.ts
saravanakumardb1 3f296a8e72 feat(mcp-server): fill 12 DOMAIN_PRODUCTS.md MCP tool gaps + client fn additions
Bug fix (committed separately):
  social-fast-coordinator: stage_transition used non-existent currentStage

New client functions:
  nomgap-client: nomgapFastingCreateSession, nomgapProtocolGet,
                 nomgapSocialListGroupFasts (+ GroupFastDoc)
  peakpulse-client: peakpulseRoutesList, peakpulseSyncStatus
  lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStats,
                  lysnraiTranscriptsExportBatch
  chronomind-client: chronomindRoutineGet, chronomindSharedTimerShare

New MCP tools (12):
  mindlyst.briefs.generate        — trigger daily brief via mindlystBriefCreate
  mindlyst.memory.getTriageResult — extract TriageResult sub-doc only
  nomgap.fasting.createSession    — start new fast with protocolId
  nomgap.protocols.get            — single protocol lookup
  nomgap.social.listGroupFasts    — list group fast sessions
  peakpulse.routes.list           — list GPS r
Bug fix (committed separately):
  social-fast-coordinator: stage_transition used non-existent currentStage
ats  social-fast-coordinator: staon
New client functions:
  nomgap-client: nomgapFastingCreateSession, nomgarai  nomgaens.rotate                      nomgapSocialListGroupFasts (+ GroupFastDoc)
 d.  peakpulse-client: peakpulseRoutesList, peakpulseSyncStaturg  lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStati                  lysnraiTranscriptsExpor                    us  chronomind-client: chronomindRoutineGet, chrerver total: 126 tools across 17 namespaces
2026-03-05 18:19:04 -08:00

212 lines
8.3 KiB
TypeScript

/**
* ChronoMind MCP tools — chronomind.timers.*, chronomind.routines.*, chronomind.syncStatus
*
* Backed by: chronomind-backend (port 4011).
* All tools require admin role.
*/
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import { config } from '../../lib/config.js';
import {
chronomindTimerCreate,
chronomindTimersList,
chronomindTimerDelete,
chronomindRoutineGet,
chronomindRoutinesList,
chronomindSyncStatus,
chronomindHouseholdsList,
chronomindSharedTimerShare,
} from '../../lib/chronomind-client.js';
import type { McpToolRequest } from '../tools/types.js';
const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);
// ── chronomind.timers.create ───────────────────────────────────────────────
registerTool({
name: 'chronomind.timers.create',
description:
'Create a new cloud-synced timer. The id and syncVersion must be provided by the caller (client-generated UUID and current version). Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
id: z.string().min(1).describe('Client-generated timer UUID'),
label: z.string().min(1).describe('Timer display name'),
type: z.enum(['alarm', 'countdown', 'pomodoro', 'event']),
urgency: z.enum(['critical', 'important', 'standard', 'gentle', 'passive']).default('standard'),
duration: z.coerce.number().optional().describe('Duration in seconds (countdown/pomodoro)'),
targetTime: z.string().optional().describe('ISO 8601 target time (alarm/event)'),
category: z.string().optional().describe('Timer category label'),
syncVersion: z.coerce.number().default(1),
deviceId: z.string().optional().describe('Origin device ID for conflict detection'),
}),
async execute(args, req) {
return chronomindTimerCreate(
{ ...args, state: 'idle' },
{ token: tokenOf(req), requestId: req.id }
);
},
});
// ── chronomind.timers.list ────────────────────────────────────────────────
registerTool({
name: 'chronomind.timers.list',
description:
'List cloud-synced timers for the authenticated user. Filter by type (alarm/countdown/pomodoro/event) or state (idle/active/paused/warning/fired/completed). Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
type: z
.enum(['alarm', 'countdown', 'pomodoro', 'event'])
.optional()
.describe('Filter by timer type'),
state: z
.enum(['idle', 'active', 'paused', 'warning', 'fired', 'completed'])
.optional()
.describe('Filter by timer state'),
limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
offset: z.coerce.number().min(0).default(0),
}),
async execute(args, req) {
return chronomindTimersList(args, { token: tokenOf(req), requestId: req.id });
},
});
// ── chronomind.timers.delete ──────────────────────────────────────────────
registerTool({
name: 'chronomind.timers.delete',
description: 'Delete a timer by ID. Use with care — deletion is permanent. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
timerId: z.string().min(1).describe('Timer ID to delete'),
}),
async execute(args, req) {
return chronomindTimerDelete(args.timerId, { token: tokenOf(req), requestId: req.id });
},
});
// ── chronomind.routines.list ──────────────────────────────────────────────
registerTool({
name: 'chronomind.routines.list',
description:
'List cloud-synced routines for the authenticated user. Optionally filter to template routines only. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
isTemplate: z
.boolean()
.optional()
.describe('true = only templates, false = only user routines'),
limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
offset: z.coerce.number().min(0).default(0),
}),
async execute(args, req) {
return chronomindRoutinesList(args, { token: tokenOf(req), requestId: req.id });
},
});
// ── chronomind.syncStatus ─────────────────────────────────────────────────
registerTool({
name: 'chronomind.syncStatus',
description:
'Instant sync health check: total timers, active count, pending count, unsynced count, and last sync timestamp. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({}),
async execute(_args, req) {
return chronomindSyncStatus({ token: tokenOf(req), requestId: req.id });
},
});
// ── chronomind.sharedTimers.share ──────────────────────────────────────────
registerTool({
name: 'chronomind.sharedTimers.share',
description:
'Share a timer with one or more household members or specific user IDs. Creates a shared-timer record in the shared-timers module. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
timerId: z.string().min(1).describe('ID of the timer to share'),
targets: z
.array(
z.object({
userId: z.string().optional().describe('Target user ID'),
householdId: z
.string()
.optional()
.describe('Target household ID (shares with all members)'),
})
)
.min(1)
.describe('Recipients — provide userId or householdId for each target'),
}),
async execute(args, req) {
return chronomindSharedTimerShare(args.timerId, args.targets, {
token: tokenOf(req),
requestId: req.id,
});
},
});
// ── chronomind.routines.validate ─────────────────────────────────────────
registerTool({
name: 'chronomind.routines.validate',
description:
'Validate a routine for structural integrity: checks that total duration does not exceed the maximum, that all steps have non-zero duration, and that the routine has at least one step. Returns pass/fail with a list of issues. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
routineId: z.string().min(1).describe('Routine ID to validate'),
maxDurationMinutes: z.coerce
.number()
.min(1)
.max(1440)
.default(480)
.describe('Maximum allowed total duration in minutes (default 480 = 8h)'),
}),
async execute(args, req) {
let routine;
try {
routine = await chronomindRoutineGet(args.routineId, {
token: tokenOf(req),
requestId: req.id,
});
} catch {
return { valid: false, routineId: args.routineId, issues: ['Routine not found'] };
}
const issues: string[] = [];
if (!routine.steps || routine.steps.length === 0) issues.push('Routine has no steps');
if (routine.totalDurationMinutes > args.maxDurationMinutes) {
issues.push(
`Total duration ${routine.totalDurationMinutes}min exceeds max ${args.maxDurationMinutes}min`
);
}
return {
valid: issues.length === 0,
routineId: routine.id,
routineName: routine.name,
stepCount: routine.steps.length,
totalDurationMinutes: routine.totalDurationMinutes,
maxDurationMinutes: args.maxDurationMinutes,
issues,
};
},
});
// ── chronomind.households.list ──────────────────────────────────────────────
registerTool({
name: 'chronomind.households.list',
description:
'List ChronoMind Family-tier households the authenticated user belongs to, including member list and invite codes. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
limit: z.coerce.number().min(1).max(config.QUERY_MAX_LIMIT).default(config.QUERY_DEFAULT_LIMIT),
offset: z.coerce.number().min(0).default(0),
}),
async execute(args, req) {
return chronomindHouseholdsList(args, { token: tokenOf(req), requestId: req.id });
},
});