@deadragdoll/tellymcp 0.0.13 → 0.0.14

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 (64) hide show
  1. package/.env.example.client +5 -1
  2. package/.env.example.gateway +16 -1
  3. package/CHANGELOG.md +30 -0
  4. package/README-ru.md +14 -0
  5. package/README.md +14 -0
  6. package/TOOLS.md +182 -10
  7. package/config/templates/env.both.template +15 -2
  8. package/config/templates/env.client.template +5 -2
  9. package/config/templates/env.gateway.template +15 -2
  10. package/dist/cli.js +28 -1
  11. package/dist/services/features/telegram-mcp/browser.service.js +18 -0
  12. package/dist/services/features/telegram-mcp/file-content.service.js +94 -0
  13. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +5 -1
  14. package/dist/services/features/telegram-mcp/gateway-socket.service.js +43 -11
  15. package/dist/services/features/telegram-mcp/mcp-http.service.js +1 -0
  16. package/dist/services/features/telegram-mcp/mcp-server.service.js +18 -0
  17. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +9 -1
  18. package/dist/services/features/telegram-mcp/src/app/config/env.js +119 -2
  19. package/dist/services/features/telegram-mcp/src/app/http.js +139 -99
  20. package/dist/services/features/telegram-mcp/src/app/oauthFacade.js +642 -0
  21. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +151 -170
  22. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +96 -99
  23. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +62 -19
  24. package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachActiveTabTool.js +28 -0
  25. package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachTabTool.js +28 -0
  26. package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
  27. package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +1 -1
  28. package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +1 -1
  29. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +410 -27
  30. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +37 -3
  31. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +7 -6
  32. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +214 -37
  33. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +186 -0
  34. package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
  35. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
  36. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +4 -1
  37. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -35
  38. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
  39. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
  40. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
  41. package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
  42. package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
  43. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +5 -1
  44. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +3 -0
  45. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
  46. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
  47. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
  48. package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
  49. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
  50. package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
  51. package/docs/CHAT_CONNECTOR.md +134 -0
  52. package/docs/STANDALONE-ru.md +13 -0
  53. package/docs/STANDALONE.md +13 -0
  54. package/package.json +5 -3
  55. package/packages/chrome-attach-extension/dist/background.js +572 -163
  56. package/packages/chrome-attach-extension/dist/manifest.json +2 -1
  57. package/packages/chrome-attach-extension/dist/options.js +15 -2
  58. package/packages/chrome-attach-extension/dist/recorder-content.js +14 -1
  59. package/packages/chrome-attach-extension/dist/recorder-page.js +34 -18
  60. package/packages/firefox-attach-extension/dist/background.js +413 -33
  61. package/packages/firefox-attach-extension/dist/manifest.json +0 -12
  62. package/packages/firefox-attach-extension/dist/options.js +14 -1
  63. package/packages/firefox-attach-extension/dist/recorder-content.js +14 -1
  64. package/packages/firefox-attach-extension/dist/recorder-page.js +34 -18
@@ -3,15 +3,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveMcpHttpAuthorization = resolveMcpHttpAuthorization;
7
+ exports.isMcpHttpRequestAuthorized = isMcpHttpRequestAuthorized;
6
8
  exports.createMcpHttpHandler = createMcpHttpHandler;
7
9
  const node_crypto_1 = require("node:crypto");
8
10
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
9
11
  const ws_1 = __importDefault(require("ws"));
12
+ const oauthFacade_1 = require("./oauthFacade");
10
13
  const auth_1 = require("./webapp/auth");
11
14
  const relay_1 = require("./webapp/relay");
12
15
  const assets_1 = require("./webapp/assets");
13
16
  const client_1 = require("../shared/integrations/terminal/client");
14
17
  const terminal_1 = require("./webapp/terminal");
