@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-запуска.
90 lines • 3.58 kB
JavaScript
import { createHash } from 'node:crypto';
/**
* Cache TTL policies per "tool class".
*
* Источник: `todo/error-logs-service/mcp/05-high-load.md` § 2.1.
*
* Class имена используются:
* - как `tool_class` label в Prometheus метриках (`mcp_cache_hit_ratio`);
* - как первая часть Redis key namespace (`mcp:cache:{class}:...`).
*
* Изменения дефолтов делайте здесь, не в `cachedElsClient.ts` — chair pattern.
*
* Значения можно override через ENV `MCP_CACHE_TTL_OVERRIDE_{CLASS}=secs`
* (см. `src/config.ts`).
*/
export const CACHE_POLICIES = {
log_details: 3600,
traffic_long: 300,
traffic_short: 60,
top_messages: 120,
stats_breakdown: 120,
search_recent: 15,
list_apps: 30,
heatmap: 300,
histogram: 60,
baseline: 300,
version_timeline: 300,
grouped_errors: 120,
};
/**
* Объединяет дефолтные политики с user overrides из конфига.
*/
export function resolvePolicies(overrides = {}) {
const result = { ...CACHE_POLICIES };
for (const [k, v] of Object.entries(overrides)) {
if (typeof v === 'number' && Number.isFinite(v) && v >= 0 && k in result) {
result[k] = v;
}
}
return result;
}
/**
* Стабильный sha256 hash от объекта параметров (отсортированные ключи).
*
* НЕ криптографически стойкий — это просто детерминированный fingerprint.
* Используется для построения cache key (paramsHash).
*
* Возвращает base64url-encoded 16 chars.
*/
export function paramsHash(params) {
const keys = Object.keys(params).sort();
const canon = JSON.stringify(params, keys);
return createHash('sha256').update(canon).digest('base64url').slice(0, 16);
}
/**
* Tenant-isolated cache key builder.
*
* **Обязательная** проверка: в key всегда присутствует tenant-идентификатор
* (`appSlug` или `keyPrefix`). Иначе — `Error`.
*
* Формат:
* `mcp:cache:{scope}:{tenant}:{...parts}`
*
* Это **единственный** разрешённый путь создания cache key в проекте.
*
* @throws Error если tenant=null AND keyPrefix=empty (cross-tenant leak guard)
*/
export function tenantKey(scope, appSlug, parts, fallbackKeyPrefix) {
// Защита от пустого scope
if (!scope || /[:\s]/.test(scope)) {
throw new Error(`Invalid cache scope: "${scope}"`);
}
const tenant = (appSlug && appSlug.trim().length > 0 && appSlug) ||
(fallbackKeyPrefix && fallbackKeyPrefix.trim().length > 0 && `k:${fallbackKeyPrefix}`) ||
null;
if (!tenant) {
// Tenant-isolation violation — это критический баг, см. § 2.1 spec.
throw new Error('tenantKey() called without appSlug AND without keyPrefix — refusing to build cross-tenant cache key');
}
const safeParts = parts.map((p) => sanitizeKeyPart(String(p)));
return `mcp:cache:${scope}:${tenant}:${safeParts.join(':')}`;
}
/**
* Удаляет небезопасные для Redis key символы (whitespace, разделители).
* Заменяет на '_'. Для traceId / hash — операция no-op.
*/
function sanitizeKeyPart(s) {
return s.replace(/[\s:{}\[\]]/g, '_').slice(0, 256);
}
//# sourceMappingURL=policies.js.map