@deadragdoll/tellymcp 0.0.12 → 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 (83) 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 +33 -0
  5. package/README.md +33 -0
  6. package/TOOLS.md +384 -9
  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 +137 -2
  11. package/dist/services/features/telegram-mcp/browser.service.js +56 -1
  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 +30 -0
  17. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +23 -1
  18. package/dist/services/features/telegram-mcp/src/app/config/env.js +132 -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 +205 -17
  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/browserClickTool.js +1 -1
  27. package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
  28. package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +1 -1
  29. package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +1 -1
  30. package/dist/services/features/telegram-mcp/src/features/browser/model/browserInjectScriptTool.js +28 -0
  31. package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +33 -0
  32. package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +33 -0
  33. package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +1 -1
  34. package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStartTool.js +28 -0
  35. package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStatusTool.js +28 -0
  36. package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStopTool.js +28 -0
  37. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  38. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +890 -23
  39. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +536 -0
  40. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +80 -0
  41. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +736 -0
  42. package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +188 -0
  43. package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
  44. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
  45. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +4 -1
  46. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -35
  47. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
  48. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
  49. package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
  50. package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
  51. package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
  52. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +5 -1
  53. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +28 -0
  54. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +3 -0
  55. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
  56. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
  57. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
  58. package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
  59. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
  60. package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
  61. package/docs/CHAT_CONNECTOR.md +134 -0
  62. package/docs/STANDALONE-ru.md +55 -6
  63. package/docs/STANDALONE.md +55 -6
  64. package/package.json +10 -5
  65. package/packages/chrome-attach-extension/dist/background.js +1735 -0
  66. package/packages/chrome-attach-extension/dist/icon.svg +6 -0
  67. package/packages/chrome-attach-extension/dist/manifest.json +37 -0
  68. package/packages/chrome-attach-extension/dist/options.html +312 -0
  69. package/packages/chrome-attach-extension/dist/options.js +606 -0
  70. package/packages/chrome-attach-extension/dist/popup.html +93 -0
  71. package/packages/chrome-attach-extension/dist/popup.js +79 -0
  72. package/packages/chrome-attach-extension/dist/recorder-content.js +96 -0
  73. package/packages/chrome-attach-extension/dist/recorder-page.js +282 -0
  74. package/packages/firefox-attach-extension/README.md +13 -0
  75. package/packages/firefox-attach-extension/dist/background.js +1622 -0
  76. package/packages/firefox-attach-extension/dist/icon.svg +6 -0
  77. package/packages/firefox-attach-extension/dist/manifest.json +44 -0
  78. package/packages/firefox-attach-extension/dist/options.html +312 -0
  79. package/packages/firefox-attach-extension/dist/options.js +540 -0
  80. package/packages/firefox-attach-extension/dist/popup.html +93 -0
  81. package/packages/firefox-attach-extension/dist/popup.js +64 -0
  82. package/packages/firefox-attach-extension/dist/recorder-content.js +90 -0
  83. package/packages/firefox-attach-extension/dist/recorder-page.js +318 -0
package/dist/cli.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_child_process_1 = require("node:child_process");
10
+ const node_crypto_1 = require("node:crypto");
10
11
  const node_net_1 = __importDefault(require("node:net"));
11
12
  const dotenv_1 = require("dotenv");
12
13
  const ioredis_1 = __importDefault(require("ioredis"));
@@ -72,9 +73,12 @@ function printHelp() {
72
73
  " tellymcp doctor [--env <file>]",
73
74
  " tellymcp system-prune [--env <file>] --yes",
74
75
  " tellymcp browser install",
76
+ " tellymcp extension firefox",
77
+ " tellymcp extension chrome",
75
78
  " tellymcp codex-plugin install",
76
79
  " tellymcp codex-plugin status",
77
80
  " tellymcp mcp [--url <url>] [--bearer <token>] [--format claude|legacy]",
81
+ " tellymcp oauth key",
78
82
  " tellymcp help",
79
83
  ]);