18
+ const bodyLimits_1 = require("../shared/lib/bodyLimits");
15
19
  function formatTerminalHttpError(error, fallback) {
16
20
  if ((0, terminal_1.isTerminalUnavailableError)(error)) {
17
21
  return "terminal runtime is unavailable";
@@ -32,6 +36,13 @@ function isInitializeRequest(body) {
32
36
  const method = Reflect.get(body, "method");
33
37
  return method === "initialize";
34
38
  }
39
+ function readMcpRpcMethod(body) {
40
+ if (!body || typeof body !== "object") {
41
+ return undefined;
42
+ }
43
+ const method = Reflect.get(body, "method");
44
+ return typeof method === "string" ? method : undefined;
45
+ }
35
46
  function readHeader(req, headerName) {
36
47
  const value = req.headers[headerName];
37
48
  if (Array.isArray(value)) {
@@ -44,24 +55,21 @@ async function readJsonBody(req) {
44
55
  if (knownParams &&
45
56
  typeof knownParams === "object" &&
46
57
  Object.keys(knownParams).length > 0) {
58
+ (0, bodyLimits_1.assertSerializedBodySize)(knownParams);
47
59
  return knownParams;
48
60
  }
49
61
  const knownBody = req.body;
50
62
  if (knownBody !== undefined) {
63
+ (0, bodyLimits_1.assertSerializedBodySize)(knownBody);
51
64
  return knownBody;
52
65
  }
53
- const chunks = [];
54
- for await (const chunk of req) {
55
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
56
- }
57
- if (chunks.length === 0) {
58
- return undefined;
59
- }
60
- const raw = Buffer.concat(chunks).toString("utf8").trim();
61
- if (!raw) {
62
- return undefined;
66
+ return (0, bodyLimits_1.readLimitedJsonBody)(req);
67
+ }
68
+ function ignoreInvalidJsonBody(error) {
69
+ if ((0, bodyLimits_1.isBodySizeLimitError)(error)) {
70
+ throw error;
63
71
  }
64
- return JSON.parse(raw);
72
+ return undefined;
65
73
  }
66
74
  function writeJson(res, statusCode, payload) {
67
75
  const body = JSON.stringify(payload);
@@ -103,6 +111,19 @@ function readBearerToken(req) {
103
111
  }
104
112
  return header.slice("Bearer ".length).trim() || null;
105
113
  }
114
+ function resolveMcpHttpAuthorization(req, internalBearerToken, oauthFacade) {
115
+ if (!internalBearerToken && !oauthFacade) {
116
+ return "public";
117
+ }
118
+ if (internalBearerToken && isAuthorized(req, internalBearerToken)) {
119
+ return "internal_bearer";
120
+ }
121
+ const token = readBearerToken(req);
122
+ return token && oauthFacade?.verifyAccessToken(token) ? "oauth" : null;
123
+ }
124
+ function isMcpHttpRequestAuthorized(req, internalBearerToken, oauthFacade) {
125
+ return resolveMcpHttpAuthorization(req, internalBearerToken, oauthFacade) !== null;
126
+ }
106
127
  function isDuplicateSseStreamError(error) {
107
128
  const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
108
129
  return message.includes("Only one SSE stream is allowed per session");
@@ -143,7 +164,10 @@ function isRelayTerminalUnavailableMessage(error) {
143
164
  function createMcpHttpHandler(runtime, input) {
144
165
  const transports = new Map();
145
166
  const webAppSessions = new auth_1.WebAppSessionRegistry();
146
- const liveWsServer = new WebSocketServer({ noServer: true });
167
+ const liveWsServer = new WebSocketServer({
168
+ noServer: true,
169
+ maxPayload: bodyLimits_1.MAX_BODY_SIZE_BYTES,
170
+ });
147
171
  const webAppBasePath = runtime.config.webapp.basePath.replace(/\/+$/u, "") || "/webapp";
148
172
  const rootPrefix = normalizeBasePath(process.env.ROOT_PREFIX || "/api");
149
173
  const publicWebAppBasePath = rootPrefix === "/"
@@ -153,6 +177,13 @@ function createMcpHttpHandler(runtime, input) {
153
177
  const webAppLivePrefix = `${webAppBasePath}/live/`;
154
178
  const telegramWebhookPath = runtime.config.telegram.webhook.path.replace(/\/+$/u, "") ||
155
179
  "/telegram/webhook";
180
+ const mcpHttpPath = runtime.config.mcp.httpPath.replace(/\/+$/u, "") || "/mcp";
181
+ const oauthFacade = runtime.config.oauth
182
+ ? (0, oauthFacade_1.createOAuthFacade)(runtime.config.oauth, mcpHttpPath, runtime.logger)
183
+ : null;
184
+ if (oauthFacade?.ephemeralSigningKey) {
185
+ runtime.logger.warn("OAuth connector is using an ephemeral signing key; access tokens will stop working after restart");
186
+ }
156
187
  const closeSessionEntry = async (entry) => {
157
188
  await entry.close();
158
189
  };
@@ -220,6 +251,11 @@ function createMcpHttpHandler(runtime, input) {
220
251
  socket.on("close", () => {
221
252
  void cleanup();
222
253
  });
254
+ socket.on("error", (error) => {
255
+ runtime.logger.warn("Telegram WebApp live WS socket error", {
256
+ error: error instanceof Error ? error.message : String(error),
257
+ });
258
+ });
223
259
  socket.on("message", (raw) => {
224
260
  void (async () => {
225
261
  const parsed = raw && typeof raw === "string"
@@ -288,6 +324,15 @@ function createMcpHttpHandler(runtime, input) {
288
324
  }
289
325
  if (resolved.session?.terminalTarget && (0, client_1.isStreamableTerminalTarget)(resolved.session.terminalTarget)) {
290
326
  (0, client_1.resizeForegroundTerminal)(resolved.session.terminalTarget, Math.max(20, Math.min(400, Math.round(cols))), Math.max(5, Math.min(200, Math.round(rows))));
327
+ return;
328
+ }
329
+ if (resolved.relayTarget) {
330
+ await input.getGatewaySocketService?.()?.requestLiveRelay?.({
331
+ clientUuid: resolved.relayTarget.clientUuid,
332
+ localSessionId: resolved.relayTarget.localSessionId,
333
+ requestType: "resize",
334
+ payload: { cols, rows },
335
+ });
291
336
  }
292
337
  }
293
338
  })().catch((error) => {
@@ -356,11 +401,39 @@ function createMcpHttpHandler(runtime, input) {
356
401
  socket.close(1011, "Live stream bootstrap failed");
357
402
  });
358
403
  });
359
- const handleRequest = async (req, res, pathname) => {
404
+ const handleRequestInternal = async (req, res, pathname) => {
360
405
  const method = req.method ?? "GET";
361
406
  const normalizedPathname = normalizePrefixedPathname(pathname);
362
407
  const requestUrl = new URL(req.url ?? normalizedPathname, `http://gateway.local`);
363
408
  requestUrl.pathname = normalizedPathname;
409
+ if (runtime.temporaryFileLinkStore &&
410
+ (await runtime.temporaryFileLinkStore.handleRequest(req, res, requestUrl.pathname))) {
411
+ return;
412
+ }
413
+ if (oauthFacade) {
414
+ const authorizationHeader = readHeader(req, "authorization");
415
+ const connectorRequestContext = {
416
+ method,
417
+ rawPath: pathname,
418
+ path: requestUrl.pathname,
419
+ queryParameters: [...requestUrl.searchParams.keys()],
420
+ userAgent: readHeader(req, "user-agent"),
421
+ accept: readHeader(req, "accept"),
422
+ contentType: readHeader(req, "content-type"),
423
+ authorizationHeaderPresent: Boolean(authorizationHeader),
424
+ authorizationScheme: authorizationHeader?.split(/\s+/u, 1)[0],
425
+ mcpSessionId: readHeader(req, "mcp-session-id"),
426
+ remoteAddress: req.socket.remoteAddress,
427
+ };
428
+ runtime.logger.info("OAuth connector HTTP request received", connectorRequestContext);
429
+ res.once("finish", () => {
430
+ runtime.logger.info("OAuth connector HTTP response completed", {
431
+ ...connectorRequestContext,
432
+ statusCode: res.statusCode,
433
+ responseContentType: String(res.getHeader("content-type") ?? ""),
434
+ });
435
+ });
436
+ }
364
437
  if (requestUrl.pathname === "/healthz") {
365
438
  writeJson(res, 200, {
366
439
  ok: true,
@@ -369,6 +442,10 @@ function createMcpHttpHandler(runtime, input) {
369
442
  });
370
443
  return;
371
444
  }
445
+ if (oauthFacade &&
446
+ (await oauthFacade.handleRequest(req, res, requestUrl.pathname))) {
447
+ return;
448
+ }
372
449
  if (runtime.config.telegram.webhook.enabled &&
373
450
  requestUrl.pathname === telegramWebhookPath) {
374
451
  if (method !== "POST") {
@@ -457,7 +534,7 @@ function createMcpHttpHandler(runtime, input) {
457
534
  method,
458
535
  path: requestUrl.pathname,
459
536
  });
460
- const body = await readJsonBody(req).catch(() => undefined);
537
+ const body = await readJsonBody(req).catch(ignoreInvalidJsonBody);
461
538
  let sessionId = body &&
462
539
  typeof body === "object" &&
463
540
  typeof Reflect.get(body, "sessionId") === "string"
@@ -529,7 +606,6 @@ function createMcpHttpHandler(runtime, input) {
529
606
  session_id: relayBootstrap.session_id,
530
607
  session_label: relayBootstrap.session_label,
531
608
  terminal_target: relayBootstrap.terminal_target,
532
- poll_interval_ms: relayBootstrap.poll_interval_ms,
533
609
  expires_at: new Date(record.expiresAtMs).toISOString(),
534
610
  });
535
611
  if (trustedTelegramUserId !== null) {
@@ -569,17 +645,6 @@ function createMcpHttpHandler(runtime, input) {
569
645
  }
570
646
  try {
571
647
  const validated = (0, auth_1.validateTelegramWebAppInitData)(initDataRaw, initDataUnsafe, requireTelegramBotToken(runtime, "validate Telegram WebApp bootstrap"), runtime.config.webapp.initDataTtlSeconds);
572
- runtime.logger.info("Telegram WebApp initData validation debug", {
573
- sessionId: sessionId || null,
574
- telegramUserId: validated.user.id,
575
- providedHash: validated.validationDebug.providedHash,
576
- officialRawMatches: validated.validationDebug.officialRaw.matches,
577
- officialRawCheckString: validated.validationDebug.officialRaw.checkString,
578
- officialRawComputedHash: validated.validationDebug.officialRaw.computedHash,
579
- userFieldsMatches: validated.validationDebug.userFields?.matches ?? null,
580
- userFieldsCheckString: validated.validationDebug.userFields?.checkString ?? null,
581
- userFieldsComputedHash: validated.validationDebug.userFields?.computedHash ?? null,
582
- });
583
648
  if (!sessionId) {
584
649
  sessionId =
585
650
  (await runtime.bindingStore.getActiveSessionIdForTelegramUser(validated.user.id)) ?? "";
@@ -615,7 +680,6 @@ function createMcpHttpHandler(runtime, input) {
615
680
  session_id: sessionId,
616
681
  session_label: session?.label ?? null,
617
682
  terminal_target: Boolean(session?.terminalTarget),
618
- poll_interval_ms: runtime.config.webapp.pollIntervalMs,
619
683
  expires_at: new Date(record.expiresAtMs).toISOString(),
620
684
  });
621
685
  if (launchRecord?.telegramChatId !== undefined &&
@@ -640,7 +704,6 @@ function createMcpHttpHandler(runtime, input) {
640
704
  runtime.logger.warn("Telegram WebApp bootstrap rejected", {
641
705
  sessionId,
642
706
  initDataLength: initDataRaw.length,
643
- initDataPreview: initDataRaw.slice(0, 160),
644
707
  hasUnsafeUser: Boolean(initDataUnsafe?.user) &&
645
708
  typeof initDataUnsafe?.user?.id === "number",
646
709
  error: error instanceof Error
@@ -651,74 +714,6 @@ function createMcpHttpHandler(runtime, input) {
651
714
  }
652
715
  return;
653
716
  }
654
- if (requestUrl.pathname === `${webAppBasePath}/api/view`) {
655
- if (method !== "GET") {
656
- writeText(res, 405, "Method not allowed");
657
- return;
658
- }
659
- const token = readBearerToken(req);
660
- const webAppSession = token ? webAppSessions.get(token) : null;
661
- if (!webAppSession) {
662
- writeText(res, 401, "Unauthorized");
663
- return;
664
- }
665
- const relayTarget = (0, relay_1.parseLiveRelaySessionId)(webAppSession.sessionId);
666
- if (relayTarget) {
667
- try {
668
- const result = await runtime.gatewayHttpService.requestLiveRelayView({
669
- clientUuid: relayTarget.clientUuid,
670
- localSessionId: relayTarget.localSessionId,
671
- });
672
- writeJson(res, 200, result);
673
- }
674
- catch (error) {
675
- runtime.logger.error("Telegram WebApp relay visible buffer capture failed", {
676
- sessionId: webAppSession.sessionId,
677
- clientUuid: relayTarget.clientUuid,
678
- localSessionId: relayTarget.localSessionId,
679
- error: error instanceof Error
680
- ? (error.stack ?? error.message)
681
- : String(error),
682
- });
683
- writeText(res, isRelayTerminalUnavailableMessage(error) ? 503 : 500, error instanceof Error ? error.message : "Failed to capture relay terminal buffer");
684
- }
685
- return;
686
- }
687
- const binding = await runtime.bindingStore.getBinding(webAppSession.sessionId);
688
- if (!binding ||
689
- binding.telegramUserId !== webAppSession.telegramUserId) {
690
- writeText(res, 403, "Session binding is no longer valid");
691
- return;
692
- }
693
- const session = await runtime.sessionStore.getSession(webAppSession.sessionId);
694
- if (!session?.terminalTarget) {
695
- writeText(res, 409, "terminal target is not configured for this session");
696
- return;
697
- }
698
- try {
699
- const terminalSize = await (0, terminal_1.getTerminalWindowSize)(runtime.config.terminal, session.terminalTarget);
700
- const content = await (0, terminal_1.captureVisibleTerminal)(runtime.config.terminal, session.terminalTarget, runtime.config.terminal.captureLines, runtime.config.webapp.visibleScreens);
701
- const ansi = await (0, terminal_1.captureVisibleTerminalAnsi)(runtime.config.terminal, session.terminalTarget, runtime.config.terminal.captureLines, runtime.config.webapp.visibleScreens);
702
- writeJson(res, 200, {
703
- session_id: session.sessionId,
704
- session_label: session.label ?? null,
705
- captured_at: new Date().toISOString(),
706
- content,
707
- ansi,
708
- ...(terminalSize ? terminalSize : {}),
709
- });
710
- }
711
- catch (error) {
712
- runtime.logger.error("Telegram WebApp visible buffer capture failed", {
713
- sessionId: webAppSession.sessionId,
714
- error: error instanceof Error
715
- ? (error.stack ?? error.message)
716
- : String(error),
717
- });
718
- writeText(res, (0, terminal_1.isTerminalUnavailableError)(error) ? 503 : 500, formatTerminalHttpError(error, "Failed to capture visible terminal buffer"));
719
- }
720
- return;
721
- }
722
717
  if (requestUrl.pathname === `${webAppBasePath}/api/action`) {
723
718
  if (method !== "POST") {
724
719
  writeText(res, 405, "Method not allowed");
@@ -730,7 +725,7 @@ function createMcpHttpHandler(runtime, input) {
730
725
  writeText(res, 401, "Unauthorized");
731
726
  return;
732
727
  }
733
- const body = await readJsonBody(req).catch(() => undefined);
728
+ const body = await readJsonBody(req).catch(ignoreInvalidJsonBody);
734
729
  const action = body &&
735
730
  typeof body === "object" &&
736
731
  typeof Reflect.get(body, "action") === "string"
@@ -921,16 +916,22 @@ function createMcpHttpHandler(runtime, input) {
921
916
  });
922
917
  return;
923
918
  }
924
- if (requestUrl.pathname !== runtime.config.mcp.httpPath) {
919
+ if (requestUrl.pathname !== mcpHttpPath &&
920
+ requestUrl.pathname !== `${mcpHttpPath}/`) {
925
921
  writeText(res, 404, "Not found");
926
922
  return;
927
923
  }
928
- if (!isAuthorized(req, runtime.config.mcp.bearerToken)) {
924
+ const authorizationMode = resolveMcpHttpAuthorization(req, runtime.config.mcp.bearerToken, oauthFacade);
925
+ if (!authorizationMode) {
926
+ const authorizationHeader = readHeader(req, "authorization");
929
927
  runtime.logger.warn("Unauthorized MCP HTTP request rejected", {
930
928
  method,
931
929
  path: requestUrl.pathname,
932
930
  remoteAddress: req.socket.remoteAddress,
931
+ authorizationHeaderPresent: Boolean(authorizationHeader),
932
+ authorizationScheme: authorizationHeader?.split(/\s+/u, 1)[0],
933
933
  });
934
+ oauthFacade?.writeMcpChallenge(res);
934
935
  writeText(res, 401, "Unauthorized");
935
936
  return;
936
937
  }
@@ -938,12 +939,33 @@ function createMcpHttpHandler(runtime, input) {
938
939
  const parsedBody = method === "POST" || method === "DELETE"
939
940
  ? await readJsonBody(req)
940
941
  : undefined;
942
+ const rpcMethod = readMcpRpcMethod(parsedBody);
941
943
  runtime.logger.debug("MCP HTTP request received", {
942
944
  method,
943
945
  path: requestUrl.pathname,
944
946
  sessionId,
947
+ authorizationMode,
948
+ rpcMethod,
945
949
  hasBody: parsedBody !== undefined,
946
950
  });
951
+ if (rpcMethod === "initialize" || rpcMethod === "tools/list") {
952
+ runtime.logger.info("Chat connector MCP handshake request received", {
953
+ rpcMethod,
954
+ authorizationMode,
955
+ sessionId,
956
+ userAgent: readHeader(req, "user-agent"),
957
+ });
958
+ res.once("finish", () => {
959
+ runtime.logger.info("Chat connector MCP handshake response completed", {
960
+ rpcMethod,
961
+ authorizationMode,
962
+ statusCode: res.statusCode,
963
+ sessionId: readHeader(req, "mcp-session-id") ??
964
+ (String(res.getHeader("mcp-session-id") ?? "") || undefined),
965
+ contentType: String(res.getHeader("content-type") ?? ""),
966
+ });
967
+ });
968
+ }
947
969
  try {
948
970
  if (method === "POST") {
949
971
  if (sessionId) {
@@ -1090,6 +1112,24 @@ function createMcpHttpHandler(runtime, input) {
1090
1112
  }
1091
1113
  }
1092
1114
  };
1115
+ const handleRequest = async (req, res, pathname) => {
1116
+ try {
1117
+ await handleRequestInternal(req, res, pathname);
1118
+ }
1119
+ catch (error) {
1120
+ if (!(0, bodyLimits_1.isBodySizeLimitError)(error)) {
1121
+ throw error;
1122
+ }
1123
+ if (!res.headersSent) {
1124
+ writeJson(res, 413, {
1125
+ error: `Request body exceeds the ${bodyLimits_1.MAX_BODY_SIZE} MiB limit`,
1126
+ });
1127
+ }
1128
+ else if (!res.writableEnded) {
1129
+ res.end();
1130
+ }
1131
+ }
1132
+ };
1093
1133
  let shuttingDown = false;
1094
1134
  const handleUpgrade = async (req, socket, head, pathname) => {
1095
1135
  const normalizedPathname = normalizePrefixedPathname(pathname);