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-запуска.

78 lines 3.19 kB
/** * Tier matrix MCP — single source of truth. * * Поля: * - reqPerDay — основной cut-off limit для tool-calls * - concurrentSse — SSE-сессий per app * - aiPerDay — лимит на AI-explain (отдельный counter) * - graceFraction — 10 % grace выше дневного лимита перед hard cut-off */ export const TIER_LIMITS = { FREE: { reqPerDay: 1_000, concurrentSse: 2, aiPerDay: 20, graceFraction: 0.1 }, STANDARD: { reqPerDay: 50_000, concurrentSse: 20, aiPerDay: 500, graceFraction: 0.1 }, PREMIUM: { reqPerDay: 500_000, concurrentSse: 100, aiPerDay: 5_000, graceFraction: 0.1 }, UNLIMITED: { reqPerDay: Number.POSITIVE_INFINITY, concurrentSse: 500, aiPerDay: Number.POSITIVE_INFINITY, graceFraction: 0, }, }; /** Секунд до конца текущих UTC-суток. */ export function secondsUntilUtcMidnight(now = new Date()) { const next = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1, 0, 0, 0, 0); return Math.max(1, Math.ceil((next - now.getTime()) / 1000)); } /** Чистое решение: принимает текущий счётчик и tier, возвращает decision. */ export function decideQuota(currentUsed, tier) { const limits = TIER_LIMITS[tier]; if (!Number.isFinite(limits.reqPerDay)) { return { allowed: true, remaining: Number.POSITIVE_INFINITY, tier }; } const cutoff = Math.floor(limits.reqPerDay * (1 + limits.graceFraction)); if (currentUsed < limits.reqPerDay) { return { allowed: true, remaining: limits.reqPerDay - currentUsed, tier }; } if (currentUsed < cutoff) { return { allowed: true, remaining: 0, overage: true, tier, }; } return { allowed: false, remaining: 0, retryAfter: secondsUntilUtcMidnight(), tier, }; } /** * Чистое решение для AI-quota: принимает текущий AI-счётчик и tier. * Используется только для tools, помеченных как AI (например, `explain_error`). * * Семантика отличается от `decideQuota`: AI-quota — hard cut-off без grace * (генерация дорогая, нет смысла превышать). */ export function decideAiQuota(currentUsed, tier) { const limits = TIER_LIMITS[tier]; if (!Number.isFinite(limits.aiPerDay)) { return { allowed: true, remaining: Number.POSITIVE_INFINITY, tier }; } if (currentUsed < limits.aiPerDay) { return { allowed: true, remaining: limits.aiPerDay - currentUsed, tier }; } return { allowed: false, remaining: 0, retryAfter: secondsUntilUtcMidnight(), tier, }; } /** Список tool-имён, считающихся AI (используют отдельную AI-квоту). */ export const AI_TOOL_NAMES = new Set(['explain_error']); export function isAiTool(toolName) { return AI_TOOL_NAMES.has(toolName); } //# sourceMappingURL=limits.js.map