@inso_web/els-mcp
Version:
MCP-сервер поверх INSO Error Logs Service. Read-only tools (search, analytics, fingerprinting, correlations) для подключения Claude Desktop/Code и ChatGPT к логам ошибок. Streamable HTTP transport + stdio для npx-запуска.
91 lines • 3.63 kB
JavaScript
import { z } from 'zod';
import { ToolError } from '../lib/errors.js';
import { applyResponseFormat } from '../lib/responseFormat.js';
/**
* Tool: triage_recent_critical (composite)
*
* Convenience-wrapper для on-call triage. Под капотом:
* 1. search_logs(level=CRITICAL, from=now-Nmin) — sample + histogram + total
* 2. analytics/top-messages (тот же window) — top fingerprints
*
* Возвращает: windowMinutes, totalCritical, topFingerprints, samples, histogram.
* НЕ требует cursor (берём sampleSize самых свежих).
*/
const DEFAULT_MINUTES = 60;
export const triageRecentCriticalInputShape = {
minutesBack: z.number().int().min(1).max(1440).default(DEFAULT_MINUTES),
serviceName: z.string().max(255).optional(),
sampleSize: z.number().int().min(1).max(20).default(5),
};
export const triageRecentCriticalToolDef = {
name: 'triage_recent_critical',
title: 'Triage recent CRITICAL errors',
description: [
'On-call triage helper. Returns count of CRITICAL errors in last N minutes,',
'top fingerprints, sample traces, and histogram. Saves LLM context vs a manual',
'search_logs + grouped_errors chain.',
'',
'WHEN TO USE:',
' - 5-10 min after deploy - confirm production is clean (deploymentEnv=PRODUCTION).',
' - Periodic background sanity check during long sessions (every ~1h).',
' - User says "is anything on fire?" - one call to triage.',
' - First step of incident response before diving into specific traces.',
].join('\n'),
inputShape: triageRecentCriticalInputShape,
};
export async function handleTriageRecentCritical(args, client) {
try {
const fromIso = new Date(Date.now() - args.minutesBack * 60 * 1000).toISOString();
const toIso = new Date().toISOString();
const searchParams = {
page: 1,
limit: args.sampleSize,
sortBy: 'receivedAt',
sortOrder: 'desc',
from: fromIso,
to: toIso,
levels: 'CRITICAL',
serviceName: args.serviceName,
};
const { data: searchData, elsRequestId } = await client.searchLogs(searchParams);
const raw = searchData;
const topParams = {
from: fromIso,
to: toIso,
take: 5,
levels: 'CRITICAL',
serviceName: args.serviceName,
};
const { data: topData } = await client.topErrorMessages(topParams);
const topFingerprints = Array.isArray(topData?.data) ? topData.data : [];
const { items: samples } = applyResponseFormat(raw.items ?? [], 'compact');
const meta = {
elsRequestId,
cached: false,
ttlSec: 15,
redactionApplied: false,
};
return {
structuredContent: {
windowMinutes: args.minutesBack,
totalCritical: Number(raw.total ?? 0),
topFingerprints,
samples,
histogram: raw.histogram ?? [],
_meta: meta,
},
content: [
{
type: 'text',
text: `Triage window=${args.minutesBack}min: ${raw.total ?? 0} CRITICAL, ${topFingerprints.length} top fingerprints, ${samples.length} samples.`,
},
],
};
}
catch (err) {
if (err instanceof ToolError)
return err.toToolResult();
throw err;
}
}
//# sourceMappingURL=triageRecentCritical.js.map