UNPKG

@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
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