learning_ai_common_plat/services/mcp-server/src/modules/lysnrai/lysnrai-tools.ts
saravanakumardb1 f70001de74 fix(mcp-server): audit fixes — 3 bugs + 2 new tools
Bug fixes:
- lysnrai: add lysnrai.sessions.get tool (GET /sessions/:id existed but had no MCP surface)
- nomgap: add nomgap.autophagyConfidence tool (POST /fasting/autophagy-confidence had no tool)
- chronomind: fix syncStatus description 'paused' -> 'pending' (wrong field name)

New client functions: lysnraiSessionGet, nomgapAutophagyConfidence (with typed interfaces)

Root bug fixed in learning_voice_ai_agent commit 42aa931:
GET /transcripts/:id was missing from backend — lysnrai.transcripts.get was always 404-ing
2026-03-05 14:05:03 -08:00

166 lines
6.5 KiB
TypeScript

/**
* LysnrAI MCP tools — lysnrai.transcripts.*, lysnrai.stt.*, lysnrai.sessions.*,
* lysnrai.orgs.*, lysnrai.apiTokens.*
*
* Backed by: lysnrai-backend (port 4015).
* All tools require admin role.
*/
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import { config } from '../../lib/config.js';
import {
lysnraiTranscriptsList,
lysnraiTranscriptGet,
lysnraiTranscriptRunExtraction,
lysnraiSttGetBackendStatus,
lysnraiSessionGet,
lysnraiSessionsList,
lysnraiOrgsList,
lysnraiOrgGet,
lysnraiApiTokensList,
} from '../../lib/lysnrai-client.js';
import type { McpToolRequest } from '../tools/types.js';
const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);
// ── lysnrai.transcripts.get ───────────────────────────────────────────────
registerTool({
name: 'lysnrai.transcripts.get',
description:
'Get a single transcript by ID, including extractions[] and extractionMetadata if extraction has run. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
transcriptId: z.string().min(1).describe('Transcript ID'),
}),
async execute(args, req) {
return lysnraiTranscriptGet(args.transcriptId, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.transcripts.list ──────────────────────────────────────────────
registerTool({
name: 'lysnrai.transcripts.list',
description: 'List dictation transcripts 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 lysnraiTranscriptsList(args, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.transcripts.runExtraction ────────────────────────────────────
registerTool({
name: 'lysnrai.transcripts.runExtraction',
description:
'Run extraction-service enrichment on a transcript — populates extractions[] and extractedAt. Best-effort: returns partial if extraction-service is unavailable. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
transcriptId: z.string().min(1).describe('Transcript ID (trx_... prefix)'),
}),
async execute(args, req) {
return lysnraiTranscriptRunExtraction(args.transcriptId, {
token: tokenOf(req),
requestId: req.id,
});
},
});
// ── lysnrai.stt.getBackendStatus ──────────────────────────────────────────
registerTool({
name: 'lysnrai.stt.getBackendStatus',
description:
'Report which speech-to-text backend is active: azure (Azure Speech SDK) or whisper (local Whisper model). Useful for ops health checks. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({}),
async execute(_args, req) {
return lysnraiSttGetBackendStatus({ token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.sessions.get ──────────────────────────────────────────────────
registerTool({
name: 'lysnrai.sessions.get',
description:
'Get a single dictation session by ID including its entries[], composedText, compositionHistory, and status. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
sessionId: z.string().min(1).describe('Session ID (ses_… prefix)'),
}),
async execute(args, req) {
return lysnraiSessionGet(args.sessionId, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.sessions.list ─────────────────────────────────────────────────
registerTool({
name: 'lysnrai.sessions.list',
description: 'List dictation sessions for the authenticated user. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
status: z
.enum(['active', 'composed', 'archived'])
.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 lysnraiSessionsList(args, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.orgs.list ─────────────────────────────────────────────────────
registerTool({
name: 'lysnrai.orgs.list',
description: 'List organisations 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 lysnraiOrgsList(args, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.orgs.get ─────────────────────────────────────────────────────
registerTool({
name: 'lysnrai.orgs.get',
description:
'Get a single organisation by ID including member count, vocabulary, and shared instructions. Requires admin role.',
requiredRole: 'admin',
inputSchema: z.object({
orgId: z.string().min(1).describe('Organisation ID'),
}),
async execute(args, req) {
return lysnraiOrgGet(args.orgId, { token: tokenOf(req), requestId: req.id });
},
});
// ── lysnrai.apiTokens.list ────────────────────────────────────────────────
registerTool({
name: 'lysnrai.apiTokens.list',
description: 'List API tokens 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 lysnraiApiTokensList(args, { token: tokenOf(req), requestId: req.id });
},
});