@inso_web/els-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +482 -0
- package/dist/audit/prisma.d.ts +67 -0
- package/dist/audit/prisma.d.ts.map +1 -0
- package/dist/audit/prisma.js +65 -0
- package/dist/audit/prisma.js.map +1 -0
- package/dist/audit/service.d.ts +72 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +137 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/billing/limits.d.ts +34 -0
- package/dist/billing/limits.d.ts.map +1 -0
- package/dist/billing/limits.js +51 -0
- package/dist/billing/limits.js.map +1 -0
- package/dist/billing/tracker.d.ts +39 -0
- package/dist/billing/tracker.d.ts.map +1 -0
- package/dist/billing/tracker.js +92 -0
- package/dist/billing/tracker.js.map +1 -0
- package/dist/cache/cachedElsClient.d.ts +71 -0
- package/dist/cache/cachedElsClient.d.ts.map +1 -0
- package/dist/cache/cachedElsClient.js +167 -0
- package/dist/cache/cachedElsClient.js.map +1 -0
- package/dist/cache/index.d.ts +10 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/policies.d.ts +60 -0
- package/dist/cache/policies.d.ts.map +1 -0
- package/dist/cache/policies.js +90 -0
- package/dist/cache/policies.js.map +1 -0
- package/dist/cache/redis.d.ts +52 -0
- package/dist/cache/redis.d.ts.map +1 -0
- package/dist/cache/redis.js +134 -0
- package/dist/cache/redis.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +32 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/cache/wrapper.d.ts +38 -0
- package/dist/cache/wrapper.d.ts.map +1 -0
- package/dist/cache/wrapper.js +109 -0
- package/dist/cache/wrapper.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +86 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +105 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +211 -0
- package/dist/config.js.map +1 -0
- package/dist/elsClient.d.ts +137 -0
- package/dist/elsClient.d.ts.map +1 -0
- package/dist/elsClient.js +285 -0
- package/dist/elsClient.js.map +1 -0
- package/dist/http/app.d.ts +40 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +135 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/jwks.d.ts +8 -0
- package/dist/http/jwks.d.ts.map +1 -0
- package/dist/http/jwks.js +34 -0
- package/dist/http/jwks.js.map +1 -0
- package/dist/http/middleware/auth.d.ts +11 -0
- package/dist/http/middleware/auth.d.ts.map +1 -0
- package/dist/http/middleware/auth.js +225 -0
- package/dist/http/middleware/auth.js.map +1 -0
- package/dist/http/middleware/dcrRateLimit.d.ts +29 -0
- package/dist/http/middleware/dcrRateLimit.d.ts.map +1 -0
- package/dist/http/middleware/dcrRateLimit.js +59 -0
- package/dist/http/middleware/dcrRateLimit.js.map +1 -0
- package/dist/http/middleware/errorHandler.d.ts +12 -0
- package/dist/http/middleware/errorHandler.d.ts.map +1 -0
- package/dist/http/middleware/errorHandler.js +26 -0
- package/dist/http/middleware/errorHandler.js.map +1 -0
- package/dist/http/middleware/originGuard.d.ts +28 -0
- package/dist/http/middleware/originGuard.d.ts.map +1 -0
- package/dist/http/middleware/originGuard.js +55 -0
- package/dist/http/middleware/originGuard.js.map +1 -0
- package/dist/http/middleware/requestId.d.ts +19 -0
- package/dist/http/middleware/requestId.d.ts.map +1 -0
- package/dist/http/middleware/requestId.js +23 -0
- package/dist/http/middleware/requestId.js.map +1 -0
- package/dist/http/routes/health.d.ts +24 -0
- package/dist/http/routes/health.d.ts.map +1 -0
- package/dist/http/routes/health.js +73 -0
- package/dist/http/routes/health.js.map +1 -0
- package/dist/http/routes/metrics.d.ts +18 -0
- package/dist/http/routes/metrics.d.ts.map +1 -0
- package/dist/http/routes/metrics.js +42 -0
- package/dist/http/routes/metrics.js.map +1 -0
- package/dist/http/routes/wellKnown.d.ts +15 -0
- package/dist/http/routes/wellKnown.d.ts.map +1 -0
- package/dist/http/routes/wellKnown.js +43 -0
- package/dist/http/routes/wellKnown.js.map +1 -0
- package/dist/http/types.d.ts +40 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +9 -0
- package/dist/http/types.js.map +1 -0
- package/dist/instrumentation.d.ts +22 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +38 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/lib/cursor.d.ts +22 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +95 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/errors.d.ts +49 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +83 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/responseFormat.d.ts +14 -0
- package/dist/lib/responseFormat.d.ts.map +1 -0
- package/dist/lib/responseFormat.js +74 -0
- package/dist/lib/responseFormat.js.map +1 -0
- package/dist/middleware/withMiddleware.d.ts +53 -0
- package/dist/middleware/withMiddleware.d.ts.map +1 -0
- package/dist/middleware/withMiddleware.js +190 -0
- package/dist/middleware/withMiddleware.js.map +1 -0
- package/dist/observability/health.d.ts +51 -0
- package/dist/observability/health.d.ts.map +1 -0
- package/dist/observability/health.js +77 -0
- package/dist/observability/health.js.map +1 -0
- package/dist/observability/index.d.ts +8 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger.d.ts +45 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +75 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +49 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +184 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/tracing.d.ts +28 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +56 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/prompts/index.d.ts +20 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +202 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/redaction/argsRedactor.d.ts +22 -0
- package/dist/redaction/argsRedactor.d.ts.map +1 -0
- package/dist/redaction/argsRedactor.js +97 -0
- package/dist/redaction/argsRedactor.js.map +1 -0
- package/dist/redaction/fields.d.ts +64 -0
- package/dist/redaction/fields.d.ts.map +1 -0
- package/dist/redaction/fields.js +155 -0
- package/dist/redaction/fields.js.map +1 -0
- package/dist/redaction/index.d.ts +52 -0
- package/dist/redaction/index.d.ts.map +1 -0
- package/dist/redaction/index.js +160 -0
- package/dist/redaction/index.js.map +1 -0
- package/dist/redaction/promptInjection.d.ts +32 -0
- package/dist/redaction/promptInjection.d.ts.map +1 -0
- package/dist/redaction/promptInjection.js +68 -0
- package/dist/redaction/promptInjection.js.map +1 -0
- package/dist/redaction/url.d.ts +8 -0
- package/dist/redaction/url.d.ts.map +1 -0
- package/dist/redaction/url.js +26 -0
- package/dist/redaction/url.js.map +1 -0
- package/dist/redaction/userAgent.d.ts +9 -0
- package/dist/redaction/userAgent.d.ts.map +1 -0
- package/dist/redaction/userAgent.js +39 -0
- package/dist/redaction/userAgent.js.map +1 -0
- package/dist/resources/index.d.ts +24 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +150 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +37 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +35 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/baselineCompare.d.ts +36 -0
- package/dist/tools/baselineCompare.d.ts.map +1 -0
- package/dist/tools/baselineCompare.js +69 -0
- package/dist/tools/baselineCompare.js.map +1 -0
- package/dist/tools/errorHeatmap.d.ts +40 -0
- package/dist/tools/errorHeatmap.d.ts.map +1 -0
- package/dist/tools/errorHeatmap.js +69 -0
- package/dist/tools/errorHeatmap.js.map +1 -0
- package/dist/tools/errorHistogram.d.ts +39 -0
- package/dist/tools/errorHistogram.d.ts.map +1 -0
- package/dist/tools/errorHistogram.js +61 -0
- package/dist/tools/errorHistogram.js.map +1 -0
- package/dist/tools/errorStatsBreakdown.d.ts +43 -0
- package/dist/tools/errorStatsBreakdown.d.ts.map +1 -0
- package/dist/tools/errorStatsBreakdown.js +77 -0
- package/dist/tools/errorStatsBreakdown.js.map +1 -0
- package/dist/tools/errorsInSession.d.ts +44 -0
- package/dist/tools/errorsInSession.d.ts.map +1 -0
- package/dist/tools/errorsInSession.js +91 -0
- package/dist/tools/errorsInSession.js.map +1 -0
- package/dist/tools/explainError.d.ts +35 -0
- package/dist/tools/explainError.d.ts.map +1 -0
- package/dist/tools/explainError.js +98 -0
- package/dist/tools/explainError.js.map +1 -0
- package/dist/tools/findCorrelatedErrors.d.ts +43 -0
- package/dist/tools/findCorrelatedErrors.d.ts.map +1 -0
- package/dist/tools/findCorrelatedErrors.js +59 -0
- package/dist/tools/findCorrelatedErrors.js.map +1 -0
- package/dist/tools/findSimilarErrors.d.ts +44 -0
- package/dist/tools/findSimilarErrors.d.ts.map +1 -0
- package/dist/tools/findSimilarErrors.js +59 -0
- package/dist/tools/findSimilarErrors.js.map +1 -0
- package/dist/tools/getLogDetails.d.ts +30 -0
- package/dist/tools/getLogDetails.d.ts.map +1 -0
- package/dist/tools/getLogDetails.js +49 -0
- package/dist/tools/getLogDetails.js.map +1 -0
- package/dist/tools/groupedErrors.d.ts +46 -0
- package/dist/tools/groupedErrors.d.ts.map +1 -0
- package/dist/tools/groupedErrors.js +71 -0
- package/dist/tools/groupedErrors.js.map +1 -0
- package/dist/tools/impactAnalysis.d.ts +42 -0
- package/dist/tools/impactAnalysis.d.ts.map +1 -0
- package/dist/tools/impactAnalysis.js +61 -0
- package/dist/tools/impactAnalysis.js.map +1 -0
- package/dist/tools/index.d.ts +41 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +83 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/listApps.d.ts +27 -0
- package/dist/tools/listApps.d.ts.map +1 -0
- package/dist/tools/listApps.js +78 -0
- package/dist/tools/listApps.js.map +1 -0
- package/dist/tools/queryLogsJql.d.ts +44 -0
- package/dist/tools/queryLogsJql.d.ts.map +1 -0
- package/dist/tools/queryLogsJql.js +107 -0
- package/dist/tools/queryLogsJql.js.map +1 -0
- package/dist/tools/searchLogs.d.ts +60 -0
- package/dist/tools/searchLogs.d.ts.map +1 -0
- package/dist/tools/searchLogs.js +127 -0
- package/dist/tools/searchLogs.js.map +1 -0
- package/dist/tools/topErrorMessages.d.ts +42 -0
- package/dist/tools/topErrorMessages.d.ts.map +1 -0
- package/dist/tools/topErrorMessages.js +63 -0
- package/dist/tools/topErrorMessages.js.map +1 -0
- package/dist/tools/trafficStats.d.ts +39 -0
- package/dist/tools/trafficStats.d.ts.map +1 -0
- package/dist/tools/trafficStats.js +57 -0
- package/dist/tools/trafficStats.js.map +1 -0
- package/dist/tools/triageRecentCritical.d.ts +26 -0
- package/dist/tools/triageRecentCritical.d.ts.map +1 -0
- package/dist/tools/triageRecentCritical.js +81 -0
- package/dist/tools/triageRecentCritical.js.map +1 -0
- package/dist/tools/versionRegression.d.ts +29 -0
- package/dist/tools/versionRegression.d.ts.map +1 -0
- package/dist/tools/versionRegression.js +80 -0
- package/dist/tools/versionRegression.js.map +1 -0
- package/dist/transports/http-server.d.ts +25 -0
- package/dist/transports/http-server.d.ts.map +1 -0
- package/dist/transports/http-server.js +84 -0
- package/dist/transports/http-server.js.map +1 -0
- package/dist/transports/http.d.ts +71 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +315 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/stdio.d.ts +13 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +16 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ToolError } from '../lib/errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tool: version_regression
|
|
5
|
+
* Mapping: GET /analytics/version-timeline → analytics.routes.ts:373
|
|
6
|
+
* Upstream Zod: VersionTimelineSchema (from, to, +фасет-фильтры, +appVersion).
|
|
7
|
+
*
|
|
8
|
+
* Сравнивает 2 версии: новые fingerprint'ы в candidateVersion vs baselineVersion,
|
|
9
|
+
* и исчезнувшие. Upstream сам определяет версии — мы пробрасываем как
|
|
10
|
+
* `appVersion=baseline,candidate` фильтр (csv) + опционально windowDays через
|
|
11
|
+
* from/to.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_WINDOW_DAYS = 7;
|
|
14
|
+
export const versionRegressionInputShape = {
|
|
15
|
+
baselineVersion: z.string().min(1).max(64),
|
|
16
|
+
candidateVersion: z.string().min(1).max(64),
|
|
17
|
+
serviceName: z.string().max(255).optional(),
|
|
18
|
+
windowDays: z.number().int().min(1).max(30).default(DEFAULT_WINDOW_DAYS),
|
|
19
|
+
};
|
|
20
|
+
export const versionRegressionToolDef = {
|
|
21
|
+
name: 'version_regression',
|
|
22
|
+
title: 'New / disappeared fingerprints between versions',
|
|
23
|
+
description: 'Compare two appVersion releases: which fingerprints are NEW in the candidate version vs baseline, which DISAPPEARED. Use after a deploy.',
|
|
24
|
+
inputShape: versionRegressionInputShape,
|
|
25
|
+
};
|
|
26
|
+
function isoDaysAgo(days) {
|
|
27
|
+
return new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
28
|
+
}
|
|
29
|
+
export async function handleVersionRegression(args, client) {
|
|
30
|
+
try {
|
|
31
|
+
const params = {
|
|
32
|
+
from: isoDaysAgo(args.windowDays),
|
|
33
|
+
to: new Date().toISOString(),
|
|
34
|
+
appVersion: `${args.baselineVersion},${args.candidateVersion}`,
|
|
35
|
+
serviceName: args.serviceName,
|
|
36
|
+
};
|
|
37
|
+
const { data, elsRequestId } = await client.versionRegression(params);
|
|
38
|
+
const body = (data ?? {});
|
|
39
|
+
// Upstream может вернуть несколько форм; нормализуем.
|
|
40
|
+
const baseline = body.baseline ?? {
|
|
41
|
+
version: args.baselineVersion,
|
|
42
|
+
errors: 0,
|
|
43
|
+
uniqueFingerprints: 0,
|
|
44
|
+
};
|
|
45
|
+
const candidate = body.candidate ?? {
|
|
46
|
+
version: args.candidateVersion,
|
|
47
|
+
errors: 0,
|
|
48
|
+
uniqueFingerprints: 0,
|
|
49
|
+
};
|
|
50
|
+
const newFingerprints = Array.isArray(body.newFingerprints) ? body.newFingerprints : [];
|
|
51
|
+
const disappeared = Array.isArray(body.disappeared) ? body.disappeared : [];
|
|
52
|
+
const meta = {
|
|
53
|
+
elsRequestId,
|
|
54
|
+
cached: false,
|
|
55
|
+
ttlSec: 120,
|
|
56
|
+
redactionApplied: false,
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
structuredContent: {
|
|
60
|
+
baseline,
|
|
61
|
+
candidate,
|
|
62
|
+
newFingerprints,
|
|
63
|
+
disappeared,
|
|
64
|
+
_meta: meta,
|
|
65
|
+
},
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: `Regression check ${args.baselineVersion} → ${args.candidateVersion}: ${newFingerprints.length} new, ${disappeared.length} disappeared.`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (err instanceof ToolError)
|
|
76
|
+
return err.toToolResult();
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=versionRegression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versionRegression.js","sourceRoot":"","sources":["../../src/tools/versionRegression.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Server } from 'node:http';
|
|
2
|
+
import type { Logger } from 'pino';
|
|
3
|
+
import type { Config } from '../config.js';
|
|
4
|
+
import { HttpTransportManager } from './http.js';
|
|
5
|
+
import { RedisService } from '../cache/redis.js';
|
|
6
|
+
/**
|
|
7
|
+
* Запускает HTTP transport: создаёт Express app, начинает listen на
|
|
8
|
+
* configured port. Возвращает handle с close()-методом для graceful shutdown.
|
|
9
|
+
*
|
|
10
|
+
* Phase 6 wire-up:
|
|
11
|
+
* - Redis (если cacheEnabled && redisUrl) — для CachedElsClient + readyz + DCR rl
|
|
12
|
+
* - Audit/Usage trackers — для withMiddleware
|
|
13
|
+
* - Middleware deps пробрасываются в HttpTransportManager
|
|
14
|
+
*/
|
|
15
|
+
export interface HttpServerHandle {
|
|
16
|
+
server: Server;
|
|
17
|
+
manager: HttpTransportManager;
|
|
18
|
+
redis: RedisService | null;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare function startHttpServer(opts: {
|
|
22
|
+
config: Config;
|
|
23
|
+
log: Logger;
|
|
24
|
+
}): Promise<HttpServerHandle>;
|
|
25
|
+
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/transports/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWjD;;;;;;;;GAQG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuF5B"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHttpApp } from '../http/app.js';
|
|
2
|
+
import { ElsClient } from '../elsClient.js';
|
|
3
|
+
import { HttpTransportManager } from './http.js';
|
|
4
|
+
import { RedisService } from '../cache/redis.js';
|
|
5
|
+
import { createAuditService, setAuditServiceForTests, } from '../audit/service.js';
|
|
6
|
+
import { createUsageTracker, setUsageTrackerForTests, } from '../billing/tracker.js';
|
|
7
|
+
export async function startHttpServer(opts) {
|
|
8
|
+
const { config, log } = opts;
|
|
9
|
+
// Probe-client для /readyz — использует master/ELS_API_KEY если задан.
|
|
10
|
+
let probeClient;
|
|
11
|
+
if (config.elsApiKey) {
|
|
12
|
+
probeClient = new ElsClient({
|
|
13
|
+
baseUrl: config.elsBaseUrl,
|
|
14
|
+
apiKey: config.elsApiKey,
|
|
15
|
+
timeoutMs: 5000,
|
|
16
|
+
log,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// Phase 6: Redis для cache layer + readyz + DCR rate-limit.
|
|
20
|
+
let redis = null;
|
|
21
|
+
if (config.cacheEnabled && config.redisUrl) {
|
|
22
|
+
redis = new RedisService({ url: config.redisUrl, log });
|
|
23
|
+
}
|
|
24
|
+
// Phase 6: audit + usage. Singletons заменяются на real instances.
|
|
25
|
+
const audit = createAuditService({
|
|
26
|
+
...(config.mcpDatabaseUrl ? { databaseUrl: config.mcpDatabaseUrl } : {}),
|
|
27
|
+
log,
|
|
28
|
+
});
|
|
29
|
+
setAuditServiceForTests(audit);
|
|
30
|
+
const usage = createUsageTracker({
|
|
31
|
+
...(config.mcpDatabaseUrl ? { databaseUrl: config.mcpDatabaseUrl } : {}),
|
|
32
|
+
log,
|
|
33
|
+
});
|
|
34
|
+
setUsageTrackerForTests(usage);
|
|
35
|
+
const middlewareDeps = {
|
|
36
|
+
audit,
|
|
37
|
+
usage,
|
|
38
|
+
redactionConfig: {
|
|
39
|
+
enabled: config.redactionEnabled,
|
|
40
|
+
...(config.redactionFields.length > 0
|
|
41
|
+
? { fields: new Set(config.redactionFields) }
|
|
42
|
+
: {}),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const manager = new HttpTransportManager({
|
|
46
|
+
config,
|
|
47
|
+
log,
|
|
48
|
+
redis,
|
|
49
|
+
middlewareDeps,
|
|
50
|
+
});
|
|
51
|
+
const { app } = createHttpApp({
|
|
52
|
+
config,
|
|
53
|
+
log,
|
|
54
|
+
transportManager: manager,
|
|
55
|
+
...(probeClient ? { probeElsClient: probeClient } : {}),
|
|
56
|
+
redis,
|
|
57
|
+
middlewareDeps,
|
|
58
|
+
});
|
|
59
|
+
const server = await new Promise((resolve, reject) => {
|
|
60
|
+
const s = app.listen(config.httpPort, () => resolve(s));
|
|
61
|
+
s.on('error', reject);
|
|
62
|
+
});
|
|
63
|
+
log.info({
|
|
64
|
+
port: config.httpPort,
|
|
65
|
+
publicUrl: config.publicUrl,
|
|
66
|
+
cacheEnabled: config.cacheEnabled && !!redis,
|
|
67
|
+
metricsEnabled: config.metricsEnabled,
|
|
68
|
+
}, 'HTTP transport listening');
|
|
69
|
+
return {
|
|
70
|
+
server,
|
|
71
|
+
manager,
|
|
72
|
+
redis,
|
|
73
|
+
async close() {
|
|
74
|
+
log.info('Shutting down HTTP transport');
|
|
75
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
76
|
+
await manager.close();
|
|
77
|
+
if (probeClient)
|
|
78
|
+
await probeClient.close();
|
|
79
|
+
if (redis)
|
|
80
|
+
await redis.close();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=http-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../../src/transports/http-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import type { Logger } from 'pino';
|
|
3
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import type { Config } from '../config.js';
|
|
6
|
+
import { ElsClient } from '../elsClient.js';
|
|
7
|
+
import type { RequestContext } from '../http/types.js';
|
|
8
|
+
import { type RedisService } from '../cache/index.js';
|
|
9
|
+
import { type Tier } from '../billing/limits.js';
|
|
10
|
+
import type { MiddlewareDeps } from '../middleware/withMiddleware.js';
|
|
11
|
+
export interface SessionRecord {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
transport: StreamableHTTPServerTransport;
|
|
14
|
+
server: McpServer;
|
|
15
|
+
client: ElsClient;
|
|
16
|
+
/** Контекст последнего запроса (snapshot — для observability). */
|
|
17
|
+
lastContext?: RequestContext;
|
|
18
|
+
createdAt: number;
|
|
19
|
+
lastTouchedAt: number;
|
|
20
|
+
/** AppSlug сессии (для concurrency-limit и SSE-метрик). */
|
|
21
|
+
appSlug: string;
|
|
22
|
+
}
|
|
23
|
+
export interface HttpTransportManagerOptions {
|
|
24
|
+
config: Config;
|
|
25
|
+
log: Logger;
|
|
26
|
+
/** TTL idle-сессии, мс. Default 30 минут. */
|
|
27
|
+
sessionTtlMs?: number;
|
|
28
|
+
/** Disable internal cleanup timer (для тестов). */
|
|
29
|
+
noCleanup?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Phase 6: Redis для cache layer. Если задан и cacheEnabled — каждая сессия
|
|
32
|
+
* получает CachedElsClient. Иначе — прямой ElsClient.
|
|
33
|
+
*/
|
|
34
|
+
redis?: RedisService | null;
|
|
35
|
+
/** Phase 6: middleware deps (audit / usage / redaction). */
|
|
36
|
+
middlewareDeps?: MiddlewareDeps;
|
|
37
|
+
/** Tier resolver — приходит из LK (Phase 7+). По умолчанию config.defaultTier. */
|
|
38
|
+
tierResolver?: (ctx: RequestContext) => Tier;
|
|
39
|
+
}
|
|
40
|
+
export declare class HttpTransportManager {
|
|
41
|
+
private readonly sessions;
|
|
42
|
+
/** Per-app счётчик active sessions (для concurrency-limit). */
|
|
43
|
+
private readonly perAppCount;
|
|
44
|
+
private readonly ttlMs;
|
|
45
|
+
private readonly cleanupTimer;
|
|
46
|
+
private readonly config;
|
|
47
|
+
private readonly log;
|
|
48
|
+
private readonly redis;
|
|
49
|
+
private readonly cachePolicies;
|
|
50
|
+
private readonly middlewareDeps;
|
|
51
|
+
private readonly tierResolver;
|
|
52
|
+
constructor(opts: HttpTransportManagerOptions);
|
|
53
|
+
/** Closes all sessions and stops cleanup. Безопасно вызывать многократно. */
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Express handler для `POST /mcp`. Решает, создавать ли новую сессию
|
|
57
|
+
* (если нет `Mcp-Session-Id` И тело — initialize) или использовать
|
|
58
|
+
* существующую.
|
|
59
|
+
*/
|
|
60
|
+
handleRequest(req: Request, res: Response): Promise<void>;
|
|
61
|
+
private createSession;
|
|
62
|
+
private incrPerApp;
|
|
63
|
+
private decrPerApp;
|
|
64
|
+
/** Для тестов: текущее число sessions per app. */
|
|
65
|
+
perAppSize(appSlug: string): number;
|
|
66
|
+
private touch;
|
|
67
|
+
private gcExpired;
|
|
68
|
+
/** Для тестов / observability. */
|
|
69
|
+
size(): number;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAoBnF,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,6BAA6B,CAAC;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,kFAAkF;IAClF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;CAC9C;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IACnE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;gBAEjD,IAAI,EAAE,2BAA2B;IAiB7C,6EAA6E;IACvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B5B;;;;OAIG;IACG,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAyEjD,aAAa;IAiH3B,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,UAAU;IASlB,kDAAkD;IAClD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAInC,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,SAAS;IAuBjB,kCAAkC;IAClC,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
+
import { createMcpServer } from '../server.js';
|
|
4
|
+
import { ElsClient } from '../elsClient.js';
|
|
5
|
+
import { CachedElsClient, CacheService, resolvePolicies, } from '../cache/index.js';
|
|
6
|
+
import { decSseActive, incSseActive, recordSseRejection, } from '../observability/metrics.js';
|
|
7
|
+
import { TIER_LIMITS } from '../billing/limits.js';
|
|
8
|
+
/**
|
|
9
|
+
* Streamable HTTP transport (Phase 3, in-memory sessions).
|
|
10
|
+
*
|
|
11
|
+
* Каждый клиент создаёт сессию через первый `initialize`-запрос. После этого
|
|
12
|
+
* `Mcp-Session-Id` header связывает запросы с конкретной парой
|
|
13
|
+
* (McpServer + StreamableHTTPServerTransport).
|
|
14
|
+
*
|
|
15
|
+
* Sessions хранятся в Map (in-memory). TTL — 30 минут idle. На каждый запрос
|
|
16
|
+
* сессия "touch'ается" (продлевается). В Phase 4 будет Redis (см. 02-transports.md §4.3).
|
|
17
|
+
*
|
|
18
|
+
* Resumability через `Last-Event-ID` поддерживается SDK 1.x — нам ничего
|
|
19
|
+
* специально делать не нужно (но `EventStore` пока не подключаем —
|
|
20
|
+
* `streaming: true` tools'ов в Phase 3 нет, все 8 tools — non-streaming).
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 минут
|
|
23
|
+
const CLEANUP_INTERVAL_MS = 60 * 1000; // 1 минута
|
|
24
|
+
export class HttpTransportManager {
|
|
25
|
+
sessions = new Map();
|
|
26
|
+
/** Per-app счётчик active sessions (для concurrency-limit). */
|
|
27
|
+
perAppCount = new Map();
|
|
28
|
+
ttlMs;
|
|
29
|
+
cleanupTimer = null;
|
|
30
|
+
config;
|
|
31
|
+
log;
|
|
32
|
+
redis;
|
|
33
|
+
cachePolicies;
|
|
34
|
+
middlewareDeps;
|
|
35
|
+
tierResolver;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
this.config = opts.config;
|
|
38
|
+
this.log = opts.log;
|
|
39
|
+
this.ttlMs = opts.sessionTtlMs ?? DEFAULT_TTL_MS;
|
|
40
|
+
this.redis = opts.redis ?? null;
|
|
41
|
+
this.cachePolicies = resolvePolicies(opts.config.cacheTtlOverrides);
|
|
42
|
+
this.middlewareDeps = opts.middlewareDeps ?? {};
|
|
43
|
+
this.tierResolver =
|
|
44
|
+
opts.tierResolver ?? (() => opts.config.defaultTier);
|
|
45
|
+
if (!opts.noCleanup) {
|
|
46
|
+
this.cleanupTimer = setInterval(() => this.gcExpired(), CLEANUP_INTERVAL_MS);
|
|
47
|
+
// Don't block process exit on this timer.
|
|
48
|
+
this.cleanupTimer.unref?.();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Closes all sessions and stops cleanup. Безопасно вызывать многократно. */
|
|
52
|
+
async close() {
|
|
53
|
+
if (this.cleanupTimer)
|
|
54
|
+
clearInterval(this.cleanupTimer);
|
|
55
|
+
const sessions = Array.from(this.sessions.values());
|
|
56
|
+
this.sessions.clear();
|
|
57
|
+
this.perAppCount.clear();
|
|
58
|
+
for (const rec of sessions) {
|
|
59
|
+
try {
|
|
60
|
+
await rec.transport.close();
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
this.log.warn({ err: errMsg(err), sessionId: rec.sessionId }, 'transport.close failed');
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
await rec.server.close();
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
this.log.warn({ err: errMsg(err), sessionId: rec.sessionId }, 'server.close failed');
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await rec.client.close();
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
this.log.warn({ err: errMsg(err), sessionId: rec.sessionId }, 'client.close failed');
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
decSseActive(rec.appSlug || 'unknown');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// ignore
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Express handler для `POST /mcp`. Решает, создавать ли новую сессию
|
|
87
|
+
* (если нет `Mcp-Session-Id` И тело — initialize) или использовать
|
|
88
|
+
* существующую.
|
|
89
|
+
*/
|
|
90
|
+
async handleRequest(req, res) {
|
|
91
|
+
const ctx = req.context;
|
|
92
|
+
if (!ctx) {
|
|
93
|
+
// Auth middleware должен был отработать раньше — fail-safe.
|
|
94
|
+
res.status(401).json({ error: 'unauthorized' });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const incomingSid = pickSessionIdHeader(req);
|
|
98
|
+
const body = req.body;
|
|
99
|
+
const isInit = isInitializeRequest(body);
|
|
100
|
+
let rec;
|
|
101
|
+
if (incomingSid) {
|
|
102
|
+
rec = this.sessions.get(incomingSid);
|
|
103
|
+
if (!rec) {
|
|
104
|
+
// 404 как в SDK semantics: клиенту нужно reinit
|
|
105
|
+
res.status(404).json({ error: 'session_not_found', sessionId: incomingSid });
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.touch(rec);
|
|
109
|
+
}
|
|
110
|
+
else if (isInit) {
|
|
111
|
+
// Phase 6: concurrency limit per tier+appSlug.
|
|
112
|
+
const tier = this.tierResolver(ctx);
|
|
113
|
+
const appSlug = ctx.appSlug || 'unknown';
|
|
114
|
+
const limit = TIER_LIMITS[tier]?.concurrentSse ?? Number.POSITIVE_INFINITY;
|
|
115
|
+
const current = this.perAppCount.get(appSlug) ?? 0;
|
|
116
|
+
if (current >= limit) {
|
|
117
|
+
recordSseRejection('concurrency_exceeded', appSlug);
|
|
118
|
+
this.log.warn({ appSlug, tier, current, limit, requestId: ctx.requestId }, 'SSE session-create rejected: concurrency limit exceeded');
|
|
119
|
+
res.setHeader('X-RateLimit-Concurrent-Exceeded', 'true');
|
|
120
|
+
res.setHeader('X-RateLimit-Concurrent-Limit', String(limit));
|
|
121
|
+
res.status(429).json({
|
|
122
|
+
error: 'concurrency_limit_exceeded',
|
|
123
|
+
error_description: `Maximum ${limit} concurrent SSE sessions for tier ${tier}`,
|
|
124
|
+
tier,
|
|
125
|
+
limit,
|
|
126
|
+
});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
rec = await this.createSession(ctx);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// нет сессии и не initialize → 400
|
|
133
|
+
res.status(400).json({
|
|
134
|
+
error: 'missing_session_id',
|
|
135
|
+
error_description: 'Mcp-Session-Id header required for non-initialize requests',
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Обновим snapshot контекста на каждом запросе (полезно для логов).
|
|
140
|
+
rec.lastContext = ctx;
|
|
141
|
+
try {
|
|
142
|
+
await rec.transport.handleRequest(req, res, body);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
this.log.error({ err: errMsg(err), sessionId: rec.sessionId, requestId: ctx.requestId }, 'StreamableHTTP transport.handleRequest threw');
|
|
146
|
+
if (!res.headersSent) {
|
|
147
|
+
res.status(500).json({ error: 'internal', requestId: ctx.requestId });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ─── private ──────────────────────────────────────────────────────────
|
|
152
|
+
async createSession(ctx) {
|
|
153
|
+
const sessionId = randomUUID();
|
|
154
|
+
// Каждая сессия получает свой ElsClient: для ELS-key path передаём
|
|
155
|
+
// ключ запроса, для OIDC — используем глобальный (master) ELS_API_KEY
|
|
156
|
+
// если задан (TODO Phase 4: per-tenant credentials через LK).
|
|
157
|
+
const apiKey = ctx.authMethod === 'els-key' && ctx.elsApiKey
|
|
158
|
+
? ctx.elsApiKey
|
|
159
|
+
: this.config.elsApiKey;
|
|
160
|
+
const baseClient = new ElsClient({
|
|
161
|
+
baseUrl: this.config.elsBaseUrl,
|
|
162
|
+
apiKey,
|
|
163
|
+
timeoutMs: this.config.upstreamTimeoutMs,
|
|
164
|
+
log: this.log,
|
|
165
|
+
});
|
|
166
|
+
// Phase 6: если включён cache и Redis доступен — оборачиваем в CachedElsClient.
|
|
167
|
+
// Сам CachedElsClient gracefully fallback'ит на baseClient при недоступном Redis.
|
|
168
|
+
let toolClient = baseClient;
|
|
169
|
+
if (this.config.cacheEnabled && this.redis) {
|
|
170
|
+
const cacheService = new CacheService({ redis: this.redis, log: this.log });
|
|
171
|
+
const cached = new CachedElsClient(baseClient, cacheService, this.cachePolicies, this.log);
|
|
172
|
+
// CachedElsClient повторяет сигнатуру ElsClient — приводим к этому типу
|
|
173
|
+
// для совместимости с registerTools / handlers (которые знают только ElsClient).
|
|
174
|
+
toolClient = cached;
|
|
175
|
+
}
|
|
176
|
+
// Phase 6: contextProvider — каждый tool-call получает актуальный ctx
|
|
177
|
+
// (с appSlug / keyId / tier / ip / userAgent / sessionId).
|
|
178
|
+
const session = {
|
|
179
|
+
lastCtx: ctx,
|
|
180
|
+
sessionId,
|
|
181
|
+
};
|
|
182
|
+
const contextProvider = () => {
|
|
183
|
+
const cur = session.lastCtx;
|
|
184
|
+
const tier = this.tierResolver(cur);
|
|
185
|
+
return {
|
|
186
|
+
appId: cur.appSlug || this.config.defaultAppId,
|
|
187
|
+
keyId: cur.keyId,
|
|
188
|
+
tier,
|
|
189
|
+
log: this.log,
|
|
190
|
+
ip: cur.ip || null,
|
|
191
|
+
userAgent: cur.userAgent || null,
|
|
192
|
+
sessionId: cur.sessionId ?? session.sessionId,
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
const { server } = createMcpServer({
|
|
196
|
+
config: { ...this.config, elsApiKey: apiKey },
|
|
197
|
+
log: this.log,
|
|
198
|
+
client: toolClient,
|
|
199
|
+
contextProvider,
|
|
200
|
+
middleware: this.middlewareDeps,
|
|
201
|
+
});
|
|
202
|
+
const appSlug = ctx.appSlug || 'unknown';
|
|
203
|
+
const transport = new StreamableHTTPServerTransport({
|
|
204
|
+
sessionIdGenerator: () => sessionId,
|
|
205
|
+
onsessionclosed: (sid) => {
|
|
206
|
+
this.log.info({ sessionId: sid, appSlug }, 'MCP session closed (DELETE)');
|
|
207
|
+
const rec = this.sessions.get(sid);
|
|
208
|
+
if (rec) {
|
|
209
|
+
this.sessions.delete(sid);
|
|
210
|
+
this.decrPerApp(rec.appSlug);
|
|
211
|
+
try {
|
|
212
|
+
decSseActive(rec.appSlug || 'unknown');
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// ignore
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
await server.connect(transport);
|
|
221
|
+
const rec = {
|
|
222
|
+
sessionId,
|
|
223
|
+
transport,
|
|
224
|
+
server,
|
|
225
|
+
client: baseClient, // close() освобождает undici pool
|
|
226
|
+
lastContext: ctx,
|
|
227
|
+
createdAt: Date.now(),
|
|
228
|
+
lastTouchedAt: Date.now(),
|
|
229
|
+
appSlug,
|
|
230
|
+
};
|
|
231
|
+
this.sessions.set(sessionId, rec);
|
|
232
|
+
this.incrPerApp(appSlug);
|
|
233
|
+
try {
|
|
234
|
+
incSseActive(appSlug);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// ignore
|
|
238
|
+
}
|
|
239
|
+
this.log.info({
|
|
240
|
+
sessionId,
|
|
241
|
+
authMethod: ctx.authMethod,
|
|
242
|
+
keyId: ctx.keyId,
|
|
243
|
+
appSlug,
|
|
244
|
+
cacheEnabled: this.config.cacheEnabled && !!this.redis,
|
|
245
|
+
}, 'MCP session created');
|
|
246
|
+
return rec;
|
|
247
|
+
}
|
|
248
|
+
incrPerApp(appSlug) {
|
|
249
|
+
this.perAppCount.set(appSlug, (this.perAppCount.get(appSlug) ?? 0) + 1);
|
|
250
|
+
}
|
|
251
|
+
decrPerApp(appSlug) {
|
|
252
|
+
const cur = this.perAppCount.get(appSlug) ?? 0;
|
|
253
|
+
if (cur <= 1) {
|
|
254
|
+
this.perAppCount.delete(appSlug);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
this.perAppCount.set(appSlug, cur - 1);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/** Для тестов: текущее число sessions per app. */
|
|
261
|
+
perAppSize(appSlug) {
|
|
262
|
+
return this.perAppCount.get(appSlug) ?? 0;
|
|
263
|
+
}
|
|
264
|
+
touch(rec) {
|
|
265
|
+
rec.lastTouchedAt = Date.now();
|
|
266
|
+
}
|
|
267
|
+
gcExpired() {
|
|
268
|
+
const now = Date.now();
|
|
269
|
+
let removed = 0;
|
|
270
|
+
for (const [sid, rec] of this.sessions) {
|
|
271
|
+
if (now - rec.lastTouchedAt > this.ttlMs) {
|
|
272
|
+
this.sessions.delete(sid);
|
|
273
|
+
this.decrPerApp(rec.appSlug);
|
|
274
|
+
try {
|
|
275
|
+
decSseActive(rec.appSlug || 'unknown');
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// ignore
|
|
279
|
+
}
|
|
280
|
+
rec.transport.close().catch(() => undefined);
|
|
281
|
+
rec.server.close().catch(() => undefined);
|
|
282
|
+
rec.client.close().catch(() => undefined);
|
|
283
|
+
removed += 1;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (removed > 0) {
|
|
287
|
+
this.log.info({ removed, alive: this.sessions.size }, 'MCP session GC ran');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** Для тестов / observability. */
|
|
291
|
+
size() {
|
|
292
|
+
return this.sessions.size;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function pickSessionIdHeader(req) {
|
|
296
|
+
const v = req.headers['mcp-session-id'];
|
|
297
|
+
if (typeof v === 'string' && v.length > 0)
|
|
298
|
+
return v;
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
function isInitializeRequest(body) {
|
|
302
|
+
if (!body)
|
|
303
|
+
return false;
|
|
304
|
+
if (Array.isArray(body)) {
|
|
305
|
+
return body.some((m) => isInitializeRequest(m));
|
|
306
|
+
}
|
|
307
|
+
if (typeof body !== 'object')
|
|
308
|
+
return false;
|
|
309
|
+
const obj = body;
|
|
310
|
+
return obj.method === 'initialize';
|
|
311
|
+
}
|
|
312
|
+
function errMsg(err) {
|
|
313
|
+
return err instanceof Error ? err.message : String(err);
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
/**
|
|
4
|
+
* Создаёт и подключает stdio-транспорт к MCP-серверу.
|
|
5
|
+
*
|
|
6
|
+
* Это default-транспорт для локальных LLM-клиентов (Claude Desktop,
|
|
7
|
+
* mcp-inspector). HTTP transport — Phase 3.
|
|
8
|
+
*
|
|
9
|
+
* Важно: при работе в stdio все stdout-байты должны быть валидным JSON-RPC.
|
|
10
|
+
* Pino должен писать в stderr (см. server.ts).
|
|
11
|
+
*/
|
|
12
|
+
export declare function connectStdio(server: McpServer): Promise<StdioServerTransport>;
|
|
13
|
+
//# sourceMappingURL=stdio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAInF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
/**
|
|
3
|
+
* Создаёт и подключает stdio-транспорт к MCP-серверу.
|
|
4
|
+
*
|
|
5
|
+
* Это default-транспорт для локальных LLM-клиентов (Claude Desktop,
|
|
6
|
+
* mcp-inspector). HTTP transport — Phase 3.
|
|
7
|
+
*
|
|
8
|
+
* Важно: при работе в stdio все stdout-байты должны быть валидным JSON-RPC.
|
|
9
|
+
* Pino должен писать в stderr (см. server.ts).
|
|
10
|
+
*/
|
|
11
|
+
export async function connectStdio(server) {
|
|
12
|
+
const transport = new StdioServerTransport();
|
|
13
|
+
await server.connect(transport);
|
|
14
|
+
return transport;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAiB;IAClD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,SAAS,CAAC;AACnB,CAAC"}
|