/** * MindLyst MCP tools — mindlyst.memory.*, mindlyst.brains.*, mindlyst.briefs.*, * mindlyst.streaks.*, mindlyst.reflections.*, mindlyst.extractions.* * * Backed by: mindlyst-backend (port 4014) + extraction-service (port 4005). * All tools require admin role. */ import { z } from 'zod'; import { registerTool } from '../tools/registry.js'; import { config } from '../../lib/config.js'; import { mindlystMemoryList, mindlystMemoryGetItem, mindlystMemoryRetriage, mindlystMemoryPatch, mindlystMemoryReassign, mindlystBrainsList, mindlystBriefsGetToday, mindlystBriefsList, mindlystStreaksGet, mindlystReflectionsList, } from '../../lib/mindlyst-client.js'; import { extractionRun } from '../../lib/extraction-client.js'; import type { McpToolRequest } from '../tools/types.js'; const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7); // ── mindlyst.memory.get ─────────────────────────────────────────────────── registerTool({ name: 'mindlyst.memory.get', description: 'Get a single memory item by ID, including its full TriageResult (urgencyScore, emotionScore, confidenceScore, entities, suggestedActions). Requires admin role.', requiredRole: 'admin', inputSchema: z.object({ itemId: z.string().min(1).describe('Memory item ID'), }), async execute(args, req) { return mindlystMemoryGetItem(args.itemId, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.memory.list ────────────────────────────────────────────────── registerTool({ name: 'mindlyst.memory.list', description: 'List MindLyst memory items for the authenticated user. Filter by brain, status, or use free-text. Requires admin role.', requiredRole: 'admin', inputSchema: z.object({ brainId: z.string().optional().describe('Filter to a specific Brain ID (e.g. "work", "home")'), filter: z .enum(['forgotten', 'completed_today']) .optional() .describe('forgotten = actedOn=false, completed_today = actedOn=true today'), 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 mindlystMemoryList(args, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.memory.retriage ────────────────────────────────────────────── registerTool({ name: 'mindlyst.memory.retriage', description: 'Re-run extraction on a single memory item to refresh its triage result (urgencyScore, suggestedBrainId, entities). Best-effort: returns current item if extraction-service is unavailable. Requires admin role.', requiredRole: 'admin', inputSchema: z.object({ itemId: z.string().min(1).describe('Memory item ID'), }), async execute(args, req) { return mindlystMemoryRetriage(args.itemId, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.memory.patch ───────────────────────────────────────────────── registerTool({ name: 'mindlyst.memory.patch', description: 'Update a memory item status: mark_done, mark_undone, increment_nudge, or set_reminder. Requires admin role.', requiredRole: 'admin', inputSchema: z.object({ itemId: z.string().min(1).describe('Memory item ID'), action: z.enum(['mark_done', 'mark_undone', 'increment_nudge', 'set_reminder']), reminderAt: z .string() .datetime() .optional() .describe('ISO 8601 datetime — required when action is set_reminder'), }), async execute(args, req) { return mindlystMemoryPatch(args.itemId, args.action, args.reminderAt, { token: tokenOf(req), requestId: req.id, }); }, }); // ── mindlyst.memory.reassign ────────────────────────────────────────────── registerTool({ name: 'mindlyst.memory.reassign', description: 'Reassign a memory item to a different Brain. Records a userCorrection for training. Requires admin role.', requiredRole: 'admin', inputSchema: z.object({ itemId: z.string().min(1).describe('Memory item ID'), newBrainId: z.string().min(1).describe('Target Brain ID'), }), async execute(args, req) { return mindlystMemoryReassign(args.itemId, args.newBrainId, { token: tokenOf(req), requestId: req.id, }); }, }); // ── mindlyst.brains.list ────────────────────────────────────────────────── registerTool({ name: 'mindlyst.brains.list', description: 'List all Brains for the authenticated user (role-based life OS categories). 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 mindlystBrainsList(args, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.briefs.getToday ────────────────────────────────────────────── registerTool({ name: 'mindlyst.briefs.getToday', description: "Get today's Daily Brief for the authenticated user. Returns 404 error if none generated yet. Requires admin role.", requiredRole: 'admin', inputSchema: z.object({}), async execute(_args, req) { return mindlystBriefsGetToday({ token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.briefs.list ────────────────────────────────────────────────── registerTool({ name: 'mindlyst.briefs.list', description: 'List past Daily Briefs for the authenticated user. 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 mindlystBriefsList(args, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.streaks.get ────────────────────────────────────────────────── registerTool({ name: 'mindlyst.streaks.get', description: 'Get the current engagement streak for the authenticated user (currentStreak, longestStreak, lastActiveDate). Requires admin role.', requiredRole: 'admin', inputSchema: z.object({}), async execute(_args, req) { return mindlystStreaksGet({ token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.reflections.list ───────────────────────────────────────────── registerTool({ name: 'mindlyst.reflections.list', description: 'List reflection journal entries for the authenticated user. 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 mindlystReflectionsList(args, { token: tokenOf(req), requestId: req.id }); }, }); // ── mindlyst.extractions.run ────────────────────────────────────────────── registerTool({ name: 'mindlyst.extractions.run', description: [ 'Run text through the MindLyst extraction pipeline with one of the three task IDs:', ' • triage — extract brain signals, entities, actions (used for new memory items)', ' • memory-insight — summarise a set of memory items into brain-level insights', ' • reflection-enrichment — extract themes and highlights from journal text', 'Requires admin role.', ].join('\n'), requiredRole: 'admin', inputSchema: z.object({ text: z.string().min(1).describe('Text to extract from'), taskId: z .enum(['triage', 'memory-insight', 'reflection-enrichment']) .default('triage') .describe('MindLyst-specific extraction task ID'), }), async execute(args, req) { return extractionRun({ text: args.text, taskId: args.taskId }, { requestId: req.id }); }, });