@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.
Files changed (266) hide show
  1. package/README.md +482 -0
  2. package/dist/audit/prisma.d.ts +67 -0
  3. package/dist/audit/prisma.d.ts.map +1 -0
  4. package/dist/audit/prisma.js +65 -0
  5. package/dist/audit/prisma.js.map +1 -0
  6. package/dist/audit/service.d.ts +72 -0
  7. package/dist/audit/service.d.ts.map +1 -0
  8. package/dist/audit/service.js +137 -0
  9. package/dist/audit/service.js.map +1 -0
  10. package/dist/billing/limits.d.ts +34 -0
  11. package/dist/billing/limits.d.ts.map +1 -0
  12. package/dist/billing/limits.js +51 -0
  13. package/dist/billing/limits.js.map +1 -0
  14. package/dist/billing/tracker.d.ts +39 -0
  15. package/dist/billing/tracker.d.ts.map +1 -0
  16. package/dist/billing/tracker.js +92 -0
  17. package/dist/billing/tracker.js.map +1 -0
  18. package/dist/cache/cachedElsClient.d.ts +71 -0
  19. package/dist/cache/cachedElsClient.d.ts.map +1 -0
  20. package/dist/cache/cachedElsClient.js +167 -0
  21. package/dist/cache/cachedElsClient.js.map +1 -0
  22. package/dist/cache/index.d.ts +10 -0
  23. package/dist/cache/index.d.ts.map +1 -0
  24. package/dist/cache/index.js +6 -0
  25. package/dist/cache/index.js.map +1 -0
  26. package/dist/cache/policies.d.ts +60 -0
  27. package/dist/cache/policies.d.ts.map +1 -0
  28. package/dist/cache/policies.js +90 -0
  29. package/dist/cache/policies.js.map +1 -0
  30. package/dist/cache/redis.d.ts +52 -0
  31. package/dist/cache/redis.d.ts.map +1 -0
  32. package/dist/cache/redis.js +134 -0
  33. package/dist/cache/redis.js.map +1 -0
  34. package/dist/cache/types.d.ts +32 -0
  35. package/dist/cache/types.d.ts.map +1 -0
  36. package/dist/cache/types.js +32 -0
  37. package/dist/cache/types.js.map +1 -0
  38. package/dist/cache/wrapper.d.ts +38 -0
  39. package/dist/cache/wrapper.d.ts.map +1 -0
  40. package/dist/cache/wrapper.js +109 -0
  41. package/dist/cache/wrapper.js.map +1 -0
  42. package/dist/cli.d.ts +3 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +86 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/config.d.ts +105 -0
  47. package/dist/config.d.ts.map +1 -0
  48. package/dist/config.js +211 -0
  49. package/dist/config.js.map +1 -0
  50. package/dist/elsClient.d.ts +137 -0
  51. package/dist/elsClient.d.ts.map +1 -0
  52. package/dist/elsClient.js +285 -0
  53. package/dist/elsClient.js.map +1 -0
  54. package/dist/http/app.d.ts +40 -0
  55. package/dist/http/app.d.ts.map +1 -0
  56. package/dist/http/app.js +135 -0
  57. package/dist/http/app.js.map +1 -0
  58. package/dist/http/jwks.d.ts +8 -0
  59. package/dist/http/jwks.d.ts.map +1 -0
  60. package/dist/http/jwks.js +34 -0
  61. package/dist/http/jwks.js.map +1 -0
  62. package/dist/http/middleware/auth.d.ts +11 -0
  63. package/dist/http/middleware/auth.d.ts.map +1 -0
  64. package/dist/http/middleware/auth.js +225 -0
  65. package/dist/http/middleware/auth.js.map +1 -0
  66. package/dist/http/middleware/dcrRateLimit.d.ts +29 -0
  67. package/dist/http/middleware/dcrRateLimit.d.ts.map +1 -0
  68. package/dist/http/middleware/dcrRateLimit.js +59 -0
  69. package/dist/http/middleware/dcrRateLimit.js.map +1 -0
  70. package/dist/http/middleware/errorHandler.d.ts +12 -0
  71. package/dist/http/middleware/errorHandler.d.ts.map +1 -0
  72. package/dist/http/middleware/errorHandler.js +26 -0
  73. package/dist/http/middleware/errorHandler.js.map +1 -0
  74. package/dist/http/middleware/originGuard.d.ts +28 -0
  75. package/dist/http/middleware/originGuard.d.ts.map +1 -0
  76. package/dist/http/middleware/originGuard.js +55 -0
  77. package/dist/http/middleware/originGuard.js.map +1 -0
  78. package/dist/http/middleware/requestId.d.ts +19 -0
  79. package/dist/http/middleware/requestId.d.ts.map +1 -0
  80. package/dist/http/middleware/requestId.js +23 -0
  81. package/dist/http/middleware/requestId.js.map +1 -0
  82. package/dist/http/routes/health.d.ts +24 -0
  83. package/dist/http/routes/health.d.ts.map +1 -0
  84. package/dist/http/routes/health.js +73 -0
  85. package/dist/http/routes/health.js.map +1 -0
  86. package/dist/http/routes/metrics.d.ts +18 -0
  87. package/dist/http/routes/metrics.d.ts.map +1 -0
  88. package/dist/http/routes/metrics.js +42 -0
  89. package/dist/http/routes/metrics.js.map +1 -0
  90. package/dist/http/routes/wellKnown.d.ts +15 -0
  91. package/dist/http/routes/wellKnown.d.ts.map +1 -0
  92. package/dist/http/routes/wellKnown.js +43 -0
  93. package/dist/http/routes/wellKnown.js.map +1 -0
  94. package/dist/http/types.d.ts +40 -0
  95. package/dist/http/types.d.ts.map +1 -0
  96. package/dist/http/types.js +9 -0
  97. package/dist/http/types.js.map +1 -0
  98. package/dist/instrumentation.d.ts +22 -0
  99. package/dist/instrumentation.d.ts.map +1 -0
  100. package/dist/instrumentation.js +38 -0
  101. package/dist/instrumentation.js.map +1 -0
  102. package/dist/lib/cursor.d.ts +22 -0
  103. package/dist/lib/cursor.d.ts.map +1 -0
  104. package/dist/lib/cursor.js +95 -0
  105. package/dist/lib/cursor.js.map +1 -0
  106. package/dist/lib/errors.d.ts +49 -0
  107. package/dist/lib/errors.d.ts.map +1 -0
  108. package/dist/lib/errors.js +83 -0
  109. package/dist/lib/errors.js.map +1 -0
  110. package/dist/lib/responseFormat.d.ts +14 -0
  111. package/dist/lib/responseFormat.d.ts.map +1 -0
  112. package/dist/lib/responseFormat.js +74 -0
  113. package/dist/lib/responseFormat.js.map +1 -0
  114. package/dist/middleware/withMiddleware.d.ts +53 -0
  115. package/dist/middleware/withMiddleware.d.ts.map +1 -0
  116. package/dist/middleware/withMiddleware.js +190 -0
  117. package/dist/middleware/withMiddleware.js.map +1 -0
  118. package/dist/observability/health.d.ts +51 -0
  119. package/dist/observability/health.d.ts.map +1 -0
  120. package/dist/observability/health.js +77 -0
  121. package/dist/observability/health.js.map +1 -0
  122. package/dist/observability/index.d.ts +8 -0
  123. package/dist/observability/index.d.ts.map +1 -0
  124. package/dist/observability/index.js +5 -0
  125. package/dist/observability/index.js.map +1 -0
  126. package/dist/observability/logger.d.ts +45 -0
  127. package/dist/observability/logger.d.ts.map +1 -0
  128. package/dist/observability/logger.js +75 -0
  129. package/dist/observability/logger.js.map +1 -0
  130. package/dist/observability/metrics.d.ts +49 -0
  131. package/dist/observability/metrics.d.ts.map +1 -0
  132. package/dist/observability/metrics.js +184 -0
  133. package/dist/observability/metrics.js.map +1 -0
  134. package/dist/observability/tracing.d.ts +28 -0
  135. package/dist/observability/tracing.d.ts.map +1 -0
  136. package/dist/observability/tracing.js +56 -0
  137. package/dist/observability/tracing.js.map +1 -0
  138. package/dist/prompts/index.d.ts +20 -0
  139. package/dist/prompts/index.d.ts.map +1 -0
  140. package/dist/prompts/index.js +202 -0
  141. package/dist/prompts/index.js.map +1 -0
  142. package/dist/redaction/argsRedactor.d.ts +22 -0
  143. package/dist/redaction/argsRedactor.d.ts.map +1 -0
  144. package/dist/redaction/argsRedactor.js +97 -0
  145. package/dist/redaction/argsRedactor.js.map +1 -0
  146. package/dist/redaction/fields.d.ts +64 -0
  147. package/dist/redaction/fields.d.ts.map +1 -0
  148. package/dist/redaction/fields.js +155 -0
  149. package/dist/redaction/fields.js.map +1 -0
  150. package/dist/redaction/index.d.ts +52 -0
  151. package/dist/redaction/index.d.ts.map +1 -0
  152. package/dist/redaction/index.js +160 -0
  153. package/dist/redaction/index.js.map +1 -0
  154. package/dist/redaction/promptInjection.d.ts +32 -0
  155. package/dist/redaction/promptInjection.d.ts.map +1 -0
  156. package/dist/redaction/promptInjection.js +68 -0
  157. package/dist/redaction/promptInjection.js.map +1 -0
  158. package/dist/redaction/url.d.ts +8 -0
  159. package/dist/redaction/url.d.ts.map +1 -0
  160. package/dist/redaction/url.js +26 -0
  161. package/dist/redaction/url.js.map +1 -0
  162. package/dist/redaction/userAgent.d.ts +9 -0
  163. package/dist/redaction/userAgent.d.ts.map +1 -0
  164. package/dist/redaction/userAgent.js +39 -0
  165. package/dist/redaction/userAgent.js.map +1 -0
  166. package/dist/resources/index.d.ts +24 -0
  167. package/dist/resources/index.d.ts.map +1 -0
  168. package/dist/resources/index.js +150 -0
  169. package/dist/resources/index.js.map +1 -0
  170. package/dist/server.d.ts +37 -0
  171. package/dist/server.d.ts.map +1 -0
  172. package/dist/server.js +35 -0
  173. package/dist/server.js.map +1 -0
  174. package/dist/tools/baselineCompare.d.ts +36 -0
  175. package/dist/tools/baselineCompare.d.ts.map +1 -0
  176. package/dist/tools/baselineCompare.js +69 -0
  177. package/dist/tools/baselineCompare.js.map +1 -0
  178. package/dist/tools/errorHeatmap.d.ts +40 -0
  179. package/dist/tools/errorHeatmap.d.ts.map +1 -0
  180. package/dist/tools/errorHeatmap.js +69 -0
  181. package/dist/tools/errorHeatmap.js.map +1 -0
  182. package/dist/tools/errorHistogram.d.ts +39 -0
  183. package/dist/tools/errorHistogram.d.ts.map +1 -0
  184. package/dist/tools/errorHistogram.js +61 -0
  185. package/dist/tools/errorHistogram.js.map +1 -0
  186. package/dist/tools/errorStatsBreakdown.d.ts +43 -0
  187. package/dist/tools/errorStatsBreakdown.d.ts.map +1 -0
  188. package/dist/tools/errorStatsBreakdown.js +77 -0
  189. package/dist/tools/errorStatsBreakdown.js.map +1 -0
  190. package/dist/tools/errorsInSession.d.ts +44 -0
  191. package/dist/tools/errorsInSession.d.ts.map +1 -0
  192. package/dist/tools/errorsInSession.js +91 -0
  193. package/dist/tools/errorsInSession.js.map +1 -0
  194. package/dist/tools/explainError.d.ts +35 -0
  195. package/dist/tools/explainError.d.ts.map +1 -0
  196. package/dist/tools/explainError.js +98 -0
  197. package/dist/tools/explainError.js.map +1 -0
  198. package/dist/tools/findCorrelatedErrors.d.ts +43 -0
  199. package/dist/tools/findCorrelatedErrors.d.ts.map +1 -0
  200. package/dist/tools/findCorrelatedErrors.js +59 -0
  201. package/dist/tools/findCorrelatedErrors.js.map +1 -0
  202. package/dist/tools/findSimilarErrors.d.ts +44 -0
  203. package/dist/tools/findSimilarErrors.d.ts.map +1 -0
  204. package/dist/tools/findSimilarErrors.js +59 -0
  205. package/dist/tools/findSimilarErrors.js.map +1 -0
  206. package/dist/tools/getLogDetails.d.ts +30 -0
  207. package/dist/tools/getLogDetails.d.ts.map +1 -0
  208. package/dist/tools/getLogDetails.js +49 -0
  209. package/dist/tools/getLogDetails.js.map +1 -0
  210. package/dist/tools/groupedErrors.d.ts +46 -0
  211. package/dist/tools/groupedErrors.d.ts.map +1 -0
  212. package/dist/tools/groupedErrors.js +71 -0
  213. package/dist/tools/groupedErrors.js.map +1 -0
  214. package/dist/tools/impactAnalysis.d.ts +42 -0
  215. package/dist/tools/impactAnalysis.d.ts.map +1 -0
  216. package/dist/tools/impactAnalysis.js +61 -0
  217. package/dist/tools/impactAnalysis.js.map +1 -0
  218. package/dist/tools/index.d.ts +41 -0
  219. package/dist/tools/index.d.ts.map +1 -0
  220. package/dist/tools/index.js +83 -0
  221. package/dist/tools/index.js.map +1 -0
  222. package/dist/tools/listApps.d.ts +27 -0
  223. package/dist/tools/listApps.d.ts.map +1 -0
  224. package/dist/tools/listApps.js +78 -0
  225. package/dist/tools/listApps.js.map +1 -0
  226. package/dist/tools/queryLogsJql.d.ts +44 -0
  227. package/dist/tools/queryLogsJql.d.ts.map +1 -0
  228. package/dist/tools/queryLogsJql.js +107 -0
  229. package/dist/tools/queryLogsJql.js.map +1 -0
  230. package/dist/tools/searchLogs.d.ts +60 -0
  231. package/dist/tools/searchLogs.d.ts.map +1 -0
  232. package/dist/tools/searchLogs.js +127 -0
  233. package/dist/tools/searchLogs.js.map +1 -0
  234. package/dist/tools/topErrorMessages.d.ts +42 -0
  235. package/dist/tools/topErrorMessages.d.ts.map +1 -0
  236. package/dist/tools/topErrorMessages.js +63 -0
  237. package/dist/tools/topErrorMessages.js.map +1 -0
  238. package/dist/tools/trafficStats.d.ts +39 -0
  239. package/dist/tools/trafficStats.d.ts.map +1 -0
  240. package/dist/tools/trafficStats.js +57 -0
  241. package/dist/tools/trafficStats.js.map +1 -0
  242. package/dist/tools/triageRecentCritical.d.ts +26 -0
  243. package/dist/tools/triageRecentCritical.d.ts.map +1 -0
  244. package/dist/tools/triageRecentCritical.js +81 -0
  245. package/dist/tools/triageRecentCritical.js.map +1 -0
  246. package/dist/tools/versionRegression.d.ts +29 -0
  247. package/dist/tools/versionRegression.d.ts.map +1 -0
  248. package/dist/tools/versionRegression.js +80 -0
  249. package/dist/tools/versionRegression.js.map +1 -0
  250. package/dist/transports/http-server.d.ts +25 -0
  251. package/dist/transports/http-server.d.ts.map +1 -0
  252. package/dist/transports/http-server.js +84 -0
  253. package/dist/transports/http-server.js.map +1 -0
  254. package/dist/transports/http.d.ts +71 -0
  255. package/dist/transports/http.d.ts.map +1 -0
  256. package/dist/transports/http.js +315 -0
  257. package/dist/transports/http.js.map +1 -0
  258. package/dist/transports/stdio.d.ts +13 -0
  259. package/dist/transports/stdio.d.ts.map +1 -0
  260. package/dist/transports/stdio.js +16 -0
  261. package/dist/transports/stdio.js.map +1 -0
  262. package/dist/types.d.ts +150 -0
  263. package/dist/types.d.ts.map +1 -0
  264. package/dist/types.js +8 -0
  265. package/dist/types.js.map +1 -0
  266. package/package.json +95 -0
