@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.
- package/.env.example.client +5 -1
- package/.env.example.gateway +16 -1
- package/CHANGELOG.md +30 -0
- package/README-ru.md +14 -0
- package/README.md +14 -0
- package/TOOLS.md +182 -10
- package/config/templates/env.both.template +15 -2
- package/config/templates/env.client.template +5 -2
- package/config/templates/env.gateway.template +15 -2
- package/dist/cli.js +28 -1
- package/dist/services/features/telegram-mcp/browser.service.js +18 -0
- package/dist/services/features/telegram-mcp/file-content.service.js +94 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +5 -1
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +43 -11
- package/dist/services/features/telegram-mcp/mcp-http.service.js +1 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +9 -1
- package/dist/services/features/telegram-mcp/src/app/config/env.js +119 -2
- package/dist/services/features/telegram-mcp/src/app/http.js +139 -99
- package/dist/services/features/telegram-mcp/src/app/oauthFacade.js +642 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +151 -170
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +96 -99
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +62 -19
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachActiveTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +410 -27
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +37 -3
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +7 -6
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +214 -37
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +186 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +4 -1
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -35
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +5 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +3 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
- package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
- package/docs/CHAT_CONNECTOR.md +134 -0
- package/docs/STANDALONE-ru.md +13 -0
- package/docs/STANDALONE.md +13 -0
- package/package.json +5 -3
- package/packages/chrome-attach-extension/dist/background.js +572 -163
- package/packages/chrome-attach-extension/dist/manifest.json +2 -1
- package/packages/chrome-attach-extension/dist/options.js +15 -2
- package/packages/chrome-attach-extension/dist/recorder-content.js +14 -1
- package/packages/chrome-attach-extension/dist/recorder-page.js +34 -18
- package/packages/firefox-attach-extension/dist/background.js +413 -33
- package/packages/firefox-attach-extension/dist/manifest.json +0 -12
- package/packages/firefox-attach-extension/dist/options.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-content.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-page.js +34 -18
|
@@ -33,6 +33,24 @@ const TelegramMcpBrowserService = {
|
|
|
33
33
|
return this.getBrowserService().listTabs(ctx.params);
|
|
34
34
|
},
|
|
35
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
|
+
},
|
|
36
54
|
startRecordingRemote: {
|
|
37
55
|
params: { $$strict: false },
|
|
38
56
|
async handler(ctx) {
|
|
@@ -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
|
-
|
|
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:
|
|
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({
|
|
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,16 +5,20 @@ 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");
|
|
@@ -34,6 +38,8 @@ const browserWaitForUrlTool_1 = require("./src/features/browser/model/browserWai
|
|
|
34
38
|
const sendPartnerFileTool_1 = require("./src/features/collaboration/model/sendPartnerFileTool");
|
|
35
39
|
const listGatewaySessionsTool_1 = require("./src/features/collaboration/model/listGatewaySessionsTool");
|
|
36
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");
|
|
37
43
|
const sendFileToTelegramTool_1 = require("./src/features/notify/model/sendFileToTelegramTool");
|
|
38
44
|
const notifyTelegramTool_1 = require("./src/features/notify/model/notifyTelegramTool");
|
|
39
45
|
const clearSessionContextTool_1 = require("./src/features/session-context/model/clearSessionContextTool");
|
|
@@ -53,6 +59,7 @@ const TelegramMcpMcpServerService = {
|
|
|
53
59
|
approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
|
|
54
60
|
browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
|
|
55
61
|
collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
|
|
62
|
+
file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
|
|
56
63
|
tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
|
|
57
64
|
xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
|
|
58
65
|
],
|
|
@@ -63,6 +70,7 @@ const TelegramMcpMcpServerService = {
|
|
|
63
70
|
const approvalService = this.broker.getLocalService(approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME);
|
|
64
71
|
const browserService = this.broker.getLocalService(browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME);
|
|
65
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);
|
|
66
74
|
const toolsSyncService = this.broker.getLocalService(tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME);
|
|
67
75
|
const xchangeService = this.broker.getLocalService(xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME);
|
|
68
76
|
if (!sessionContextService ||
|
|
@@ -70,6 +78,7 @@ const TelegramMcpMcpServerService = {
|
|
|
70
78
|
!approvalService ||
|
|
71
79
|
!browserService ||
|
|
72
80
|
!collaborationService ||
|
|
81
|
+
!fileContentService ||
|
|
73
82
|
!toolsSyncService ||
|
|
74
83
|
!xchangeService) {
|
|
75
84
|
throw new Error("telegram_mcp MCP server dependencies are not ready");
|
|
@@ -84,6 +93,9 @@ const TelegramMcpMcpServerService = {
|
|
|
84
93
|
new askUserTelegram_1.AskUserTelegramTool(approvalService.getApprovalOrchestrator()),
|
|
85
94
|
new browserListAttachedInstancesTool_1.BrowserListAttachedInstancesTool(browserService.getBrowserService()),
|
|
86
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()),
|
|
87
99
|
new browserRecordingStartTool_1.BrowserRecordingStartTool(browserService.getBrowserService()),
|
|
88
100
|
new browserRecordingStopTool_1.BrowserRecordingStopTool(browserService.getBrowserService()),
|
|
89
101
|
new browserRecordingStatusTool_1.BrowserRecordingStatusTool(browserService.getBrowserService()),
|
|
@@ -106,11 +118,16 @@ const TelegramMcpMcpServerService = {
|
|
|
106
118
|
new sendPartnerNoteTool_1.SendPartnerNoteTool(collaborationService.getCollaborationService()),
|
|
107
119
|
new listGatewaySessionsTool_1.ListGatewaySessionsTool(collaborationService.getGatewaySessionsService()),
|
|
108
120
|
new sendPartnerFileTool_1.SendPartnerFileTool(collaborationService.getSendPartnerFileService()),
|
|
121
|
+
new getFileTool_1.GetFileTool(fileContentService.getGetFileService()),
|
|
122
|
+
new getFileListTool_1.GetFileListTool(fileContentService.getGetFileService()),
|
|
109
123
|
new listXchangeRecordsTool_1.ListXchangeRecordsTool(xchangeService.getXchangeService()),
|
|
110
124
|
new getXchangeRecordTool_1.GetXchangeRecordTool(xchangeService.getXchangeService()),
|
|
111
125
|
new markXchangeRecordReadTool_1.MarkXchangeRecordReadTool(xchangeService.getXchangeService()),
|
|
112
126
|
new refreshToolsMarkdownTool_1.RefreshToolsMarkdownTool(toolsSyncService.getRefreshToolsMarkdownService()),
|
|
113
127
|
];
|
|
128
|
+
this.logger.info("telegram_mcp MCP server instance created", {
|
|
129
|
+
toolCount: tools.length,
|
|
130
|
+
});
|
|
114
131
|
return (0, server_1.createMcpServer)(tools);
|
|
115
132
|
},
|
|
116
133
|
},
|
|
@@ -121,6 +138,7 @@ const TelegramMcpMcpServerService = {
|
|
|
121
138
|
approval_service_1.TELEGRAM_MCP_APPROVAL_SERVICE_NAME,
|
|
122
139
|
browser_service_1.TELEGRAM_MCP_BROWSER_SERVICE_NAME,
|
|
123
140
|
collaboration_service_1.TELEGRAM_MCP_COLLABORATION_SERVICE_NAME,
|
|
141
|
+
file_content_service_1.TELEGRAM_MCP_FILE_CONTENT_SERVICE_NAME,
|
|
124
142
|
tools_sync_service_1.TELEGRAM_MCP_TOOLS_SYNC_SERVICE_NAME,
|
|
125
143
|
xchange_service_1.TELEGRAM_MCP_XCHANGE_SERVICE_NAME,
|
|
126
144
|
]);
|
|
@@ -13,6 +13,7 @@ const minioExchangeStore_1 = require("../../shared/integrations/object-storage/m
|
|
|
13
13
|
const gatewayHttpService_1 = require("../../features/distributed-gateway/model/gatewayHttpService");
|
|
14
14
|
const gatewayClientAccess_1 = require("../../features/distributed-client/model/gatewayClientAccess");
|
|
15
15
|
const firefoxAttachServer_1 = require("../../features/browser-attach/model/firefoxAttachServer");
|
|
16
|
+
const temporaryFileLinkStore_1 = require("../../features/file-content/model/temporaryFileLinkStore");
|
|
16
17
|
const client_2 = require("../../shared/integrations/terminal/client");
|
|
17
18
|
const ptyRegistry_1 = require("../../shared/integrations/terminal/ptyRegistry");
|
|
18
19
|
async function createAppRuntime(input) {
|
|
@@ -34,6 +35,7 @@ async function createAppRuntime(input) {
|
|
|
34
35
|
httpPort: config.mcp.httpPort,
|
|
35
36
|
httpPath: config.mcp.httpPath,
|
|
36
37
|
bearerAuthEnabled: Boolean(config.mcp.bearerToken),
|
|
38
|
+
oauthConnectorEnabled: Boolean(config.oauth),
|
|
37
39
|
enableDebugRoutes: config.mcp.enableDebugRoutes,
|
|
38
40
|
enablePruneRoute: config.mcp.enablePruneRoute,
|
|
39
41
|
},
|
|
@@ -56,7 +58,6 @@ async function createAppRuntime(input) {
|
|
|
56
58
|
initDataTtlSeconds: config.webapp.initDataTtlSeconds,
|
|
57
59
|
sessionTtlSeconds: config.webapp.sessionTtlSeconds,
|
|
58
60
|
launchMode: config.webapp.launchMode,
|
|
59
|
-
pollIntervalMs: config.webapp.pollIntervalMs,
|
|
60
61
|
actionCooldownMs: config.webapp.actionCooldownMs,
|
|
61
62
|
},
|
|
62
63
|
terminal: {
|
|
@@ -210,6 +211,11 @@ async function createAppRuntime(input) {
|
|
|
210
211
|
await telegramTransport.sendStartupNotifications();
|
|
211
212
|
logger.info("Startup Telegram notifications completed");
|
|
212
213
|
const gatewayHttpService = new gatewayHttpService_1.GatewayHttpService(config, input.callBroker);
|
|
214
|
+
const temporaryFileLinkStore = config.distributed.mode !== "client" &&
|
|
215
|
+
config.distributed.gatewayPublicUrl?.trim()
|
|
216
|
+
? new temporaryFileLinkStore_1.TemporaryFileLinkStore(config.distributed.gatewayPublicUrl, logger)
|
|
217
|
+
: null;
|
|
218
|
+
await temporaryFileLinkStore?.start();
|
|
213
219
|
const firefoxAttachServer = new firefoxAttachServer_1.FirefoxAttachServer(config, logger, stateStore, stateStore);
|
|
214
220
|
await firefoxAttachServer.start();
|
|
215
221
|
return {
|
|
@@ -230,8 +236,10 @@ async function createAppRuntime(input) {
|
|
|
230
236
|
webAppLaunchRegistry,
|
|
231
237
|
gatewayHttpService,
|
|
232
238
|
firefoxAttachServer,
|
|
239
|
+
temporaryFileLinkStore,
|
|
233
240
|
shutdown: async () => {
|
|
234
241
|
logger.info("Shutdown started");
|
|
242
|
+
await temporaryFileLinkStore?.stop();
|
|
235
243
|
await firefoxAttachServer.stop();
|
|
236
244
|
await telegramTransport.stop();
|
|
237
245
|
(0, ptyRegistry_1.stopAllPtyTargets)();
|
|
@@ -93,6 +93,22 @@ const envSchema = z.object({
|
|
|
93
93
|
MCP_HTTP_PORT: z.coerce.number().int().positive().default(8787),
|
|
94
94
|
MCP_HTTP_PATH: z.string().min(1).default("/mcp"),
|
|
95
95
|
MCP_HTTP_BEARER_TOKEN: optionalNonEmptyString,
|
|
96
|
+
TELLYMCP_PUBLIC_URL: optionalUrlString,
|
|
97
|
+
TELLYMCP_OAUTH_ISSUER: optionalUrlString,
|
|
98
|
+
TELLYMCP_OAUTH_AUDIENCE: optionalUrlString,
|
|
99
|
+
TELLYMCP_MAGIC_TOKEN: optionalNonEmptyString,
|
|
100
|
+
TELLYMCP_MAGIC_TOKEN_HASH: optionalNonEmptyString,
|
|
101
|
+
TELLYMCP_OAUTH_CLIENT_ID: optionalNonEmptyString,
|
|
102
|
+
TELLYMCP_OAUTH_CLIENT_SECRET: optionalNonEmptyString,
|
|
103
|
+
TELLYMCP_ALLOWED_REDIRECT_URIS: optionalNonEmptyString,
|
|
104
|
+
TELLYMCP_OAUTH_PRIVATE_KEY_PEM: optionalNonEmptyString,
|
|
105
|
+
TELLYMCP_AUTH_CODE_TTL_SECONDS: z.coerce
|
|
106
|
+
.number()
|
|
107
|
+
.int()
|
|
108
|
+
.positive()
|
|
109
|
+
.default(300),
|
|
110
|
+
TELLYMCP_OAUTH_SCOPES: z.string().min(1).default("tellymcp:read tellymcp:write"),
|
|
111
|
+
TELLYMCP_OAUTH_KEY_ID: z.string().min(1).default("tellymcp-oauth"),
|
|
96
112
|
MCP_HTTP_ENABLE_DEBUG_ROUTES: z
|
|
97
113
|
.string()
|
|
98
114
|
.optional()
|
|
@@ -145,7 +161,6 @@ const envSchema = z.object({
|
|
|
145
161
|
.enum(["default", "expand", "fullscreen"])
|
|
146
162
|
.default("fullscreen"),
|
|
147
163
|
WEBAPP_VISIBLE_SCREENS: z.coerce.number().int().positive().default(2),
|
|
148
|
-
WEBAPP_POLL_INTERVAL_MS: z.coerce.number().int().positive().default(2000),
|
|
149
164
|
WEBAPP_ACTION_COOLDOWN_MS: z.coerce.number().int().nonnegative().default(150),
|
|
150
165
|
MCP_XCHANGE_DIR: z.string().min(1).default(".mcp-xchange"),
|
|
151
166
|
TERMINAL_SHELL: z.string().min(1).default(process.env.SHELL || "bash"),
|
|
@@ -246,6 +261,16 @@ function loadConfig() {
|
|
|
246
261
|
!parsed.TELEGRAM_BOT_TOKEN?.trim()) {
|
|
247
262
|
throw new Error("TELEGRAM_BOT_TOKEN is required for gateway and both distributed modes.");
|
|
248
263
|
}
|
|
264
|
+
const gatewayServerEnabled = parsed.DISTRIBUTED_MODE === "gateway" ||
|
|
265
|
+
parsed.DISTRIBUTED_MODE === "both";
|
|
266
|
+
const gatewayClientConfigured = parsed.DISTRIBUTED_MODE === "client" &&
|
|
267
|
+
Boolean(parsed.GATEWAY_PUBLIC_URL || parsed.GATEWAY_WS_URL);
|
|
268
|
+
if ((gatewayServerEnabled || gatewayClientConfigured) &&
|
|
269
|
+
!parsed.GATEWAY_AUTH_TOKEN?.trim()) {
|
|
270
|
+
throw new Error(gatewayServerEnabled
|
|
271
|
+
? "GATEWAY_AUTH_TOKEN is required for gateway and both distributed modes."
|
|
272
|
+
: "GATEWAY_AUTH_TOKEN is required when a client connects to a gateway.");
|
|
273
|
+
}
|
|
249
274
|
if (parsed.ADMIN_TOKEN?.trim() && !parsed.TELEGRAM_BOT_TOKEN?.trim()) {
|
|
250
275
|
throw new Error("ADMIN_TOKEN requires TELEGRAM_BOT_TOKEN because admin mode runs through the gateway bot.");
|
|
251
276
|
}
|
|
@@ -257,6 +282,69 @@ function loadConfig() {
|
|
|
257
282
|
throw new Error("TELEGRAM_WEBHOOK_ENABLED=true requires TELEGRAM_WEBHOOK_SECRET.");
|
|
258
283
|
}
|
|
259
284
|
}
|
|
285
|
+
const oauthConfigured = Boolean(parsed.TELLYMCP_PUBLIC_URL ||
|
|
286
|
+
parsed.TELLYMCP_OAUTH_ISSUER ||
|
|
287
|
+
parsed.TELLYMCP_OAUTH_AUDIENCE ||
|
|
288
|
+
parsed.TELLYMCP_MAGIC_TOKEN ||
|
|
289
|
+
parsed.TELLYMCP_MAGIC_TOKEN_HASH ||
|
|
290
|
+
parsed.TELLYMCP_OAUTH_CLIENT_ID ||
|
|
291
|
+
parsed.TELLYMCP_OAUTH_CLIENT_SECRET ||
|
|
292
|
+
parsed.TELLYMCP_ALLOWED_REDIRECT_URIS ||
|
|
293
|
+
parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM);
|
|
294
|
+
if (oauthConfigured && !parsed.TELLYMCP_PUBLIC_URL) {
|
|
295
|
+
throw new Error("TELLYMCP_PUBLIC_URL is required when OAuth connector settings are configured.");
|
|
296
|
+
}
|
|
297
|
+
if (oauthConfigured &&
|
|
298
|
+
!parsed.TELLYMCP_MAGIC_TOKEN &&
|
|
299
|
+
!parsed.TELLYMCP_MAGIC_TOKEN_HASH) {
|
|
300
|
+
throw new Error("TELLYMCP_MAGIC_TOKEN or TELLYMCP_MAGIC_TOKEN_HASH is required when OAuth is configured.");
|
|
301
|
+
}
|
|
302
|
+
if (parsed.TELLYMCP_MAGIC_TOKEN && parsed.TELLYMCP_MAGIC_TOKEN_HASH) {
|
|
303
|
+
throw new Error("Configure only one of TELLYMCP_MAGIC_TOKEN and TELLYMCP_MAGIC_TOKEN_HASH.");
|
|
304
|
+
}
|
|
305
|
+
if (parsed.TELLYMCP_MAGIC_TOKEN_HASH &&
|
|
306
|
+
!/^sha256:[a-f0-9]{64}$/iu.test(parsed.TELLYMCP_MAGIC_TOKEN_HASH)) {
|
|
307
|
+
throw new Error("TELLYMCP_MAGIC_TOKEN_HASH must use the format sha256:<64 hex characters>.");
|
|
308
|
+
}
|
|
309
|
+
if (parsed.TELLYMCP_OAUTH_CLIENT_SECRET && !parsed.TELLYMCP_OAUTH_CLIENT_ID) {
|
|
310
|
+
throw new Error("TELLYMCP_OAUTH_CLIENT_SECRET requires TELLYMCP_OAUTH_CLIENT_ID.");
|
|
311
|
+
}
|
|
312
|
+
for (const [name, value] of [
|
|
313
|
+
["TELLYMCP_PUBLIC_URL", parsed.TELLYMCP_PUBLIC_URL],
|
|
314
|
+
["TELLYMCP_OAUTH_ISSUER", parsed.TELLYMCP_OAUTH_ISSUER],
|
|
315
|
+
["TELLYMCP_OAUTH_AUDIENCE", parsed.TELLYMCP_OAUTH_AUDIENCE],
|
|
316
|
+
]) {
|
|
317
|
+
if (!value) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const url = new URL(value);
|
|
321
|
+
if (url.search || url.hash) {
|
|
322
|
+
throw new Error(`${name} must not contain a query string or fragment.`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const oauthScopes = parsed.TELLYMCP_OAUTH_SCOPES
|
|
326
|
+
.split(/[\s,]+/u)
|
|
327
|
+
.map((scope) => scope.trim())
|
|
328
|
+
.filter(Boolean);
|
|
329
|
+
if (oauthConfigured && oauthScopes.length === 0) {
|
|
330
|
+
throw new Error("TELLYMCP_OAUTH_SCOPES must contain at least one scope.");
|
|
331
|
+
}
|
|
332
|
+
const allowedRedirectUris = parsed.TELLYMCP_ALLOWED_REDIRECT_URIS
|
|
333
|
+
? parsed.TELLYMCP_ALLOWED_REDIRECT_URIS.split(",")
|
|
334
|
+
.map((redirectUri) => redirectUri.trim())
|
|
335
|
+
.filter(Boolean)
|
|
336
|
+
: [];
|
|
337
|
+
for (const redirectUri of allowedRedirectUris) {
|
|
338
|
+
try {
|
|
339
|
+
const parsedRedirectUri = new URL(redirectUri);
|
|
340
|
+
if (parsedRedirectUri.hash) {
|
|
341
|
+
throw new Error("fragment");
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
throw new Error(`TELLYMCP_ALLOWED_REDIRECT_URIS contains an invalid URL: ${redirectUri}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
260
348
|
const telegramProxy = parsed.PROXY_USE === "http"
|
|
261
349
|
? parsed.HTTP_PROXY
|
|
262
350
|
? {
|
|
@@ -328,6 +416,36 @@ function loadConfig() {
|
|
|
328
416
|
enableDebugRoutes: parsed.MCP_HTTP_ENABLE_DEBUG_ROUTES,
|
|
329
417
|
enablePruneRoute: parsed.MCP_HTTP_ENABLE_PRUNE_ROUTE,
|
|
330
418
|
},
|
|
419
|
+
...(oauthConfigured && parsed.TELLYMCP_PUBLIC_URL
|
|
420
|
+
? {
|
|
421
|
+
oauth: {
|
|
422
|
+
publicUrl: parsed.TELLYMCP_PUBLIC_URL.replace(/\/+$/u, ""),
|
|
423
|
+
issuer: (parsed.TELLYMCP_OAUTH_ISSUER ?? parsed.TELLYMCP_PUBLIC_URL).replace(/\/+$/u, ""),
|
|
424
|
+
audience: (parsed.TELLYMCP_OAUTH_AUDIENCE ?? parsed.TELLYMCP_PUBLIC_URL).replace(/\/+$/u, ""),
|
|
425
|
+
...(parsed.TELLYMCP_MAGIC_TOKEN
|
|
426
|
+
? { magicToken: parsed.TELLYMCP_MAGIC_TOKEN }
|
|
427
|
+
: {}),
|
|
428
|
+
...(parsed.TELLYMCP_MAGIC_TOKEN_HASH
|
|
429
|
+
? { magicTokenHash: parsed.TELLYMCP_MAGIC_TOKEN_HASH }
|
|
430
|
+
: {}),
|
|
431
|
+
...(parsed.TELLYMCP_OAUTH_CLIENT_ID
|
|
432
|
+
? { clientId: parsed.TELLYMCP_OAUTH_CLIENT_ID }
|
|
433
|
+
: {}),
|
|
434
|
+
...(parsed.TELLYMCP_OAUTH_CLIENT_SECRET
|
|
435
|
+
? { clientSecret: parsed.TELLYMCP_OAUTH_CLIENT_SECRET }
|
|
436
|
+
: {}),
|
|
437
|
+
allowedRedirectUris,
|
|
438
|
+
...(parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM
|
|
439
|
+
? {
|
|
440
|
+
privateKeyPem: parsed.TELLYMCP_OAUTH_PRIVATE_KEY_PEM.replace(/\\n/gu, "\n"),
|
|
441
|
+
}
|
|
442
|
+
: {}),
|
|
443
|
+
authCodeTtlSeconds: parsed.TELLYMCP_AUTH_CODE_TTL_SECONDS,
|
|
444
|
+
scopes: oauthScopes,
|
|
445
|
+
keyId: parsed.TELLYMCP_OAUTH_KEY_ID,
|
|
446
|
+
},
|
|
447
|
+
}
|
|
448
|
+
: {}),
|
|
331
449
|
distributed: {
|
|
332
450
|
mode: parsed.DISTRIBUTED_MODE,
|
|
333
451
|
...(parsed.GATEWAY_PUBLIC_URL
|
|
@@ -386,7 +504,6 @@ function loadConfig() {
|
|
|
386
504
|
sessionTtlSeconds: parsed.WEBAPP_SESSION_TTL_SECONDS,
|
|
387
505
|
launchMode: parsed.WEBAPP_LAUNCH_MODE,
|
|
388
506
|
visibleScreens: parsed.WEBAPP_VISIBLE_SCREENS,
|
|
389
|
-
pollIntervalMs: parsed.WEBAPP_POLL_INTERVAL_MS,
|
|
390
507
|
actionCooldownMs: parsed.WEBAPP_ACTION_COOLDOWN_MS,
|
|
391
508
|
},
|
|
392
509
|
exchange: {
|