@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.
- package/.env.example.client +5 -1
- package/.env.example.gateway +16 -1
- package/CHANGELOG.md +30 -0
- package/README-ru.md +33 -0
- package/README.md +33 -0
- package/TOOLS.md +384 -9
- 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 +137 -2
- package/dist/services/features/telegram-mcp/browser.service.js +56 -1
- 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 +30 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +23 -1
- package/dist/services/features/telegram-mcp/src/app/config/env.js +132 -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 +205 -17
- 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/browserClickTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserInjectScriptTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStartTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStatusTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStopTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +890 -23
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +536 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +80 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +736 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +188 -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/redis/stateStore.js +28 -0
- 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 +55 -6
- package/docs/STANDALONE.md +55 -6
- package/package.json +10 -5
- package/packages/chrome-attach-extension/dist/background.js +1735 -0
- package/packages/chrome-attach-extension/dist/icon.svg +6 -0
- package/packages/chrome-attach-extension/dist/manifest.json +37 -0
- package/packages/chrome-attach-extension/dist/options.html +312 -0
- package/packages/chrome-attach-extension/dist/options.js +606 -0
- package/packages/chrome-attach-extension/dist/popup.html +93 -0
- package/packages/chrome-attach-extension/dist/popup.js +79 -0
- package/packages/chrome-attach-extension/dist/recorder-content.js +96 -0
- package/packages/chrome-attach-extension/dist/recorder-page.js +282 -0
- package/packages/firefox-attach-extension/README.md +13 -0
- package/packages/firefox-attach-extension/dist/background.js +1622 -0
- package/packages/firefox-attach-extension/dist/icon.svg +6 -0
- package/packages/firefox-attach-extension/dist/manifest.json +44 -0
- package/packages/firefox-attach-extension/dist/options.html +312 -0
- package/packages/firefox-attach-extension/dist/options.js +540 -0
- package/packages/firefox-attach-extension/dist/popup.html +93 -0
- package/packages/firefox-attach-extension/dist/popup.js +64 -0
- package/packages/firefox-attach-extension/dist/recorder-content.js +90 -0
- package/packages/firefox-attach-extension/dist/recorder-page.js +318 -0
|
@@ -54,6 +54,8 @@ exports.resizePtyTarget = resizePtyTarget;
|
|
|
54
54
|
exports.subscribePtyTarget = subscribePtyTarget;
|
|
55
55
|
exports.stopPtyTarget = stopPtyTarget;
|
|
56
56
|
exports.stopAllPtyTargets = stopAllPtyTargets;
|
|
57
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
58
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
57
59
|
const node_path_1 = __importDefault(require("node:path"));
|
|
58
60
|
const node_pty_1 = require("node-pty");
|
|
59
61
|
const XtermHeadless = __importStar(require("@xterm/headless"));
|
|
@@ -73,6 +75,97 @@ function buildExitLine(record) {
|
|
|
73
75
|
}
|
|
74
76
|
return `${parts.join(" ")}]`;
|
|
75
77
|
}
|
|
78
|
+
function sanitizeFileNameSegment(value) {
|
|
79
|
+
const sanitized = value.trim().replace(/[^a-zA-Z0-9._-]+/gu, "-");
|
|
80
|
+
return sanitized || "session";
|
|
81
|
+
}
|
|
82
|
+
function shellSingleQuote(value) {
|
|
83
|
+
return `'${value.replace(/'/gu, `'\\''`)}'`;
|
|
84
|
+
}
|
|
85
|
+
function buildContextPromptPrefix(record) {
|
|
86
|
+
return `[TELLY ${record.sessionId}]`;
|
|
87
|
+
}
|
|
88
|
+
function buildContextEnv(record) {
|
|
89
|
+
return {
|
|
90
|
+
...process.env,
|
|
91
|
+
TELLYMCP_TERMINAL_CONTEXT: "1",
|
|
92
|
+
TELLYMCP_SESSION_ID: record.sessionId,
|
|
93
|
+
TELLYMCP_TERMINAL_TARGET: record.target,
|
|
94
|
+
TELLYMCP_TERMINAL_CWD: record.cwd,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function prepareBashLaunch(record) {
|
|
98
|
+
const tempDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "tellymcp-pty-bash-"));
|
|
99
|
+
const rcPath = node_path_1.default.join(tempDir, `${sanitizeFileNameSegment(record.sessionId)}.bashrc`);
|
|
100
|
+
const promptPrefix = buildContextPromptPrefix(record);
|
|
101
|
+
const script = [
|
|
102
|
+
'if [ -r "$HOME/.profile" ]; then . "$HOME/.profile"; fi',
|
|
103
|
+
'if [ -r "$HOME/.bashrc" ]; then . "$HOME/.bashrc"; fi',
|
|
104
|
+
`export TELLYMCP_TERMINAL_CONTEXT=${shellSingleQuote("1")}`,
|
|
105
|
+
`export TELLYMCP_SESSION_ID=${shellSingleQuote(record.sessionId)}`,
|
|
106
|
+
`export TELLYMCP_TERMINAL_TARGET=${shellSingleQuote(record.target)}`,
|
|
107
|
+
`export TELLYMCP_TERMINAL_CWD=${shellSingleQuote(record.cwd)}`,
|
|
108
|
+
`PS1=${shellSingleQuote(`${promptPrefix} \\u@\\h:\\w\\$ `)}`,
|
|
109
|
+
].join("\n");
|
|
110
|
+
node_fs_1.default.writeFileSync(rcPath, `${script}\n`, "utf8");
|
|
111
|
+
return {
|
|
112
|
+
args: ["--rcfile", rcPath, "-i"],
|
|
113
|
+
env: buildContextEnv(record),
|
|
114
|
+
tempPaths: [tempDir],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function prepareZshLaunch(record) {
|
|
118
|
+
const tempDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "tellymcp-pty-zsh-"));
|
|
119
|
+
const promptPrefix = buildContextPromptPrefix(record);
|
|
120
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(tempDir, ".zshenv"), [
|
|
121
|
+
'if [[ -r "$HOME/.zshenv" ]]; then source "$HOME/.zshenv"; fi',
|
|
122
|
+
`export TELLYMCP_TERMINAL_CONTEXT=${shellSingleQuote("1")}`,
|
|
123
|
+
`export TELLYMCP_SESSION_ID=${shellSingleQuote(record.sessionId)}`,
|
|
124
|
+
`export TELLYMCP_TERMINAL_TARGET=${shellSingleQuote(record.target)}`,
|
|
125
|
+
`export TELLYMCP_TERMINAL_CWD=${shellSingleQuote(record.cwd)}`,
|
|
126
|
+
"",
|
|
127
|
+
].join("\n"), "utf8");
|
|
128
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(tempDir, ".zshrc"), [
|
|
129
|
+
'if [[ -r "$HOME/.zprofile" ]]; then source "$HOME/.zprofile"; fi',
|
|
130
|
+
'if [[ -r "$HOME/.zshrc" ]]; then source "$HOME/.zshrc"; fi',
|
|
131
|
+
`PROMPT=${shellSingleQuote(`${promptPrefix} %n@%m:%~%# `)}`,
|
|
132
|
+
"RPROMPT=''",
|
|
133
|
+
"",
|
|
134
|
+
].join("\n"), "utf8");
|
|
135
|
+
return {
|
|
136
|
+
args: ["-i"],
|
|
137
|
+
env: {
|
|
138
|
+
...buildContextEnv(record),
|
|
139
|
+
ZDOTDIR: tempDir,
|
|
140
|
+
},
|
|
141
|
+
tempPaths: [tempDir],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function prepareShellLaunch(record) {
|
|
145
|
+
const shellName = getShellDisplayName(record.shell).toLowerCase();
|
|
146
|
+
if (shellName === "bash") {
|
|
147
|
+
return prepareBashLaunch(record);
|
|
148
|
+
}
|
|
149
|
+
if (shellName === "zsh") {
|
|
150
|
+
return prepareZshLaunch(record);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
args: [],
|
|
154
|
+
env: buildContextEnv(record),
|
|
155
|
+
tempPaths: [],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function cleanupRecordTempPaths(record) {
|
|
159
|
+
for (const tempPath of record.tempPaths) {
|
|
160
|
+
try {
|
|
161
|
+
node_fs_1.default.rmSync(tempPath, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// ignore cleanup failures
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
record.tempPaths = [];
|
|
168
|
+
}
|
|
76
169
|
function createHeadlessTerminal(config) {
|
|
77
170
|
return new XtermHeadless.Terminal({
|
|
78
171
|
cols: config.cols,
|
|
@@ -97,13 +190,16 @@ function createSessionRecord(config, input) {
|
|
|
97
190
|
pendingWrite: Promise.resolve(),
|
|
98
191
|
pty: null,
|
|
99
192
|
exited: false,
|
|
193
|
+
tempPaths: [],
|
|
100
194
|
};
|
|
101
|
-
const
|
|
195
|
+
const launch = prepareShellLaunch(record);
|
|
196
|
+
record.tempPaths = [...launch.tempPaths];
|
|
197
|
+
const pty = (0, node_pty_1.spawn)(record.shell, launch.args, {
|
|
102
198
|
name: "xterm-color",
|
|
103
199
|
cols: record.cols,
|
|
104
200
|
rows: record.rows,
|
|
105
201
|
cwd: record.cwd,
|
|
106
|
-
env:
|
|
202
|
+
env: launch.env,
|
|
107
203
|
});
|
|
108
204
|
pty.onData((data) => {
|
|
109
205
|
record.pendingWrite = record.pendingWrite.then(() => new Promise((resolve) => {
|
|
@@ -115,6 +211,7 @@ function createSessionRecord(config, input) {
|
|
|
115
211
|
record.exited = true;
|
|
116
212
|
record.exitCode = exitCode;
|
|
117
213
|
record.signal = signal;
|
|
214
|
+
cleanupRecordTempPaths(record);
|
|
118
215
|
record.pendingWrite = record.pendingWrite.then(() => new Promise((resolve) => {
|
|
119
216
|
record.terminal.writeln(buildExitLine(record), resolve);
|
|
120
217
|
}));
|
|
@@ -533,6 +630,7 @@ function stopPtyTarget(target) {
|
|
|
533
630
|
record.pty?.kill();
|
|
534
631
|
record.pty = null;
|
|
535
632
|
record.exited = true;
|
|
633
|
+
cleanupRecordTempPaths(record);
|
|
536
634
|
record.terminal.dispose();
|
|
537
635
|
return true;
|
|
538
636
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readLimitedJsonBody = exports.assertSerializedBodySize = exports.assertStringBodySize = exports.assertBodySize = exports.isBodySizeLimitError = exports.BodySizeLimitError = exports.MAX_BASE64_SOURCE_SIZE_BYTES = exports.MAX_BODY_SIZE_BYTES = exports.MAX_BODY_SIZE = void 0;
|
|
4
|
+
exports.MAX_BODY_SIZE = 16;
|
|
5
|
+
exports.MAX_BODY_SIZE_BYTES = exports.MAX_BODY_SIZE * 1024 * 1024;
|
|
6
|
+
exports.MAX_BASE64_SOURCE_SIZE_BYTES = Math.floor((exports.MAX_BODY_SIZE_BYTES * 3) / 4);
|
|
7
|
+
class BodySizeLimitError extends Error {
|
|
8
|
+
actualBytes;
|
|
9
|
+
maxBytes;
|
|
10
|
+
statusCode = 413;
|
|
11
|
+
constructor(actualBytes, maxBytes = exports.MAX_BODY_SIZE_BYTES) {
|
|
12
|
+
const maxMiB = maxBytes / (1024 * 1024);
|
|
13
|
+
super(`Body size ${actualBytes} bytes exceeds the ${maxMiB} MiB limit.`);
|
|
14
|
+
this.actualBytes = actualBytes;
|
|
15
|
+
this.maxBytes = maxBytes;
|
|
16
|
+
this.name = "BodySizeLimitError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.BodySizeLimitError = BodySizeLimitError;
|
|
20
|
+
const isBodySizeLimitError = (error) => error instanceof BodySizeLimitError;
|
|
21
|
+
exports.isBodySizeLimitError = isBodySizeLimitError;
|
|
22
|
+
const assertBodySize = (actualBytes, maxBytes = exports.MAX_BODY_SIZE_BYTES) => {
|
|
23
|
+
if (actualBytes > maxBytes) {
|
|
24
|
+
throw new BodySizeLimitError(actualBytes, maxBytes);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
exports.assertBodySize = assertBodySize;
|
|
28
|
+
const assertStringBodySize = (value, maxBytes = exports.MAX_BODY_SIZE_BYTES) => {
|
|
29
|
+
(0, exports.assertBodySize)(Buffer.byteLength(value, "utf8"), maxBytes);
|
|
30
|
+
};
|
|
31
|
+
exports.assertStringBodySize = assertStringBodySize;
|
|
32
|
+
const assertSerializedBodySize = (value) => {
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
(0, exports.assertStringBodySize)(JSON.stringify(value));
|
|
37
|
+
};
|
|
38
|
+
exports.assertSerializedBodySize = assertSerializedBodySize;
|
|
39
|
+
const readLimitedJsonBody = async (req) => {
|
|
40
|
+
const contentLength = req.headers["content-length"];
|
|
41
|
+
if (typeof contentLength === "string" && /^\d+$/u.test(contentLength)) {
|
|
42
|
+
(0, exports.assertBodySize)(Number(contentLength));
|
|
43
|
+
}
|
|
44
|
+
const chunks = [];
|
|
45
|
+
let totalBytes = 0;
|
|
46
|
+
for await (const chunk of req) {
|
|
47
|
+
const buffer = Buffer.isBuffer(chunk)
|
|
48
|
+
? chunk
|
|
49
|
+
: Buffer.from(chunk);
|
|
50
|
+
totalBytes += buffer.byteLength;
|
|
51
|
+
(0, exports.assertBodySize)(totalBytes);
|
|
52
|
+
chunks.push(buffer);
|
|
53
|
+
}
|
|
54
|
+
if (chunks.length === 0) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const raw = Buffer.concat(chunks, totalBytes).toString("utf8").trim();
|
|
58
|
+
if (!raw) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return JSON.parse(raw);
|
|
62
|
+
};
|
|
63
|
+
exports.readLimitedJsonBody = readLimitedJsonBody;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isGatewayAuthorizationValid = isGatewayAuthorizationValid;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
function digest(value) {
|
|
6
|
+
return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest();
|
|
7
|
+
}
|
|
8
|
+
function isGatewayAuthorizationValid(authorization, authToken) {
|
|
9
|
+
if (typeof authorization !== "string" || !authToken) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return (0, node_crypto_1.timingSafeEqual)(digest(authorization), digest(`Bearer ${authToken}`));
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatLocalTimestamp = formatLocalTimestamp;
|
|
4
|
+
exports.formatLocalDateSegment = formatLocalDateSegment;
|
|
5
|
+
exports.formatLocalTimeSegment = formatLocalTimeSegment;
|
|
6
|
+
exports.formatLocalTimestampForFileName = formatLocalTimestampForFileName;
|
|
7
|
+
function padNumber(value, length = 2) {
|
|
8
|
+
return String(value).padStart(length, "0");
|
|
9
|
+
}
|
|
10
|
+
function formatLocalTimestamp(date = new Date()) {
|
|
11
|
+
return `${date.getFullYear()}-${padNumber(date.getMonth() + 1)}-${padNumber(date.getDate())}T${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}.${padNumber(date.getMilliseconds(), 3)}`;
|
|
12
|
+
}
|
|
13
|
+
function formatLocalDateSegment(date = new Date()) {
|
|
14
|
+
return `${date.getFullYear()}-${padNumber(date.getMonth() + 1)}-${padNumber(date.getDate())}`;
|
|
15
|
+
}
|
|
16
|
+
function formatLocalTimeSegment(date = new Date()) {
|
|
17
|
+
return `${padNumber(date.getHours())}-${padNumber(date.getMinutes())}-${padNumber(date.getSeconds())}`;
|
|
18
|
+
}
|
|
19
|
+
function formatLocalTimestampForFileName(date = new Date()) {
|
|
20
|
+
return formatLocalTimestamp(date).replace(/[:.]/gu, "-");
|
|
21
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# ChatGPT and Claude connector
|
|
2
|
+
|
|
3
|
+
TellyMCP can expose its Streamable HTTP MCP endpoint to ChatGPT and Claude
|
|
4
|
+
through an OAuth 2.0 authorization-code facade with PKCE. The facade coexists
|
|
5
|
+
with `MCP_HTTP_BEARER_TOKEN`; existing internal clients can continue to use the
|
|
6
|
+
static bearer token.
|
|
7
|
+
|
|
8
|
+
## Configure the gateway
|
|
9
|
+
|
|
10
|
+
Add the following to the gateway environment file:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
TELLYMCP_PUBLIC_URL=https://mcp.example.com/api
|
|
14
|
+
TELLYMCP_OAUTH_ISSUER=https://mcp.example.com/api
|
|
15
|
+
TELLYMCP_OAUTH_AUDIENCE=https://mcp.example.com/api
|
|
16
|
+
TELLYMCP_MAGIC_TOKEN=replace_with_a_private_human_login_token
|
|
17
|
+
TELLYMCP_OAUTH_PRIVATE_KEY_PEM="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Generate the stable signing key with:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
tellymcp oauth key
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The command prints a dotenv-ready `TELLYMCP_OAUTH_PRIVATE_KEY_PEM` assignment.
|
|
27
|
+
If the private key is omitted, TellyMCP generates an ephemeral key and existing
|
|
28
|
+
OAuth access tokens stop working after a restart.
|
|
29
|
+
|
|
30
|
+
For a hashed magic token, configure
|
|
31
|
+
`TELLYMCP_MAGIC_TOKEN_HASH=sha256:<64-hex-digest>` instead of the raw token.
|
|
32
|
+
Never configure both forms.
|
|
33
|
+
|
|
34
|
+
Optional restrictions:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
TELLYMCP_OAUTH_CLIENT_ID=tellymcp
|
|
38
|
+
TELLYMCP_OAUTH_CLIENT_SECRET=replace_with_client_secret
|
|
39
|
+
TELLYMCP_ALLOWED_REDIRECT_URIS=https://chatgpt.com/connector/oauth/...,https://claude.ai/api/mcp/auth_callback
|
|
40
|
+
TELLYMCP_AUTH_CODE_TTL_SECONDS=300
|
|
41
|
+
TELLYMCP_OAUTH_SCOPES=tellymcp:read tellymcp:write
|
|
42
|
+
TELLYMCP_OAUTH_KEY_ID=tellymcp-oauth
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
OAuth is enabled when a connector identity, credential, redirect, or signing-key
|
|
46
|
+
setting is present. `TELLYMCP_PUBLIC_URL` and one magic-token form are then
|
|
47
|
+
required. Redirect URIs are matched exactly when the allowlist is configured.
|
|
48
|
+
|
|
49
|
+
## Reverse proxy
|
|
50
|
+
|
|
51
|
+
Proxy all `/api/` routes to TellyMCP and disable response buffering on
|
|
52
|
+
`/api/mcp`. Claude also needs root path-insertion discovery routes such as:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
/.well-known/oauth-authorization-server/api
|
|
56
|
+
/.well-known/openid-configuration/api
|
|
57
|
+
/.well-known/oauth-protected-resource/api/mcp
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The complete Nginx example is in `docs/tellymcp.gw.conf`.
|
|
61
|
+
|
|
62
|
+
## Connect the chat host
|
|
63
|
+
|
|
64
|
+
Use the concrete MCP endpoint in the host's `Connection` field:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
https://mcp.example.com/api/mcp
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Do not enter `https://mcp.example.com/api` as the connection URL. That URL is
|
|
71
|
+
the OAuth issuer/audience base, not an MCP endpoint. With the correct
|
|
72
|
+
connection URL, discovery may legitimately show two related resources:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
OAuth issuer/audience: https://mcp.example.com/api
|
|
76
|
+
MCP resource: https://mcp.example.com/api/mcp
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For the production deployment used while implementing this feature, the
|
|
80
|
+
working ChatGPT values are:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Connection: https://drd.undoo.ru/api/mcp
|
|
84
|
+
Authorization server base: https://drd.undoo.ru/api
|
|
85
|
+
Resource: https://drd.undoo.ru/api/mcp
|
|
86
|
+
OIDC configuration URL: https://drd.undoo.ru/.well-known/openid-configuration/api
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The `/api` suffix in the root discovery URL is expected RFC 8414
|
|
90
|
+
path-insertion behavior for an issuer whose path is `/api`.
|
|
91
|
+
|
|
92
|
+
Do not give the host `MCP_HTTP_BEARER_TOKEN` or the magic token. The magic token
|
|
93
|
+
is entered only into the authorization page opened by the host. If a client ID
|
|
94
|
+
or client secret is configured in the host, it must match the gateway values.
|
|
95
|
+
|
|
96
|
+
TellyMCP tool names already use Claude-compatible letters, digits, and
|
|
97
|
+
underscores, and the tools publish output schemas.
|
|
98
|
+
|
|
99
|
+
## Verify before connecting
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
curl -fsS https://mcp.example.com/api/.well-known/oauth-protected-resource/mcp
|
|
103
|
+
curl -fsS https://mcp.example.com/api/.well-known/oauth-authorization-server
|
|
104
|
+
curl -fsS https://mcp.example.com/.well-known/oauth-authorization-server/api
|
|
105
|
+
curl -fsS https://mcp.example.com/api/.well-known/jwks.json
|
|
106
|
+
curl -i https://mcp.example.com/api/mcp
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The last response must be `401` and include a `WWW-Authenticate` header whose
|
|
110
|
+
`resource_metadata` value points to the protected-resource metadata endpoint.
|
|
111
|
+
|
|
112
|
+
Access tokens are RS256 JWTs without `exp`, matching the trusted internal
|
|
113
|
+
connector model. Authorization codes remain short-lived, PKCE-bound, and
|
|
114
|
+
one-time-use. Failed magic-token attempts are rate-limited per source address.
|
|
115
|
+
|
|
116
|
+
## Diagnostics
|
|
117
|
+
|
|
118
|
+
OAuth discovery, authorization, token exchange, MCP `initialize`, and
|
|
119
|
+
`tools/list` milestones are logged at `info`. Rejections are logged at `warn`
|
|
120
|
+
without credentials, authorization codes, PKCE verifiers, or access tokens.
|
|
121
|
+
When OAuth is enabled, every HTTP request and completed response is also logged
|
|
122
|
+
with its normalized path, status, user agent, content types, MCP session id,
|
|
123
|
+
and whether an Authorization header was present. Header values and tokens are
|
|
124
|
+
never logged.
|
|
125
|
+
|
|
126
|
+
The production Nginx sample writes connector traffic to:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
/var/log/nginx/tellymcp.access.log
|
|
130
|
+
/var/log/nginx/tellymcp.error.log
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If refresh stops after OAuth metadata and never logs an MCP `initialize`, first
|
|
134
|
+
verify that the host's `Connection` value ends in `/api/mcp`.
|
package/docs/STANDALONE-ru.md
CHANGED
|
@@ -31,6 +31,8 @@ npm install -g @deadragdoll/tellymcp
|
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
tellymcp browser install
|
|
34
|
+
tellymcp extension firefox
|
|
35
|
+
tellymcp extension chrome
|
|
34
36
|
tellymcp codex-plugin install
|
|
35
37
|
```
|
|
36
38
|
|
|
@@ -63,6 +65,7 @@ DB_NAME=
|
|
|
63
65
|
GATEWAY_PUBLIC_URL=https://your-domain.example/api/gateway
|
|
64
66
|
GATEWAY_WS_URL=wss://your-domain.example/api/gateway/ws
|
|
65
67
|
GATEWAY_TOKEN=change_me_gateway_token
|
|
68
|
+
GATEWAY_AUTH_TOKEN=put_strong_shared_transport_token_here
|
|
66
69
|
ROOT_PREFIX=/api
|
|
67
70
|
PORT=8080
|
|
68
71
|
DISTRIBUTED_MODE=gateway
|
|
@@ -81,9 +84,15 @@ DISTRIBUTED_MODE=client
|
|
|
81
84
|
GATEWAY_PUBLIC_URL=https://your-domain.example/api/gateway
|
|
82
85
|
GATEWAY_WS_URL=wss://your-domain.example/api/gateway/ws
|
|
83
86
|
GATEWAY_TOKEN=change_me_gateway_token
|
|
87
|
+
GATEWAY_AUTH_TOKEN=put_strong_shared_transport_token_here
|
|
84
88
|
GATEWAY_USER_UUID=put_owner_uuid_here
|
|
85
89
|
```
|
|
86
90
|
|
|
91
|
+
Используйте один и тот же стойкий `GATEWAY_AUTH_TOKEN` на gateway и всех клиентах.
|
|
92
|
+
Не смешивайте его с `GATEWAY_TOKEN`: последний разделяет данные gateway по scope,
|
|
93
|
+
но не аутентифицирует HTTP- или WebSocket-транспорт. Сгенерируйте токен один раз,
|
|
94
|
+
например командой `openssl rand -hex 32`, и не используйте пример значения выше.
|
|
95
|
+
|
|
87
96
|
Для первого запуска также желательно задать:
|
|
88
97
|
|
|
89
98
|
```env
|
|
@@ -91,7 +100,41 @@ TELLYMCP_SESSION_ID=NEW
|
|
|
91
100
|
TELLYMCP_SESSION_LABEL=NEW
|
|
92
101
|
```
|
|
93
102
|
|
|
94
|
-
## 5.
|
|
103
|
+
## 5. Attach extensions для браузера
|
|
104
|
+
|
|
105
|
+
Если нужно attach'иться к уже открытому Firefox или Chrome на агентской машине, включи локальный attach bridge в env этого агента:
|
|
106
|
+
|
|
107
|
+
```env
|
|
108
|
+
BROWSER_ATTACH_ENABLED=true
|
|
109
|
+
BROWSER_ATTACH_WS_HOST=127.0.0.1
|
|
110
|
+
BROWSER_ATTACH_WS_PORT=9999
|
|
111
|
+
BROWSER_ATTACH_WS_PATH=/browser-attach/ws
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Выгрузи unpacked extension bundle из установленного пакета:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
tellymcp extension firefox
|
|
118
|
+
tellymcp extension chrome
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Команда создаст один из каталогов:
|
|
122
|
+
|
|
123
|
+
- `./tellymcp-firefox-attach`
|
|
124
|
+
- `./tellymcp-chrome-attach`
|
|
125
|
+
|
|
126
|
+
Дальше загрузи его в локальный браузер:
|
|
127
|
+
|
|
128
|
+
- Firefox: `about:debugging#/runtime/this-firefox` -> `Load Temporary Add-on` -> выбрать `manifest.json`
|
|
129
|
+
- Chrome: `chrome://extensions` -> включить Developer mode -> `Load unpacked` -> выбрать выгруженный каталог
|
|
130
|
+
|
|
131
|
+
После этого browser control panel умеет:
|
|
132
|
+
|
|
133
|
+
- attach'ить текущую agent-сессию к живой вкладке
|
|
134
|
+
- запускать и останавливать structured recording bundles в `.mcp-xchange/web/...`
|
|
135
|
+
- инжектить helper scripts в attached tab
|
|
136
|
+
|
|
137
|
+
## 6. Запуск
|
|
95
138
|
|
|
96
139
|
Gateway:
|
|
97
140
|
|
|
@@ -111,7 +154,7 @@ tellymcp run --env .env -s NEW
|
|
|
111
154
|
tellymcp run
|
|
112
155
|
```
|
|
113
156
|
|
|
114
|
-
##
|
|
157
|
+
## 7. Webhook
|
|
115
158
|
|
|
116
159
|
Gateway поддерживает polling и webhook.
|
|
117
160
|
|
|
@@ -128,10 +171,16 @@ TELEGRAM_WEBHOOK_SECRET=change_me_webhook_secret
|
|
|
128
171
|
|
|
129
172
|
- `/api/telegram/webhook`
|
|
130
173
|
- `/api/gateway`
|
|
174
|
+
- `/api/files` для короткоживущих upload/download запросов `get_file(type="url")`
|
|
131
175
|
- `/api/webapp`
|
|
132
176
|
- `/api/healthz`
|
|
133
177
|
|
|
134
|
-
|
|
178
|
+
Отдельный `location ^~ /api/files/` рекомендуется, хотя для самой маршрутизации
|
|
179
|
+
он не обязателен. В нём следует отключить access log, потому что путь содержит
|
|
180
|
+
токен, задать `client_max_body_size 32m` и отключить buffering запросов и
|
|
181
|
+
ответов. Канонический блок приведён в `nginx/tellymcp.gw.conf`.
|
|
182
|
+
|
|
183
|
+
## 8. MCP
|
|
135
184
|
|
|
136
185
|
Локальный client-mode MCP endpoint:
|
|
137
186
|
|
|
@@ -141,7 +190,7 @@ http://127.0.0.1:8787/mcp
|
|
|
141
190
|
|
|
142
191
|
Используй MCP HTTP endpoint, который поднимает `tellymcp run`.
|
|
143
192
|
|
|
144
|
-
##
|
|
193
|
+
## 9. Проверки
|
|
145
194
|
|
|
146
195
|
```bash
|
|
147
196
|
tellymcp doctor --env .env
|
|
@@ -153,7 +202,7 @@ tellymcp doctor --env .env
|
|
|
153
202
|
tellymcp system-prune --env .env --yes
|
|
154
203
|
```
|
|
155
204
|
|
|
156
|
-
##
|
|
205
|
+
## 10. Операционные заметки
|
|
157
206
|
|
|
158
207
|
- gateway-бот — это основной user-facing control plane
|
|
159
208
|
- консоли видны из gateway live registry
|
|
@@ -162,7 +211,7 @@ tellymcp system-prune --env .env --yes
|
|
|
162
211
|
- browser screenshot для человека лучше отправлять через `browser_screenshot(send_to_telegram=true)`
|
|
163
212
|
- файлы между консолями лучше отправлять через `send_partner_file`
|
|
164
213
|
|
|
165
|
-
##
|
|
214
|
+
## 11. Чего не делать в новых setup
|
|
166
215
|
|
|
167
216
|
Не строй новые setup вокруг:
|
|
168
217
|
|
package/docs/STANDALONE.md
CHANGED
|
@@ -31,6 +31,8 @@ Optional:
|
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
tellymcp browser install
|
|
34
|
+
tellymcp extension firefox
|
|
35
|
+
tellymcp extension chrome
|
|
34
36
|
tellymcp codex-plugin install
|
|
35
37
|
```
|
|
36
38
|
|
|
@@ -63,6 +65,7 @@ DB_NAME=
|
|
|
63
65
|
GATEWAY_PUBLIC_URL=https://your-domain.example/api/gateway
|
|
64
66
|
GATEWAY_WS_URL=wss://your-domain.example/api/gateway/ws
|
|
65
67
|
GATEWAY_TOKEN=change_me_gateway_token
|
|
68
|
+
GATEWAY_AUTH_TOKEN=put_strong_shared_transport_token_here
|
|
66
69
|
ROOT_PREFIX=/api
|
|
67
70
|
PORT=8080
|
|
68
71
|
DISTRIBUTED_MODE=gateway
|
|
@@ -81,9 +84,15 @@ DISTRIBUTED_MODE=client
|
|
|
81
84
|
GATEWAY_PUBLIC_URL=https://your-domain.example/api/gateway
|
|
82
85
|
GATEWAY_WS_URL=wss://your-domain.example/api/gateway/ws
|
|
83
86
|
GATEWAY_TOKEN=change_me_gateway_token
|
|
87
|
+
GATEWAY_AUTH_TOKEN=put_strong_shared_transport_token_here
|
|
84
88
|
GATEWAY_USER_UUID=put_owner_uuid_here
|
|
85
89
|
```
|
|
86
90
|
|
|
91
|
+
Use the same strong `GATEWAY_AUTH_TOKEN` on the gateway and every client. Keep it
|
|
92
|
+
separate from `GATEWAY_TOKEN`, which scopes gateway data but does not authenticate
|
|
93
|
+
the HTTP or WebSocket transport. Generate it once, for example with
|
|
94
|
+
`openssl rand -hex 32`, and do not use the illustrative value above.
|
|
95
|
+
|
|
87
96
|
For the first run, also set:
|
|
88
97
|
|
|
89
98
|
```env
|
|
@@ -91,7 +100,41 @@ TELLYMCP_SESSION_ID=NEW
|
|
|
91
100
|
TELLYMCP_SESSION_LABEL=NEW
|
|
92
101
|
```
|
|
93
102
|
|
|
94
|
-
## 5.
|
|
103
|
+
## 5. Attached Browser Extensions
|
|
104
|
+
|
|
105
|
+
If you want to attach TellyMCP to an already running Firefox or Chrome tab on an agent machine, enable the local attach bridge in that agent env:
|
|
106
|
+
|
|
107
|
+
```env
|
|
108
|
+
BROWSER_ATTACH_ENABLED=true
|
|
109
|
+
BROWSER_ATTACH_WS_HOST=127.0.0.1
|
|
110
|
+
BROWSER_ATTACH_WS_PORT=9999
|
|
111
|
+
BROWSER_ATTACH_WS_PATH=/browser-attach/ws
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Export the unpacked extension bundle from the installed package:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
tellymcp extension firefox
|
|
118
|
+
tellymcp extension chrome
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This creates one of:
|
|
122
|
+
|
|
123
|
+
- `./tellymcp-firefox-attach`
|
|
124
|
+
- `./tellymcp-chrome-attach`
|
|
125
|
+
|
|
126
|
+
Load it into the local browser:
|
|
127
|
+
|
|
128
|
+
- Firefox: `about:debugging#/runtime/this-firefox` -> `Load Temporary Add-on` -> choose `manifest.json`
|
|
129
|
+
- Chrome: `chrome://extensions` -> enable Developer mode -> `Load unpacked` -> choose the exported directory
|
|
130
|
+
|
|
131
|
+
After that the browser control panel can:
|
|
132
|
+
|
|
133
|
+
- attach the current agent session to a live browser tab
|
|
134
|
+
- start and stop structured recording bundles in `.mcp-xchange/web/...`
|
|
135
|
+
- inject helper scripts into the attached tab
|
|
136
|
+
|
|
137
|
+
## 6. Run
|
|
95
138
|
|
|
96
139
|
Gateway:
|
|
97
140
|
|
|
@@ -111,7 +154,7 @@ After `.mcpsession.json` is created in the workspace, later runs can usually use
|
|
|
111
154
|
tellymcp run
|
|
112
155
|
```
|
|
113
156
|
|
|
114
|
-
##
|
|
157
|
+
## 7. Webhook
|
|
115
158
|
|
|
116
159
|
Gateway supports polling and webhook.
|
|
117
160
|
|
|
@@ -128,10 +171,16 @@ If nginx already proxies `location /api/ { ... }` to the standalone listener, th
|
|
|
128
171
|
|
|
129
172
|
- `/api/telegram/webhook`
|
|
130
173
|
- `/api/gateway`
|
|
174
|
+
- `/api/files` for short-lived `get_file(type="url")` uploads and downloads
|
|
131
175
|
- `/api/webapp`
|
|
132
176
|
- `/api/healthz`
|
|
133
177
|
|
|
134
|
-
|
|
178
|
+
A dedicated `location ^~ /api/files/` is recommended, though not required for
|
|
179
|
+
routing. It should disable access logs because the path contains a token, set
|
|
180
|
+
`client_max_body_size 32m`, and disable proxy request/response buffering. See
|
|
181
|
+
`nginx/tellymcp.gw.conf` for the canonical block.
|
|
182
|
+
|
|
183
|
+
## 8. MCP
|
|
135
184
|
|
|
136
185
|
Local client-mode MCP:
|
|
137
186
|
|
|
@@ -141,7 +190,7 @@ http://127.0.0.1:8787/mcp
|
|
|
141
190
|
|
|
142
191
|
Use the MCP HTTP endpoint exposed by `tellymcp run`.
|
|
143
192
|
|
|
144
|
-
##
|
|
193
|
+
## 9. Health Checks
|
|
145
194
|
|
|
146
195
|
```bash
|
|
147
196
|
tellymcp doctor --env .env
|
|
@@ -153,7 +202,7 @@ Destructive cleanup:
|
|
|
153
202
|
tellymcp system-prune --env .env --yes
|
|
154
203
|
```
|
|
155
204
|
|
|
156
|
-
##
|
|
205
|
+
## 10. Operational Notes
|
|
157
206
|
|
|
158
207
|
- the gateway bot is the user-facing control plane
|
|
159
208
|
- consoles are discovered from the gateway live registry
|
|
@@ -162,7 +211,7 @@ tellymcp system-prune --env .env --yes
|
|
|
162
211
|
- browser screenshot replies to humans should use `browser_screenshot(send_to_telegram=true)`
|
|
163
212
|
- file results between consoles should use `send_partner_file`
|
|
164
213
|
|
|
165
|
-
##
|
|
214
|
+
## 11. Legacy Concepts To Avoid
|
|
166
215
|
|
|
167
216
|
Do not build new setups around:
|
|
168
217
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deadragdoll/tellymcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "TellyMCP - Telegram control plane for MCP-connected coding agents",
|
|
5
5
|
"main": "dist/services/features/telegram-mcp/runtime.service.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
+
"packages/firefox-attach-extension/dist",
|
|
12
|
+
"packages/chrome-attach-extension/dist",
|
|
11
13
|
"scripts",
|
|
12
14
|
"config/templates",
|
|
13
15
|
"config/codex",
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
"README-ru.md",
|
|
16
18
|
"docs/STANDALONE.md",
|
|
17
19
|
"docs/STANDALONE-ru.md",
|
|
20
|
+
"docs/CHAT_CONNECTOR.md",
|
|
18
21
|
"VERSION.md",
|
|
19
22
|
"CHANGELOG.md",
|
|
20
23
|
"TOOLS.md",
|
|
@@ -36,8 +39,9 @@
|
|
|
36
39
|
},
|
|
37
40
|
"scripts": {
|
|
38
41
|
"postinstall": "node ./scripts/postinstall.js",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
42
|
+
"build:extensions": "node ./packages/firefox-attach-extension/scripts/build.mjs && node ./packages/chrome-attach-extension/scripts/build.mjs",
|
|
43
|
+
"prepack": "yarn build && yarn build:extensions",
|
|
44
|
+
"prepublishOnly": "yarn build && yarn build:extensions && yarn lint && yarn test",
|
|
41
45
|
"mcp:local": "codex mcp add telegramHuman --url http://127.0.0.1:8787/mcp",
|
|
42
46
|
"dev:gw": "TS_NODE_TRANSPILE_ONLY=1 TS_NODE_EXPERIMENTAL_RESOLVER=1 NODE_OPTIONS=--openssl-legacy-provider ts-node ./node_modules/moleculer/bin/moleculer-runner.js src/services --config src/moleculer.config.ts --envfile /opt/tellymcp-gateway/.env-gateway --hot --mask \"**/*.service.ts\"",
|
|
43
47
|
"dev:builder": "TS_NODE_TRANSPILE_ONLY=1 TS_NODE_EXPERIMENTAL_RESOLVER=1 NODE_OPTIONS=--openssl-legacy-provider ts-node ./node_modules/moleculer/bin/moleculer-runner.js src/services --config src/moleculer.config.ts --envfile ./.env-builder --hot --mask \"**/*.service.ts\"",
|
|
@@ -73,7 +77,8 @@
|
|
|
73
77
|
"dependencies": {
|
|
74
78
|
"@grammyjs/menu": "^1.3.1",
|
|
75
79
|
"@grammyjs/storage-redis": "^2.5.1",
|
|
76
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
80
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
81
|
+
"@xterm/addon-fit": "0.10.0",
|
|
77
82
|
"@xterm/headless": "5.5.0",
|
|
78
83
|
"@xterm/xterm": "5.5.0",
|
|
79
84
|
"amqplib": "0.10.9",
|
|
@@ -93,7 +98,7 @@
|
|
|
93
98
|
"pino-pretty": "^13.1.3",
|
|
94
99
|
"playwright": "^1.60.0",
|
|
95
100
|
"socks-proxy-agent": "^8.0.5",
|
|
96
|
-
"ws": "8.
|
|
101
|
+
"ws": "8.21.0",
|
|
97
102
|
"zod": "4.4.3"
|
|
98
103
|
},
|
|
99
104
|
"devDependencies": {
|