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
156 lines
6.3 KiB
TypeScript
156 lines
6.3 KiB
TypeScript
/**
|
|
* PeakPulse MCP tools — peakpulse.sessions.*, peakpulse.routes.*, peakpulse.stats
|
|
*
|
|
* Backed by: peakpulse-backend (port 4010).
|
|
* All tools require admin role.
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
import { registerTool } from '../tools/registry.js';
|
|
import { config } from '../../lib/config.js';
|
|
import {
|
|
peakpulseSessionsList,
|
|
peakpulseSessionGet,
|
|
peakpulseSessionExport,
|
|
peakpulseGetStats,
|
|
peakpulseRoutesList,
|
|
peakpulseRouteGet,
|
|
peakpulseSyncStatus,
|
|
} from '../../lib/peakpulse-client.js';
|
|
import type { McpToolRequest } from '../tools/types.js';
|
|
|
|
const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);
|
|
|
|
// ── peakpulse.sessions.list ───────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.sessions.list',
|
|
description:
|
|
'List adventure sessions for the authenticated user. Filter by activity type (hiking/skiing/cycling/running) or status. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({
|
|
activityType: z
|
|
.enum(['hiking', 'skiing', 'cycling', 'running'])
|
|
.optional()
|
|
.describe('Filter by activity type'),
|
|
status: z
|
|
.enum(['active', 'completed', 'paused'])
|
|
.optional()
|
|
.describe('Filter by session status'),
|
|
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 peakpulseSessionsList(args, { token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.sessions.export ─────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.sessions.export',
|
|
description:
|
|
'Export a session as a portable JSON summary including GPS bounds, ski metrics, weather snapshot, and elevation data. Useful for sharing or route-review flows. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({
|
|
sessionId: z.string().min(1).describe('Session ID to export'),
|
|
}),
|
|
async execute(args, req) {
|
|
return peakpulseSessionExport(args.sessionId, { token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.stats ───────────────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.stats',
|
|
description:
|
|
'Get aggregated activity stats for the authenticated user (total sessions, distance, elevation gain, per-activity breakdown). Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({}),
|
|
async execute(_args, req) {
|
|
return peakpulseGetStats({ token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.sessions.get ──────────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.sessions.get',
|
|
description:
|
|
'Get a single adventure session by ID including activityType, GPS trackPoints summary, ski/hike metrics, weather snapshot, and haptic events. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({
|
|
sessionId: z.string().min(1).describe('Session ID'),
|
|
}),
|
|
async execute(args, req) {
|
|
return peakpulseSessionGet(args.sessionId, { token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.routes.list ───────────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.routes.list',
|
|
description:
|
|
'List GPS route documents for the authenticated user. Each route contains track points, haptic milestone events, and a bounding box. 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 peakpulseRoutesList(args, { token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.routes.get ────────────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.routes.get',
|
|
description:
|
|
'Retrieve GPS track points and haptic milestone events for a session. Returns bounding box coordinates plus full track point array. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({
|
|
sessionId: z.string().min(1).describe('Session ID to get route data for'),
|
|
}),
|
|
async execute(args, req) {
|
|
return peakpulseRouteGet(args.sessionId, { token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.syncStatus ─────────────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.syncStatus',
|
|
description:
|
|
'Check the PeakPulse offline upload queue: pending session count, last successful sync timestamp, and oldest pending item age. Useful for diagnosing sync failures on iOS. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({}),
|
|
async execute(_args, req) {
|
|
return peakpulseSyncStatus({ token: tokenOf(req), requestId: req.id });
|
|
},
|
|
});
|
|
|
|
// ── peakpulse.weather.getSnapshot ───────────────────────────────────────────────
|
|
|
|
registerTool({
|
|
name: 'peakpulse.weather.getSnapshot',
|
|
description:
|
|
'Get the weather snapshot captured at the start of a session (temperature, wind speed, UV index, condition). Returns null if weather data was not captured. Requires admin role.',
|
|
requiredRole: 'admin',
|
|
inputSchema: z.object({
|
|
sessionId: z.string().min(1).describe('Session ID to retrieve weather snapshot for'),
|
|
}),
|
|
async execute(args, req) {
|
|
const session = await peakpulseSessionGet(args.sessionId, {
|
|
token: tokenOf(req),
|
|
requestId: req.id,
|
|
});
|
|
return {
|
|
sessionId: args.sessionId,
|
|
weather: (session as unknown as Record<string, unknown>).weather ?? null,
|
|
};
|
|
},
|
|
});
|