@@ -0,0 +1,38 @@
1
+ import type { Logger } from 'pino';
2
+ import type { RedisService } from './redis.js';
3
+ export interface CacheServiceDeps {
4
+ redis: RedisService;
5
+ log?: Logger;
6
+ /** Tool-class label, используется в метриках. По умолчанию — извлекается из key. */
7
+ toolClass?: string;
8
+ }
9
+ export interface CacheOptions {
10
+ /** Tool-class для метрик. Если не задан — берётся из CacheServiceDeps. */
11
+ toolClass?: string;
12
+ /** Bypass cache (всегда вызывать loader). */
13
+ bypass?: boolean;
14
+ }
15
+ export declare class CacheService {
16
+ private readonly deps;
17
+ constructor(deps: CacheServiceDeps);
18
+ /**
19
+ * Lookup-aside fetch.
20
+ *
21
+ * Loader НЕ вызывается, если был cache hit. Ошибки loader'а — пробрасываются
22
+ * (не кэшируем negative result).
23
+ */
24
+ cached<T>(key: string, ttlSec: number, loader: () => Promise<T>, opts?: CacheOptions): Promise<{
25
+ value: T;
26
+ cached: boolean;
27
+ }>;
28
+ }
29
+ /**
30
+ * Static convenience helper (для случаев без CacheService instance).
31
+ *
32
+ * НЕ рекомендуется в production коде — используйте `CacheService.cached()`.
33
+ */
34
+ export declare function cached<T>(redis: RedisService, key: string, ttlSec: number, loader: () => Promise<T>, log?: Logger): Promise<{
35
+ value: T;
36
+ cached: boolean;
37
+ }>;
38
+ //# sourceMappingURL=wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/cache/wrapper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAuB/C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,gBAAgB;IAEnD;;;;;OAKG;IACG,MAAM,CAAC,CAAC,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CAkD1C;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,CAAC,EAC5B,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAGxC"}
@@ -0,0 +1,109 @@
1
+ import { gzipSync, gunzipSync } from 'node:zlib';
2
+ import { recordCacheHit, recordCacheMiss } from '../observability/metrics.js';
3
+ /**
4
+ * Lookup-aside cache wrapper.
5
+ *
6
+ * Алгоритм:
7
+ * 1. GET key → если HIT, парсим JSON (с gzip-распаковкой если нужно), отдаём.
8
+ * 2. Если MISS — вызываем loader(), сохраняем результат с TTL через SETEX.
9
+ * 3. На любых ошибках Redis — graceful degradation: loader() вызывается всегда.
10
+ *
11
+ * Compression: значения > `COMPRESSION_THRESHOLD_BYTES` (10 KB) — gzip + base64.
12
+ * Префикс `gz:` помечает сжатые значения.
13
+ *
14
+ * Negative cache: НЕ реализован в Phase 4 (loader-исключения не кэшируются).
15
+ *
16
+ * Tenant-isolation: cache key обязан содержать appSlug/keyPrefix.
17
+ * Это обеспечивает `tenantKey()` в `policies.ts`.
18
+ */
19
+ const COMPRESSION_THRESHOLD_BYTES = 10 * 1024;
20
+ const COMPRESSION_PREFIX = 'gz:';
21
+ export class CacheService {
22
+ deps;
23
+ constructor(deps) {
24
+ this.deps = deps;
25
+ }
26
+ /**
27
+ * Lookup-aside fetch.
28
+ *
29
+ * Loader НЕ вызывается, если был cache hit. Ошибки loader'а — пробрасываются
30
+ * (не кэшируем negative result).
31
+ */
32
+ async cached(key, ttlSec, loader, opts = {}) {
33
+ const toolClass = opts.toolClass ?? this.deps.toolClass ?? inferToolClass(key);
34
+ if (opts.bypass || this.deps.redis.unavailable) {
35
+ const value = await loader();
36
+ recordCacheMiss(toolClass);
37
+ return { value, cached: false };
38
+ }
39
+ // 1. Lookup
40
+ let raw = null;
41
+ try {
42
+ raw = await this.deps.redis.get(key);
43
+ }
44
+ catch (err) {
45
+ this.deps.log?.warn?.({ err: err.message, key }, 'cache GET failed');
46
+ }
47
+ if (raw !== null) {
48
+ try {
49
+ const parsed = decodeCacheValue(raw);
50
+ recordCacheHit(toolClass);
51
+ return { value: parsed, cached: true };
52
+ }
53
+ catch (err) {
54
+ // Поломанная запись (битый JSON / битый gzip) — игнорируем, идём в loader.
55
+ this.deps.log?.warn?.({ err: err.message, key }, 'cache value decode failed, falling back to loader');
56
+ }
57
+ }
58
+ // 2. Miss → loader
59
+ recordCacheMiss(toolClass);
60
+ const value = await loader();
61
+ // 3. Store (best-effort, не блокируем при ошибке)
62
+ if (value !== undefined && ttlSec > 0) {
63
+ try {
64
+ const encoded = encodeCacheValue(value);
65
+ await this.deps.redis.setex(key, ttlSec, encoded);
66
+ }
67
+ catch (err) {
68
+ this.deps.log?.warn?.({ err: err.message, key }, 'cache SETEX failed (continuing)');
69
+ }
70
+ }
71
+ return { value, cached: false };
72
+ }
73
+ }
74
+ /**
75
+ * Static convenience helper (для случаев без CacheService instance).
76
+ *
77
+ * НЕ рекомендуется в production коде — используйте `CacheService.cached()`.
78
+ */
79
+ export async function cached(redis, key, ttlSec, loader, log) {
80
+ const svc = new CacheService({ redis, ...(log !== undefined ? { log } : {}) });
81
+ return svc.cached(key, ttlSec, loader);
82
+ }
83
+ // ─── Serialization helpers ──────────────────────────────────────────────────
84
+ function encodeCacheValue(value) {
85
+ const json = JSON.stringify(value);
86
+ if (json.length <= COMPRESSION_THRESHOLD_BYTES)
87
+ return json;
88
+ // gzip + base64 для значений > 10KB
89
+ const compressed = gzipSync(Buffer.from(json, 'utf-8'));
90
+ return COMPRESSION_PREFIX + compressed.toString('base64');
91
+ }
92
+ function decodeCacheValue(raw) {
93
+ if (raw.startsWith(COMPRESSION_PREFIX)) {
94
+ const buf = Buffer.from(raw.slice(COMPRESSION_PREFIX.length), 'base64');
95
+ const json = gunzipSync(buf).toString('utf-8');
96
+ return JSON.parse(json);
97
+ }
98
+ return JSON.parse(raw);
99
+ }
100
+ /**
101
+ * Извлекает tool-class из cache key `mcp:cache:{class}:{tenant}:...`.
102
+ * Используется как fallback для метрик, если caller не указал явно.
103
+ */
104
+ function inferToolClass(key) {
105
+ const parts = key.split(':');
106
+ // mcp:cache:{class}:...
107
+ return parts[2] ?? 'unknown';
108
+ }
109
+ //# sourceMappingURL=wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/cache/wrapper.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ // Phase 6: OpenTelemetry instrumentation должен импортироваться ПЕРВЫМ —
3
+ // до любых других модулей, которые SDK инструментирует (http/undici/express/ioredis).
4
+ import { initInstrumentation } from './instrumentation.js';
5
+ import pino from 'pino';
6
+ import { loadConfig } from './config.js';
7
+ import { createMcpServer } from './server.js';
8
+ import { connectStdio } from './transports/stdio.js';
9
+ import { startHttpServer } from './transports/http-server.js';
10
+ /**
11
+ * CLI entry point. Выбирает транспорт по `MCP_TRANSPORT`:
12
+ * - `stdio` (default) — child-process для Claude Desktop / mcp-inspector.
13
+ * - `http` — Streamable HTTP + OIDC для hosted endpoint.
14
+ *
15
+ * Использование:
16
+ * ELS_API_KEY=els_live_... npx els-mcp # stdio
17
+ * MCP_TRANSPORT=http MCP_HTTP_PORT=3030 npx els-mcp # HTTP
18
+ *
19
+ * Все логи — в stderr (stdout зарезервирован под JSON-RPC при stdio).
20
+ */
21
+ async function main() {
22
+ // 1. OTel — early init (no-op если OTEL_EXPORTER_OTLP_ENDPOINT не задан).
23
+ const tracing = await initInstrumentation();
24
+ let config;
25
+ try {
26
+ config = loadConfig(process.env);
27
+ }
28
+ catch (err) {
29
+ process.stderr.write(`[els-mcp] Config error: ${err instanceof Error ? err.message : String(err)}\n`);
30
+ process.exit(1);
31
+ }
32
+ // Pino всегда в stderr — для stdio это обязательно, для HTTP — единый стиль.
33
+ const log = pino({ level: config.logLevel, name: 'els-mcp' }, pino.destination({ dest: 2, sync: false }));
34
+ if (tracing.enabled) {
35
+ log.info('OpenTelemetry tracing enabled');
36
+ }
37
+ if (config.transport === 'http') {
38
+ await runHttp(config, log, tracing);
39
+ }
40
+ else {
41
+ await runStdio(config, log, tracing);
42
+ }
43
+ }
44
+ async function runStdio(config, log, tracing) {
45
+ const { server, client } = createMcpServer({ config, log });
46
+ const shutdown = async (signal) => {
47
+ log.info({ signal }, 'Shutting down');
48
+ try {
49
+ await server.close();
50
+ await client.close();
51
+ await tracing.shutdown();
52
+ }
53
+ catch (err) {
54
+ log.error({ err }, 'Error during shutdown');
55
+ }
56
+ process.exit(0);
57
+ };
58
+ process.on('SIGINT', () => void shutdown('SIGINT'));
59
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
60
+ try {
61
+ await connectStdio(server);
62
+ log.info('MCP stdio transport ready');
63
+ }
64
+ catch (err) {
65
+ log.error({ err }, 'Failed to start stdio transport');
66
+ process.exit(1);
67
+ }
68
+ }
69
+ async function runHttp(config, log, tracing) {
70
+ const handle = await startHttpServer({ config, log });
71
+ const shutdown = async (signal) => {
72
+ log.info({ signal }, 'Shutting down');
73
+ try {
74
+ await handle.close();
75
+ await tracing.shutdown();
76
+ }
77
+ catch (err) {
78
+ log.error({ err }, 'Error during shutdown');
79
+ }
80
+ process.exit(0);
81
+ };
82
+ process.on('SIGINT', () => void shutdown('SIGINT'));
83
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
84
+ }
85
+ void main();
86
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import { z } from 'zod';
2
+ export declare const TransportSchema: z.ZodEnum<["stdio", "http"]>;
3
+ export type Transport = z.infer<typeof TransportSchema>;
4
+ export declare const ConfigSchema: z.ZodObject<{
5
+ /**
6
+ * ELS API key для stdio transport / fallback. В HTTP-режиме ключ берётся
7
+ * из заголовка `Authorization: Bearer els_...` запроса.
8
+ */
9
+ elsApiKey: z.ZodDefault<z.ZodString>;
10
+ elsBaseUrl: z.ZodString;
11
+ logLevel: z.ZodDefault<z.ZodEnum<["trace", "debug", "info", "warn", "error", "fatal"]>>;
12
+ disabledTools: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
13
+ /**
14
+ * Таймаут upstream-запроса в ELS, мс. В Phase 1 единый таймаут 30s;
15
+ * в Phase 5 разделим на ELS=25s и AI=60s.
16
+ */
17
+ upstreamTimeoutMs: z.ZodDefault<z.ZodNumber>;
18
+ transport: z.ZodDefault<z.ZodEnum<["stdio", "http"]>>;
19
+ httpPort: z.ZodDefault<z.ZodNumber>;
20
+ oidcIssuer: z.ZodDefault<z.ZodString>;
21
+ oidcJwksUrl: z.ZodString;
22
+ oidcAudience: z.ZodDefault<z.ZodString>;
23
+ /**
24
+ * Временный workaround Phase 3: маппинг любого OIDC-юзера на один appSlug,
25
+ * пока не реализован полноценный resolver через LK API. TODO Phase 4.
26
+ */
27
+ oidcDemoAppSlug: z.ZodOptional<z.ZodString>;
28
+ publicUrl: z.ZodDefault<z.ZodString>;
29
+ corsOrigins: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
30
+ /** Включена ли PII-редакция в ответах tools. */
31
+ redactionEnabled: z.ZodDefault<z.ZodBoolean>;
32
+ /** Whitelist полей для редакции (пусто → редактим все известные). */
33
+ redactionFields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
34
+ /** Postgres connection для audit/usage. Если пусто — модули в no-op. */
35
+ mcpDatabaseUrl: z.ZodOptional<z.ZodString>;
36
+ /** AppId по умолчанию (для stdio-mode, когда контекст не задан). */
37
+ defaultAppId: z.ZodDefault<z.ZodString>;
38
+ /** Tier по умолчанию (для stdio-mode / прокси-режима). */
39
+ defaultTier: z.ZodDefault<z.ZodEnum<["FREE", "STANDARD", "PREMIUM", "UNLIMITED"]>>;
40
+ /** Redis URL для cache layer. */
41
+ redisUrl: z.ZodDefault<z.ZodString>;
42
+ /** Включить cache layer. Если false — методы CachedElsClient прозрачно прокидываются в ElsClient. */
43
+ cacheEnabled: z.ZodDefault<z.ZodBoolean>;
44
+ /**
45
+ * Per-class TTL overrides. Ключи — имена CacheClass из `cache/policies.ts`.
46
+ * Значения — секунды (целые ≥ 0; 0 эффективно отключает кэш для класса).
47
+ * Source ENV: `MCP_CACHE_TTL_OVERRIDE_<CLASS>` (напр. `MCP_CACHE_TTL_OVERRIDE_LOG_DETAILS=7200`).
48
+ */
49
+ cacheTtlOverrides: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
50
+ /** Включить Prometheus metrics endpoint (`/els/metrics`). */
51
+ metricsEnabled: z.ZodDefault<z.ZodBoolean>;
52
+ /** OTLP endpoint для OpenTelemetry traces. Если не задан — tracing disabled. */
53
+ otelExporterOtlpEndpoint: z.ZodOptional<z.ZodString>;
54
+ }, "strip", z.ZodTypeAny, {
55
+ elsApiKey: string;
56
+ elsBaseUrl: string;
57
+ logLevel: "fatal" | "error" | "warn" | "info" | "debug" | "trace";
58
+ disabledTools: string[];
59
+ upstreamTimeoutMs: number;
60
+ transport: "stdio" | "http";
61
+ httpPort: number;
62
+ oidcIssuer: string;
63
+ oidcJwksUrl: string;
64
+ oidcAudience: string;
65
+ publicUrl: string;
66
+ corsOrigins: string[];
67
+ redactionEnabled: boolean;
68
+ redactionFields: string[];
69
+ defaultAppId: string;
70
+ defaultTier: "FREE" | "STANDARD" | "PREMIUM" | "UNLIMITED";
71
+ redisUrl: string;
72
+ cacheEnabled: boolean;
73
+ cacheTtlOverrides: Record<string, number>;
74
+ metricsEnabled: boolean;
75
+ oidcDemoAppSlug?: string | undefined;
76
+ mcpDatabaseUrl?: string | undefined;
77
+ otelExporterOtlpEndpoint?: string | undefined;
78
+ }, {
79
+ elsBaseUrl: string;
80
+ oidcJwksUrl: string;
81
+ elsApiKey?: string | undefined;
82
+ logLevel?: "fatal" | "error" | "warn" | "info" | "debug" | "trace" | undefined;
83
+ disabledTools?: string[] | undefined;
84
+ upstreamTimeoutMs?: number | undefined;
85
+ transport?: "stdio" | "http" | undefined;
86
+ httpPort?: number | undefined;
87
+ oidcIssuer?: string | undefined;
88
+ oidcAudience?: string | undefined;
89
+ oidcDemoAppSlug?: string | undefined;
90
+ publicUrl?: string | undefined;
91
+ corsOrigins?: string[] | undefined;
92
+ redactionEnabled?: boolean | undefined;
93
+ redactionFields?: string[] | undefined;
94
+ mcpDatabaseUrl?: string | undefined;
95
+ defaultAppId?: string | undefined;
96
+ defaultTier?: "FREE" | "STANDARD" | "PREMIUM" | "UNLIMITED" | undefined;
97
+ redisUrl?: string | undefined;
98
+ cacheEnabled?: boolean | undefined;
99
+ cacheTtlOverrides?: Record<string, number> | undefined;
100
+ metricsEnabled?: boolean | undefined;
101
+ otelExporterOtlpEndpoint?: string | undefined;
102
+ }>;
103
+ export type Config = z.infer<typeof ConfigSchema>;
104
+ export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
105
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,eAAO,MAAM,eAAe,8BAA4B,CAAC;AACzD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,YAAY;IACvB;;;OAGG;;;;;IAKH;;;OAGG;;;;;;;IAWH;;;OAGG;;;;IAQH,gDAAgD;;IAEhD,qEAAqE;;IAErE,wEAAwE;;IAExE,oEAAoE;;IAEpE,0DAA0D;;IAI1D,iCAAiC;;IAEjC,qGAAqG;;IAErG;;;;OAIG;;IAEH,6DAA6D;;IAE7D,gFAAgF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEhF,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAuDlD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAqDvE"}
package/dist/config.js ADDED
@@ -0,0 +1,211 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Парсинг и валидация переменных окружения для ELS MCP сервера.
4
+ *
5
+ * Источники: process.env. Phase 3 добавляет параметры HTTP-транспорта и OIDC.
6
+ */
7
+ const DEFAULT_BASE_URL_DEV = 'http://localhost:4010';
8
+ const DEFAULT_BASE_URL_PROD = 'https://api.insoweb.ru/els';
9
+ const DEFAULT_OIDC_ISSUER = 'https://auth.insoweb.ru';
10
+ const DEFAULT_PUBLIC_URL = 'https://mcp.insoweb.ru/els';
11
+ const DEFAULT_CORS_ORIGINS = 'https://claude.ai,https://chat.openai.com';
12
+ export const TransportSchema = z.enum(['stdio', 'http']);
13
+ export const ConfigSchema = z.object({
14
+ /**
15
+ * ELS API key для stdio transport / fallback. В HTTP-режиме ключ берётся
16
+ * из заголовка `Authorization: Bearer els_...` запроса.
17
+ */
18
+ elsApiKey: z.string().default(''),
19
+ elsBaseUrl: z.string().url(),
20
+ logLevel: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'),
21
+ disabledTools: z.array(z.string()).default([]),
22
+ /**
23
+ * Таймаут upstream-запроса в ELS, мс. В Phase 1 единый таймаут 30s;
24
+ * в Phase 5 разделим на ELS=25s и AI=60s.
25
+ */
26
+ upstreamTimeoutMs: z.number().int().positive().default(30_000),
27
+ // ─── Phase 3: HTTP transport ───────────────────────────────────────────
28
+ transport: TransportSchema.default('stdio'),
29
+ httpPort: z.number().int().positive().default(3030),
30
+ // ─── Phase 3: OIDC ─────────────────────────────────────────────────────
31
+ oidcIssuer: z.string().url().default(DEFAULT_OIDC_ISSUER),
32
+ oidcJwksUrl: z.string().url(),
33
+ oidcAudience: z.string().default('els-mcp'),
34
+ /**
35
+ * Временный workaround Phase 3: маппинг любого OIDC-юзера на один appSlug,
36
+ * пока не реализован полноценный resolver через LK API. TODO Phase 4.
37
+ */
38
+ oidcDemoAppSlug: z.string().optional(),
39
+ // ─── Phase 3: discovery / CORS ─────────────────────────────────────────
40
+ publicUrl: z.string().url().default(DEFAULT_PUBLIC_URL),
41
+ corsOrigins: z.array(z.string()).default([]),
42
+ // ─── Phase 5: PII-redaction + audit + billing ──────────────────────────
43
+ /** Включена ли PII-редакция в ответах tools. */
44
+ redactionEnabled: z.boolean().default(true),
45
+ /** Whitelist полей для редакции (пусто → редактим все известные). */
46
+ redactionFields: z.array(z.string()).default([]),
47
+ /** Postgres connection для audit/usage. Если пусто — модули в no-op. */
48
+ mcpDatabaseUrl: z.string().optional(),
49
+ /** AppId по умолчанию (для stdio-mode, когда контекст не задан). */
50
+ defaultAppId: z.string().default('default'),
51
+ /** Tier по умолчанию (для stdio-mode / прокси-режима). */
52
+ defaultTier: z.enum(['FREE', 'STANDARD', 'PREMIUM', 'UNLIMITED']).default('STANDARD'),
53
+ // ─── Phase 4: Cache & Observability ────────────────────────────────────
54
+ /** Redis URL для cache layer. */
55
+ redisUrl: z.string().default('redis://localhost:6379'),
56
+ /** Включить cache layer. Если false — методы CachedElsClient прозрачно прокидываются в ElsClient. */
57
+ cacheEnabled: z.boolean().default(true),
58
+ /**
59
+ * Per-class TTL overrides. Ключи — имена CacheClass из `cache/policies.ts`.
60
+ * Значения — секунды (целые ≥ 0; 0 эффективно отключает кэш для класса).
61
+ * Source ENV: `MCP_CACHE_TTL_OVERRIDE_<CLASS>` (напр. `MCP_CACHE_TTL_OVERRIDE_LOG_DETAILS=7200`).
62
+ */
63
+ cacheTtlOverrides: z.record(z.string(), z.number().int().nonnegative()).default({}),
64
+ /** Включить Prometheus metrics endpoint (`/els/metrics`). */
65
+ metricsEnabled: z.boolean().default(true),
66
+ /** OTLP endpoint для OpenTelemetry traces. Если не задан — tracing disabled. */
67
+ otelExporterOtlpEndpoint: z.string().optional(),
68
+ });
69
+ function pickBaseUrl(envBase, nodeEnv) {
70
+ if (envBase && envBase.trim().length > 0)
71
+ return envBase.trim();
72
+ if (nodeEnv === 'production')
73
+ return DEFAULT_BASE_URL_PROD;
74
+ return DEFAULT_BASE_URL_DEV;
75
+ }
76
+ function parseCsv(csv) {
77
+ if (!csv)
78
+ return [];
79
+ return csv.split(',').map((s) => s.trim()).filter(Boolean);
80
+ }
81
+ function pickIssuer(envIssuer) {
82
+ if (envIssuer && envIssuer.trim().length > 0)
83
+ return envIssuer.trim().replace(/\/$/, '');
84
+ return DEFAULT_OIDC_ISSUER;
85
+ }
86
+ function pickJwksUrl(envJwks, issuer) {
87
+ if (envJwks && envJwks.trim().length > 0)
88
+ return envJwks.trim();
89
+ return `${issuer.replace(/\/$/, '')}/oidc/.well-known/jwks.json`;
90
+ }
91
+ function pickPublicUrl(envPublic) {
92
+ if (envPublic && envPublic.trim().length > 0)
93
+ return envPublic.trim().replace(/\/$/, '');
94
+ return DEFAULT_PUBLIC_URL;
95
+ }
96
+ /**
97
+ * Парсит `MCP_CACHE_TTL_OVERRIDE_<CLASS>` ENV переменные.
98
+ * Пример: `MCP_CACHE_TTL_OVERRIDE_LOG_DETAILS=7200` → { log_details: 7200 }.
99
+ */
100
+ function parseCacheTtlOverrides(env) {
101
+ const prefix = 'MCP_CACHE_TTL_OVERRIDE_';
102
+ const result = {};
103
+ for (const [k, v] of Object.entries(env)) {
104
+ if (!k.startsWith(prefix) || v === undefined)
105
+ continue;
106
+ const cls = k.slice(prefix.length).toLowerCase();
107
+ const n = Number(v);
108
+ if (Number.isFinite(n) && n >= 0) {
109
+ result[cls] = Math.trunc(n);
110
+ }
111
+ }
112
+ return result;
113
+ }
114
+ function pickCorsOrigins(env, nodeEnv) {
115
+ const base = parseCsv(env ?? DEFAULT_CORS_ORIGINS);
116
+ if (nodeEnv !== 'production') {
117
+ // localhost для dev (любые порты) — exact match в middleware, regex там же.
118
+ base.push('http://localhost', 'http://127.0.0.1');
119
+ }
120
+ return Array.from(new Set(base));
121
+ }
122
+ export function loadConfig(env = process.env) {
123
+ const issuer = pickIssuer(env.MCP_OIDC_ISSUER);
124
+ const jwksUrl = pickJwksUrl(env.MCP_OIDC_JWKS_URL, issuer);
125
+ const raw = {
126
+ elsApiKey: env.ELS_API_KEY ?? '',
127
+ elsBaseUrl: pickBaseUrl(env.ELS_BASE_URL, env.NODE_ENV),
128
+ logLevel: (env.MCP_LOG_LEVEL ?? 'info').toLowerCase(),
129
+ disabledTools: parseCsv(env.MCP_DISABLE_TOOLS),
130
+ upstreamTimeoutMs: env.MCP_UPSTREAM_TIMEOUT_MS
131
+ ? Number(env.MCP_UPSTREAM_TIMEOUT_MS)
132
+ : 30_000,
133
+ transport: (env.MCP_TRANSPORT ?? 'stdio').toLowerCase(),
134
+ httpPort: env.MCP_HTTP_PORT ? Number(env.MCP_HTTP_PORT) : 3030,
135
+ oidcIssuer: issuer,
136
+ oidcJwksUrl: jwksUrl,
137
+ oidcAudience: env.MCP_OIDC_AUDIENCE ?? 'els-mcp',
138
+ oidcDemoAppSlug: env.MCP_OIDC_DEMO_APP_SLUG?.trim() || undefined,
139
+ publicUrl: pickPublicUrl(env.MCP_PUBLIC_URL),
140
+ corsOrigins: pickCorsOrigins(env.MCP_CORS_ORIGINS, env.NODE_ENV),
141
+ redactionEnabled: env.MCP_REDACTION_ENABLED
142
+ ? env.MCP_REDACTION_ENABLED.toLowerCase() !== 'false'
143
+ : true,
144
+ redactionFields: parseCsv(env.MCP_REDACTION_FIELDS),
145
+ mcpDatabaseUrl: env.MCP_DATABASE_URL?.trim() || undefined,
146
+ defaultAppId: env.MCP_DEFAULT_APP_ID?.trim() || 'default',
147
+ defaultTier: (env.MCP_DEFAULT_TIER ?? 'STANDARD').toUpperCase(),
148
+ redisUrl: env.MCP_REDIS_URL?.trim() || 'redis://localhost:6379',
149
+ cacheEnabled: env.MCP_CACHE_ENABLED ? env.MCP_CACHE_ENABLED.toLowerCase() !== 'false' : true,
150
+ cacheTtlOverrides: parseCacheTtlOverrides(env),
151
+ metricsEnabled: env.MCP_METRICS_ENABLED
152
+ ? env.MCP_METRICS_ENABLED.toLowerCase() !== 'false'
153
+ : true,
154
+ otelExporterOtlpEndpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim() || undefined,
155
+ };
156
+ const parsed = ConfigSchema.parse(raw);
157
+ // stdio-режим без ELS_API_KEY — фатальная ошибка (HTTP-режим допускает
158
+ // отсутствие глобального ключа: ключи приходят в запросах).
159
+ if (parsed.transport === 'stdio' && parsed.elsApiKey.length === 0) {
160
+ throw new Error('ELS_API_KEY is required for stdio transport');
161
+ }
162
+ // Phase 6: production-strict ENV validation.
163
+ validateProductionEnv(parsed, env);
164
+ return parsed;
165
+ }
166
+ /**
167
+ * Phase 6 ENV-validation:
168
+ * - В `NODE_ENV=production` fail-fast если критичные env vars не заданы.
169
+ * - В dev — только warnings в stderr.
170
+ *
171
+ * Критерии:
172
+ * - HTTP transport требует `MCP_OIDC_ISSUER` (явно задан, не default).
173
+ * - HTTP transport требует `MCP_PUBLIC_URL` (явно задан).
174
+ * - Если cacheEnabled=true → MCP_REDIS_URL должен быть задан (не default localhost).
175
+ */
176
+ function validateProductionEnv(cfg, env) {
177
+ const isProd = env.NODE_ENV === 'production';
178
+ const isTest = env.NODE_ENV === 'test' || env.VITEST === 'true';
179
+ const warnings = [];
180
+ const errors = [];
181
+ if (cfg.transport === 'http') {
182
+ if (!env.MCP_OIDC_ISSUER || env.MCP_OIDC_ISSUER.trim().length === 0) {
183
+ (isProd ? errors : warnings).push('MCP_OIDC_ISSUER not set (using default — INVALID for production)');
184
+ }
185
+ if (!env.MCP_PUBLIC_URL || env.MCP_PUBLIC_URL.trim().length === 0) {
186
+ (isProd ? errors : warnings).push('MCP_PUBLIC_URL not set (HTTP transport requires explicit public URL in production)');
187
+ }
188
+ }
189
+ // Cache: если cacheEnabled явно (env=true), то MCP_REDIS_URL должен быть задан.
190
+ const cacheExplicitlyEnabled = env.MCP_CACHE_ENABLED && env.MCP_CACHE_ENABLED.toLowerCase() === 'true';
191
+ if (cacheExplicitlyEnabled) {
192
+ if (!env.MCP_REDIS_URL || env.MCP_REDIS_URL.trim().length === 0) {
193
+ errors.push('MCP_CACHE_ENABLED=true requires MCP_REDIS_URL (no URL → cannot cache)');
194
+ }
195
+ }
196
+ else if (isProd && cfg.cacheEnabled) {
197
+ // В prod cacheEnabled=true (default), но redisUrl=default localhost — warning.
198
+ if (!env.MCP_REDIS_URL || env.MCP_REDIS_URL.trim().length === 0) {
199
+ warnings.push('MCP_REDIS_URL not set in production (cache will run in degraded mode against localhost)');
200
+ }
201
+ }
202
+ if (warnings.length > 0 && !isTest) {
203
+ for (const w of warnings) {
204
+ process.stderr.write(`[els-mcp] WARN: ${w}\n`);
205
+ }
206
+ }
207
+ if (errors.length > 0) {
208
+ throw new Error(`Production config validation failed:\n - ${errors.join('\n - ')}`);
209
+ }
210
+ }
211
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}