80
84
  printSection("Examples", [
@@ -87,9 +91,12 @@ function printHelp() {
87
91
  " tellymcp doctor --env .env.client",
88
92
  " tellymcp system-prune --env .env.gateway --yes",
89
93
  " tellymcp browser install",
94
+ " tellymcp extension firefox",
95
+ " tellymcp extension chrome ./tellymcp-chrome-attach",
90
96
  " tellymcp codex-plugin install",
91
97
  " tellymcp codex-plugin status",
92
98
  " tellymcp mcp --help",
99
+ " tellymcp oauth key",
93
100
  ]);
94
101
  printSection("terminal", [
95
102
  `${picocolors_1.default.green(" OK")} built-in PTY runtime`,
@@ -234,6 +241,26 @@ function printMcpHelp() {
234
241
  " tellymcp mcp --url https://builder.undoo.ru/api/mcp --format legacy",
235
242
  ]);
236
243
  }
244
+ function runOAuthCommand(args) {
245
+ const [subcommand] = args;
246
+ if (!subcommand || subcommand === "--help" || subcommand === "-h") {
247
+ printBanner("OAuth helper", "Generate connector signing material");
248
+ printSection("Usage", [" tellymcp oauth key"]);
249
+ printSection("Output", [
250
+ " Prints a dotenv-ready TELLYMCP_OAUTH_PRIVATE_KEY_PEM value.",
251
+ " Store it only on the gateway and never expose it to chat clients.",
252
+ ]);
253
+ return;
254
+ }
255
+ if (subcommand !== "key") {
256
+ fail("Supported OAuth subcommands: key");
257
+ }
258
+ const privateKeyPem = (0, node_crypto_1.generateKeyPairSync)("rsa", { modulusLength: 2048 })
259
+ .privateKey.export({ type: "pkcs8", format: "pem" })
260
+ .toString()
261
+ .replace(/\n/gu, "\\n");
262
+ process.stdout.write(`TELLYMCP_OAUTH_PRIVATE_KEY_PEM="${privateKeyPem}"\n`);
263
+ }
237
264
  function printBrowserHelp() {
238
265
  printBanner("browser helper", "Manage Playwright browser binaries used by browser_* tools");
239
266
  printSection("Usage", [
@@ -245,6 +272,27 @@ function printBrowserHelp() {
245
272
  " Avoids generic npx warnings about missing local project dependencies.",
246
273
  ]);
247
274
  }
275
+ function printExtensionHelp() {
276
+ printBanner("extension helper", "Export bundled browser attach extensions into a local directory");
277
+ printSection("Usage", [
278
+ " tellymcp extension firefox [output-directory]",
279
+ " tellymcp extension ff [output-directory]",
280
+ " tellymcp extension chrome [output-directory]",
281
+ " tellymcp extension <firefox|ff|chrome> --out-dir <directory>",
282
+ " tellymcp extension <firefox|ff|chrome> --force",
283
+ ]);
284
+ printSection("What this command does", [
285
+ " Copies the packaged unpacked extension bundle out of the installed tellymcp package.",
286
+ " By default exports into the current directory.",
287
+ " Creates a browser-specific folder you can load into Firefox or Chrome.",
288
+ ]);
289
+ printSection("Examples", [
290
+ " tellymcp extension firefox",
291
+ " tellymcp extension chrome",
292
+ " tellymcp extension firefox ./tellymcp-firefox-attach",
293
+ " tellymcp extension chrome --out-dir ./browser-addon",
294
+ ]);
295
+ }
248
296
  function printCodexPluginHelp() {
249
297
  printBanner("codex plugin", "Install or inspect the bundled Codex workflow plugin");
250
298
  printSection("Usage", [
@@ -684,6 +732,39 @@ async function runDoctor(args) {
684
732
  function hasFlag(args, flagName) {
685
733
  return args.includes(flagName);
686
734
  }
735
+ function normalizeExtensionFlavor(rawValue) {
736
+ if (rawValue === "firefox" || rawValue === "ff") {
737
+ return "firefox";
738
+ }
739
+ if (rawValue === "chrome") {
740
+ return "chrome";
741
+ }
742
+ return null;
743
+ }
744
+ function getBundledExtensionDir(flavor) {
745
+ return node_path_1.default.join(packageRoot, "packages", flavor === "firefox" ? "firefox-attach-extension" : "chrome-attach-extension", "dist");
746
+ }
747
+ function getDefaultExtensionTargetDir(flavor) {
748
+ return node_path_1.default.resolve(process.cwd(), flavor === "firefox" ? "tellymcp-firefox-attach" : "tellymcp-chrome-attach");
749
+ }
750
+ function resolveExtensionTargetDir(args, flavor) {
751
+ const explicitOutDir = readFlagValue(args, "--out-dir");
752
+ if (explicitOutDir) {
753
+ return node_path_1.default.resolve(process.cwd(), explicitOutDir);
754
+ }
755
+ const positionalOutDir = args.find((value, index) => {
756
+ if (index === 0 || !value) {
757
+ return false;
758
+ }
759
+ if (value === "--force") {
760
+ return false;
761
+ }
762
+ return !value.startsWith("--out-dir=");
763
+ });
764
+ return positionalOutDir
765
+ ? node_path_1.default.resolve(process.cwd(), positionalOutDir)
766
+ : getDefaultExtensionTargetDir(flavor);
767
+ }
687
768
  async function runSystemPrune(args) {
688
769
  const confirmed = hasFlag(args, "--yes");
689
770
  if (!confirmed) {
@@ -821,6 +902,52 @@ function runBrowserCommand(args) {
821
902
  process.exit(code ?? 0);
822
903
  });
823
904
  }
905
+ function runExtensionCommand(args) {
906
+ const [rawFlavor] = args;
907
+ if (!rawFlavor || rawFlavor === "--help" || rawFlavor === "-h") {
908
+ printExtensionHelp();
909
+ return;
910
+ }
911
+ const flavor = normalizeExtensionFlavor(rawFlavor);
912
+ if (!flavor) {
913
+ fail("Supported extension targets: firefox, ff, chrome");
914
+ }
915
+ const sourceDir = getBundledExtensionDir(flavor);
916
+ const sourceManifestPath = node_path_1.default.join(sourceDir, "manifest.json");
917
+ if (!(0, node_fs_1.existsSync)(sourceManifestPath)) {
918
+ fail(`Missing bundled ${flavor} extension. Reinstall or republish tellymcp with packaged extension bundles.`);
919
+ }
920
+ const targetDir = resolveExtensionTargetDir(args, flavor);
921
+ const force = hasFlag(args, "--force");
922
+ if ((0, node_fs_1.existsSync)(targetDir)) {
923
+ if (!force) {
924
+ fail(`Refusing to overwrite existing directory: ${targetDir}. Re-run with --force.`);
925
+ }
926
+ (0, node_fs_1.rmSync)(targetDir, { recursive: true, force: true });
927
+ }
928
+ (0, node_fs_1.mkdirSync)(node_path_1.default.dirname(targetDir), { recursive: true });
929
+ (0, node_fs_1.cpSync)(sourceDir, targetDir, { recursive: true });
930
+ printBanner(`extension ${flavor}`, "Bundled attach extension exported");
931
+ printSection("result", [
932
+ ` source: ${sourceDir}`,
933
+ ` target: ${targetDir}`,
934
+ ` manifest: ${node_path_1.default.join(targetDir, "manifest.json")}`,
935
+ ]);
936
+ if (flavor === "firefox") {
937
+ printSection("next", [
938
+ " 1. Open about:debugging#/runtime/this-firefox",
939
+ " 2. Click 'Load Temporary Add-on'",
940
+ ` 3. Choose ${node_path_1.default.join(targetDir, "manifest.json")}`,
941
+ ]);
942
+ return;
943
+ }
944
+ printSection("next", [
945
+ " 1. Open chrome://extensions",
946
+ " 2. Enable Developer mode",
947
+ " 3. Click 'Load unpacked'",
948
+ ` 4. Choose ${targetDir}`,
949
+ ]);
950
+ }
824
951
  function runCodexPluginCommand(args) {
825
952
  const [subcommand] = args;
826
953
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
@@ -941,8 +1068,8 @@ async function runRuntime(args) {
941
1068
  }
942
1069
  async function main(argv) {
943
1070
  const [rawCommand, firstArg, secondArg] = argv;
944
- const command = rawCommand === "init" || rawCommand === "run" || rawCommand === "help" || rawCommand === "mcp" || rawCommand === "doctor" || rawCommand === "browser" || rawCommand === "system-prune"
945
- || rawCommand === "codex-plugin"
1071
+ const command = rawCommand === "init" || rawCommand === "run" || rawCommand === "help" || rawCommand === "mcp" || rawCommand === "oauth" || rawCommand === "doctor" || rawCommand === "browser" || rawCommand === "system-prune"
1072
+ || rawCommand === "codex-plugin" || rawCommand === "extension"
946
1073
  ? rawCommand
947
1074
  : "help";
948
1075
  if (command === "help" || !rawCommand || rawCommand === "--help" || rawCommand === "-h") {
@@ -957,6 +1084,10 @@ async function main(argv) {
957
1084
  printMcpConfig(argv.slice(1));
958
1085
  return;
959
1086
  }
1087
+ if (command === "oauth") {
1088
+ runOAuthCommand(argv.slice(1));
1089
+ return;
1090
+ }
960
1091
  if (command === "doctor") {
961
1092
  await runDoctor(argv.slice(1));
962
1093
  return;
@@ -965,6 +1096,10 @@ async function main(argv) {
965
1096
  runBrowserCommand(argv.slice(1));
966
1097
  return;
967
1098
  }
1099
+ if (command === "extension") {
1100
+ runExtensionCommand(argv.slice(1));
1101
+ return;
1102
+ }
968
1103
  if (command === "codex-plugin") {
969
1104
  runCodexPluginCommand(argv.slice(1));
970
1105
  return;
@@ -21,6 +21,54 @@ const TelegramMcpBrowserService = {
21
21
  return this.getBrowserService().getConsole(ctx.params);
22
22
  },
23
23
  },
24
+ listAttachedInstancesRemote: {
25
+ params: { $$strict: false },
26
+ async handler(ctx) {
27
+ return this.getBrowserService().listAttachedInstances(ctx.params);
28
+ },
29
+ },
30
+ listTabsRemote: {
31
+ params: { $$strict: false },
32
+ async handler(ctx) {
33
+ return this.getBrowserService().listTabs(ctx.params);
34
+ },
35
+ },
36
+ attachActiveTabRemote: {
37
+ params: { $$strict: false },
38
+ async handler(ctx) {
39
+ return this.getBrowserService().attachActiveTab(ctx.params);
40
+ },
41
+ },
42
+ attachTabRemote: {
43
+ params: { $$strict: false },
44
+ async handler(ctx) {
45
+ return this.getBrowserService().attachTab(ctx.params);
46
+ },
47
+ },
48
+ detachTabRemote: {
49
+ params: { $$strict: false },
50
+ async handler(ctx) {
51
+ return this.getBrowserService().detachTab(ctx.params);
52
+ },
53
+ },
54
+ startRecordingRemote: {
55
+ params: { $$strict: false },
56
+ async handler(ctx) {
57
+ return this.getBrowserService().startRecording(ctx.params);
58
+ },
59
+ },
60
+ stopRecordingRemote: {
61
+ params: { $$strict: false },
62
+ async handler(ctx) {
63
+ return this.getBrowserService().stopRecording(ctx.params);
64
+ },
65
+ },
66
+ getRecordingStatusRemote: {
67
+ params: { $$strict: false },
68
+ async handler(ctx) {
69
+ return this.getBrowserService().getRecordingStatus(ctx.params);
70
+ },
71
+ },
24
72
  clickRemote: {
25
73
  params: { $$strict: false },
26
74
  async handler(ctx) {
@@ -33,6 +81,12 @@ const TelegramMcpBrowserService = {
33
81
  return this.getBrowserService().fill(ctx.params);
34
82
  },
35
83
  },
84
+ injectScriptRemote: {
85
+ params: { $$strict: false },
86
+ async handler(ctx) {
87
+ return this.getBrowserService().injectScript(ctx.params);
88
+ },
89
+ },
36
90
  pressRemote: {
37
91
  params: { $$strict: false },
38
92
  async handler(ctx) {
@@ -119,7 +173,8 @@ const TelegramMcpBrowserService = {
119
173
  }
120
174
  const runtime = await runtimeService.waitUntilReady();
121
175
  this.logger.info("Starting telegram_mcp browser service");
122
- this.browserService = new browserService_1.BrowserService(runtime.config, runtime.sessionStore, runtime.maintenanceStore, runtime.stateStore, runtime.stateStore, runtime.objectStore, runtime.telegramTransport, runtime.logger, runtime.projectIdentityResolver, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })));
176
+ const firefoxAttachServer = runtime.firefoxAttachServer;
177
+ this.browserService = new browserService_1.BrowserService(runtime.config, runtime.sessionStore, runtime.maintenanceStore, runtime.stateStore, runtime.stateStore, runtime.objectStore, runtime.telegramTransport, runtime.logger, runtime.projectIdentityResolver, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })), firefoxAttachServer);
123
178
  this.logger.info("telegram_mcp browser service is ready");
124
179
  },
125
180
  async stopped() {
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME = void 0;
4
+ const runtime_service_1 = require("./runtime.service");
5
+ const remoteConsoleActionClient_1 = require("./src/features/distributed-gateway/model/remoteConsoleActionClient");
6
+ const getFileService_1 = require("./src/features/file-content/model/getFileService");
7
+ exports.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME = "telegramMcp.fileContent";
8
+ const TelegramMcpFileContentService = {
9
+ name: exports.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
10
+ dependencies: [runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME],
11
+ actions: {
12
+ listFilesRemote: {
13
+ params: {
14
+ $$strict: false,
15
+ session_id: { type: "string", optional: true, trim: true, min: 1 },
16
+ source: {
17
+ type: "enum",
18
+ optional: true,
19
+ values: ["telegram-upload", "browser-screenshot", "partner-artifact"],
20
+ },
21
+ limit: {
22
+ type: "number",
23
+ optional: true,
24
+ integer: true,
25
+ positive: true,
26
+ max: 200,
27
+ },
28
+ },
29
+ async handler(ctx) {
30
+ return this.getGetFileService().list(ctx.params);
31
+ },
32
+ },
33
+ getFileRemote: {
34
+ params: {
35
+ $$strict: false,
36
+ session_id: { type: "string", optional: true, trim: true, min: 1 },
37
+ file_path: { type: "string", optional: true, trim: true, min: 1 },
38
+ selector: {
39
+ type: "enum",
40
+ optional: true,
41
+ values: ["latest_screenshot"],
42
+ },
43
+ type: {
44
+ type: "enum",
45
+ optional: true,
46
+ values: ["text", "base64"],
47
+ },
48
+ },
49
+ async handler(ctx) {
50
+ return this.getGetFileService().get(ctx.params);
51
+ },
52
+ },
53
+ uploadFileRemote: {
54
+ params: {
55
+ $$strict: false,
56
+ session_id: { type: "string", optional: true, trim: true, min: 1 },
57
+ file_path: { type: "string", optional: true, trim: true, min: 1 },
58
+ selector: {
59
+ type: "enum",
60
+ optional: true,
61
+ values: ["latest_screenshot"],
62
+ },
63
+ type: { type: "enum", values: ["url"] },
64
+ upload_url: { type: "string", trim: true, min: 1 },
65
+ },
66
+ async handler(ctx) {
67
+ return this.getGetFileService().upload(ctx.params);
68
+ },
69
+ },
70
+ },
71
+ created() {
72
+ this.getFileService = null;
73
+ },
74
+ methods: {
75
+ getGetFileService() {
76
+ if (!this.getFileService) {
77
+ throw new Error("telegram_mcp file content service is not initialized yet");
78
+ }
79
+ return this.getFileService;
80
+ },
81
+ },
82
+ async started() {
83
+ await this.broker.waitForServices([runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME]);
84
+ const runtimeService = this.broker.getLocalService(runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME);
85
+ if (!runtimeService) {
86
+ throw new Error(`Local Moleculer service '${runtime_service_1.TELEGRAM_MCP_RUNTIME_SERVICE_NAME}' is unavailable`);
87
+ }
88
+ const runtime = await runtimeService.waitUntilReady();
89
+ this.logger.info("Starting telegram_mcp file content service");
90
+ this.getFileService = new getFileService_1.GetFileService(runtime.config, runtime.sessionStore, runtime.stateStore, runtime.stateStore, runtime.logger, runtime.projectIdentityResolver, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })), runtime.temporaryFileLinkStore);
91
+ this.logger.info("telegram_mcp file content service is ready");
92
+ },
93
+ };
94
+ exports.default = TelegramMcpFileContentService;
@@ -9,6 +9,7 @@ const runtime_service_1 = require("./runtime.service");
9
9
  const xchangeRecordHints_1 = require("./src/shared/lib/xchangeRecordHints");
10
10
  const client_1 = require("./src/shared/integrations/terminal/client");
11
11
  const sqliteRecordStore_1 = require("./src/shared/integrations/xchange/sqliteRecordStore");
12
+ const bodyLimits_1 = require("./src/shared/lib/bodyLimits");
12
13
  exports.TELEGRAM_MCP_GATEWAY_DELIVERY_SERVICE_NAME = "telegramMcp.gatewayDelivery";
13
14
  function renderYamlArray(values) {
14
15
  if (values.length === 0) {
@@ -319,7 +320,10 @@ const TelegramMcpGatewayDeliveryService = {
319
320
  `shares/files/${delivery.share_id}/${artifact.original_name}`;
320
321
  let localArtifactPath;
321
322
  if (artifact.content_base64) {
322
- localArtifactPath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.terminal, workspaceDir, runtime.config.exchange.dir, relativePath, Buffer.from(artifact.content_base64, "base64"));
323
+ (0, bodyLimits_1.assertStringBodySize)(artifact.content_base64);
324
+ const decodedContent = Buffer.from(artifact.content_base64, "base64");
325
+ (0, bodyLimits_1.assertBodySize)(decodedContent.byteLength);
326
+ localArtifactPath = await (0, client_1.writeXchangeRelativeFile)(runtime.config.terminal, workspaceDir, runtime.config.exchange.dir, relativePath, decodedContent);
323
327
  }
324
328
  else {
325
329
  localArtifactPath = await runtime.objectStore.ensureLocalFile({
@@ -11,6 +11,8 @@ const auth_1 = require("./src/app/webapp/auth");
11
11
  const terminal_1 = require("./src/app/webapp/terminal");
12
12
  const client_1 = require("./src/shared/integrations/terminal/client");
13
13
  const gateway_loopback_1 = require("./gateway-loopback");
14
+ const gatewayAuth_1 = require("./src/shared/lib/gatewayAuth");
15
+ const bodyLimits_1 = require("./src/shared/lib/bodyLimits");
14
16
  const versionHandshake_1 = require("./src/shared/lib/version/versionHandshake");
15
17
  const wsLib = require("ws");
16
18
  const WebSocketServer = wsLib.WebSocketServer;
@@ -226,6 +228,7 @@ const TelegramMcpGatewaySocketService = {
226
228
  "bootstrap_validate",
227
229
  "view",
228
230
  "action",
231
+ "resize",
229
232
  "stream_subscribe",
230
233
  "stream_unsubscribe",
231
234
  ],
@@ -941,7 +944,6 @@ const TelegramMcpGatewaySocketService = {
941
944
  session_id: sessionId,
942
945
  session_label: session?.label ?? null,
943
946
  terminal_target: Boolean(session?.terminalTarget),
944
- poll_interval_ms: runtime.config.webapp.pollIntervalMs,
945
947
  telegram_user_id: telegramUserId,
946
948
  },
947
949
  };
@@ -1002,6 +1004,25 @@ const TelegramMcpGatewaySocketService = {
1002
1004
  },
1003
1005
  };
1004
1006
  }
1007
+ if (request.request_type === "resize") {
1008
+ const cols = typeof request.payload?.cols === "number" ? request.payload.cols : NaN;
1009
+ const rows = typeof request.payload?.rows === "number" ? request.payload.rows : NaN;
1010
+ if (!Number.isFinite(cols) || !Number.isFinite(rows)) {
1011
+ throw new Error("Terminal cols and rows are required");
1012
+ }
1013
+ const sessionId = request.local_session_id.trim();
1014
+ const session = await runtime.sessionStore.getSession(sessionId);
1015
+ if (!session?.terminalTarget || !(0, client_1.isStreamableTerminalTarget)(session.terminalTarget)) {
1016
+ throw new Error("Terminal target does not support resize");
1017
+ }
1018
+ (0, client_1.resizeForegroundTerminal)(session.terminalTarget, Math.max(20, Math.min(400, Math.round(cols))), Math.max(5, Math.min(200, Math.round(rows))));
1019
+ return {
1020
+ type: "live_response",
1021
+ request_id: request.request_id,
1022
+ ok: true,
1023
+ result: { ok: true },
1024
+ };
1025
+ }
1005
1026
  if (request.request_type === "stream_subscribe") {
1006
1027
  const streamId = typeof request.payload?.stream_id === "string"
1007
1028
  ? request.payload.stream_id.trim()
@@ -1582,7 +1603,9 @@ const TelegramMcpGatewaySocketService = {
1582
1603
  requestId,
1583
1604
  actionName,
1584
1605
  error: formattedError,
1585
- payload: parsed.payload ?? {},
1606
+ payload: actionName === "telegramMcp.fileContent.uploadFileRemote"
1607
+ ? { ...(parsed.payload ?? {}), upload_url: "[redacted]" }
1608
+ : (parsed.payload ?? {}),
1586
1609
  });
1587
1610
  this.wsClient?.send(JSON.stringify({
1588
1611
  type: "action_response",
@@ -1956,16 +1979,11 @@ const TelegramMcpGatewaySocketService = {
1956
1979
  }
1957
1980
  const httpServer = await this.waitForHttpServer?.();
1958
1981
  const wsPath = runtime.config.distributed.gatewayWsPath.replace(/\/+$/u, "") || "/";
1959
- const wsServer = new WebSocketServer({ noServer: true });
1982
+ const wsServer = new WebSocketServer({
1983
+ noServer: true,
1984
+ maxPayload: bodyLimits_1.MAX_BODY_SIZE_BYTES,
1985
+ });
1960
1986
  wsServer.on("connection", (socket, req) => {
1961
- if (runtime.config.distributed.gatewayAuthToken) {
1962
- const authorization = req.headers?.authorization;
1963
- if (authorization !==
1964
- `Bearer ${runtime.config.distributed.gatewayAuthToken}`) {
1965
- socket.close(1008, "Unauthorized");
1966
- return;
1967
- }
1968
- }
1969
1987
  runtime.logger.warn("Gateway WS client connected", {
1970
1988
  remoteAddress: req.socket.remoteAddress,
1971
1989
  path: req.url,
@@ -1977,6 +1995,11 @@ const TelegramMcpGatewaySocketService = {
1977
1995
  });
1978
1996
  });
1979
1997
  });
1998
+ socket.on("error", (error) => {
1999
+ runtime.logger.warn("Gateway WS server socket error", {
2000
+ error: error instanceof Error ? error.message : String(error),
2001
+ });
2002
+ });
1980
2003
  socket.on("close", () => {
1981
2004
  const hello = this.connectedClients?.get(socket);
1982
2005
  if (hello?.connection_id) {
@@ -2026,6 +2049,14 @@ const TelegramMcpGatewaySocketService = {
2026
2049
  if (requestPath !== wsPath) {
2027
2050
  return;
2028
2051
  }
2052
+ if (!(0, gatewayAuth_1.isGatewayAuthorizationValid)(req.headers.authorization, runtime.config.distributed.gatewayAuthToken)) {
2053
+ socket.write("HTTP/1.1 401 Unauthorized\r\n" +
2054
+ "Connection: close\r\n" +
2055
+ "Content-Length: 0\r\n" +
2056
+ "\r\n");
2057
+ socket.destroy();
2058
+ return;
2059
+ }
2029
2060
  wsServer.handleUpgrade(req, socket, head, (clientSocket) => {
2030
2061
  wsServer.emit("connection", clientSocket, req);
2031
2062
  });
@@ -2082,6 +2113,7 @@ const TelegramMcpGatewaySocketService = {
2082
2113
  const normalizedUrl = normalizeWebSocketUrl(wsUrl, runtime.config.distributed.gatewayWsPath);
2083
2114
  this.wsConnectionId = (0, node_crypto_1.randomUUID)();
2084
2115
  const socket = new wsLib.WebSocket(normalizedUrl, {
2116
+ maxPayload: bodyLimits_1.MAX_BODY_SIZE_BYTES,
2085
2117
  headers: runtime.config.distributed.gatewayAuthToken
2086
2118
  ? {
2087
2119
  authorization: `Bearer ${runtime.config.distributed.gatewayAuthToken}`,
@@ -69,6 +69,7 @@ const TelegramMcpHttpService = {
69
69
  path: runtime.config.mcp.httpPath,
70
70
  webappBasePath: runtime.config.webapp.basePath,
71
71
  bearerAuthEnabled: Boolean(runtime.config.mcp.bearerToken),
72
+ oauthConnectorEnabled: Boolean(runtime.config.oauth),
72
73
  });
73
74
  },
74
75
  async stopped() {
@@ -5,22 +5,32 @@ const server_1 = require("./src/app/providers/mcp/server");
5
5
  const approval_service_1 = require("./approval.service");
6
6
  const browser_service_1 = require("./browser.service");
7
7
  const collaboration_service_1 = require("./collaboration.service");
8
+ const file_content_service_1 = require("./file-content.service");
8
9
  const notify_service_1 = require("./notify.service");
9
10
  const session_context_service_1 = require("./session-context.service");
10
11
  const tools_sync_service_1 = require("./tools-sync.service");
11
12
  const xchange_service_1 = require("./xchange.service");
12
13
  const askUserTelegram_1 = require("./src/features/ask-user/model/askUserTelegram");
14
+ const browserAttachActiveTabTool_1 = require("./src/features/browser/model/browserAttachActiveTabTool");
15
+ const browserAttachTabTool_1 = require("./src/features/browser/model/browserAttachTabTool");
13
16
  const browserClickTool_1 = require("./src/features/browser/model/browserClickTool");
14
17
  const browserClearLogsTool_1 = require("./src/features/browser/model/browserClearLogsTool");
15
18
  const browserCloseTool_1 = require("./src/features/browser/model/browserCloseTool");
16
19
  const browserComputedStyleTool_1 = require("./src/features/browser/model/browserComputedStyleTool");
17
20
  const browserConsoleTool_1 = require("./src/features/browser/model/browserConsoleTool");
21
+ const browserDetachTabTool_1 = require("./src/features/browser/model/browserDetachTabTool");
18
22
  const browserDomTool_1 = require("./src/features/browser/model/browserDomTool");
19
23
  const browserErrorsTool_1 = require("./src/features/browser/model/browserErrorsTool");
20
24
  const browserFillTool_1 = require("./src/features/browser/model/browserFillTool");
25
+ const browserInjectScriptTool_1 = require("./src/features/browser/model/browserInjectScriptTool");
26
+ const browserListAttachedInstancesTool_1 = require("./src/features/browser/model/browserListAttachedInstancesTool");
27
+ const browserListTabsTool_1 = require("./src/features/browser/model/browserListTabsTool");
21
28
  const browserNetworkFailuresTool_1 = require("./src/features/browser/model/browserNetworkFailuresTool");
22
29
  const browserOpenTool_1 = require("./src/features/browser/model/browserOpenTool");
23
30
  const browserPressTool_1 = require("./src/features/browser/model/browserPressTool");
31
+ const browserRecordingStartTool_1 = require("./src/features/browser/model/browserRecordingStartTool");
32
+ const browserRecordingStatusTool_1 = require("./src/features/browser/model/browserRecordingStatusTool");
33
+ const browserRecordingStopTool_1 = require("./src/features/browser/model/browserRecordingStopTool");
24
34
  const browserReloadTool_1 = require("./src/features/browser/model/browserReloadTool");
25
35
  const browserScreenshotTool_1 = require("./src/features/browser/model/browserScreenshotTool");
26
36
  const browserWaitForTool_1 = require("./src/features/browser/model/browserWaitForTool");
@@ -28,6 +38,8 @@ const browserWaitForUrlTool_1 = require("./src/features/browser/model/browserWai
28
38
  const sendPartnerFileTool_1 = require("./src/features/collaboration/model/sendPartnerFileTool");
29
39
  const listGatewaySessionsTool_1 = require("./src/features/collaboration/model/listGatewaySessionsTool");
30
40
  const sendPartnerNoteTool_1 = require("./src/features/collaboration/model/sendPartnerNoteTool");
41
+ const getFileTool_1 = require("./src/features/file-content/model/getFileTool");
42
+ const getFileListTool_1 = require("./src/features/file-content/model/getFileListTool");
31
43
  const sendFileToTelegramTool_1 = require("./src/features/notify/model/sendFileToTelegramTool");
32
44
  const notifyTelegramTool_1 = require("./src/features/notify/model/notifyTelegramTool");
33
45
  const clearSessionContextTool_1 = require("./src/features/session-context/model/clearSessionContextTool");
@@ -47,6 +59,7 @@ const TelegramMcpMcpServerService = {
47
59
  approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
48
60
  browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
49
61
  collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
62
+ file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
50
63
  tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
51
64
  xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
52
65
  ],
@@ -57,6 +70,7 @@ const TelegramMcpMcpServerService = {
57
70
  const approvalService = this.broker.getLocalService(approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME);
58
71
  const browserService = this.broker.getLocalService(browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME);
59
72
  const collaborationService = this.broker.getLocalService(collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME);
73
+ const fileContentService = this.broker.getLocalService(file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME);
60
74
  const toolsSyncService = this.broker.getLocalService(tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME);
61
75
  const xchangeService = this.broker.getLocalService(xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME);
62
76
  if (!sessionContextService ||
@@ -64,6 +78,7 @@ const TelegramMcpMcpServerService = {
64
78
  !approvalService ||
65
79
  !browserService ||
66
80
  !collaborationService ||
81
+ !fileContentService ||
67
82
  !toolsSyncService ||
68
83
  !xchangeService) {
69
84
  throw new Error("telegram_mcp MCP server dependencies are not ready");
@@ -76,10 +91,19 @@ const TelegramMcpMcpServerService = {
76
91
  new notifyTelegramTool_1.NotifyTelegramTool(notifyService.getNotifyService()),
77
92
  new sendFileToTelegramTool_1.SendFileToTelegramTool(notifyService.getNotifyService()),
78
93
  new askUserTelegram_1.AskUserTelegramTool(approvalService.getApprovalOrchestrator()),
94
+ new browserListAttachedInstancesTool_1.BrowserListAttachedInstancesTool(browserService.getBrowserService()),
95
+ new browserListTabsTool_1.BrowserListTabsTool(browserService.getBrowserService()),
96
+ new browserAttachActiveTabTool_1.BrowserAttachActiveTabTool(browserService.getBrowserService()),
97
+ new browserAttachTabTool_1.BrowserAttachTabTool(browserService.getBrowserService()),
98
+ new browserDetachTabTool_1.BrowserDetachTabTool(browserService.getBrowserService()),
99
+ new browserRecordingStartTool_1.BrowserRecordingStartTool(browserService.getBrowserService()),
100
+ new browserRecordingStopTool_1.BrowserRecordingStopTool(browserService.getBrowserService()),
101
+ new browserRecordingStatusTool_1.BrowserRecordingStatusTool(browserService.getBrowserService()),
79
102
  new browserOpenTool_1.BrowserOpenTool(browserService.getBrowserService()),
80
103
  new browserReloadTool_1.BrowserReloadTool(browserService.getBrowserService()),
81
104
  new browserClickTool_1.BrowserClickTool(browserService.getBrowserService()),
82
105
  new browserFillTool_1.BrowserFillTool(browserService.getBrowserService()),
106
+ new browserInjectScriptTool_1.BrowserInjectScriptTool(browserService.getBrowserService()),
83
107
  new browserPressTool_1.BrowserPressTool(browserService.getBrowserService()),
84
108
  new browserWaitForTool_1.BrowserWaitForTool(browserService.getBrowserService()),
85
109
  new browserWaitForUrlTool_1.BrowserWaitForUrlTool(browserService.getBrowserService()),
@@ -94,11 +118,16 @@ const TelegramMcpMcpServerService = {
94
118
  new sendPartnerNoteTool_1.SendPartnerNoteTool(collaborationService.getCollaborationService()),
95
119
  new listGatewaySessionsTool_1.ListGatewaySessionsTool(collaborationService.getGatewaySessionsService()),
96
120
  new sendPartnerFileTool_1.SendPartnerFileTool(collaborationService.getSendPartnerFileService()),
121
+ new getFileTool_1.GetFileTool(fileContentService.getGetFileService()),
122
+ new getFileListTool_1.GetFileListTool(fileContentService.getGetFileService()),
97
123
  new listXchangeRecordsTool_1.ListXchangeRecordsTool(xchangeService.getXchangeService()),
98
124
  new getXchangeRecordTool_1.GetXchangeRecordTool(xchangeService.getXchangeService()),
99
125
  new markXchangeRecordReadTool_1.MarkXchangeRecordReadTool(xchangeService.getXchangeService()),
100
126
  new refreshToolsMarkdownTool_1.RefreshToolsMarkdownTool(toolsSyncService.getRefreshToolsMarkdownService()),
101
127
  ];
128
+ this.logger.info("telegram_mcp MCP server instance created", {
129
+ toolCount: tools.length,
130
+ });
102
131
  return (0, server_1.createMcpServer)(tools);
103
132
  },
104
133
  },
@@ -109,6 +138,7 @@ const TelegramMcpMcpServerService = {
109
138
  approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
110
139
  browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
111
140
  collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
141
+ file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
112
142
  tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
113
143
  xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
114
144
  ]);