@deadragdoll/tellymcp 0.0.1
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 +93 -0
- package/.env.example.gateway +120 -0
- package/CHANGELOG.md +155 -0
- package/LICENSE +21 -0
- package/README-ru.md +338 -0
- package/README.md +1262 -0
- package/STANDALONE-ru.md +266 -0
- package/STANDALONE.md +266 -0
- package/TOOLS.md +1296 -0
- package/config/templates/env.both.template +83 -0
- package/config/templates/env.client.template +60 -0
- package/config/templates/env.gateway.template +82 -0
- package/dist/cli.js +636 -0
- package/dist/index.js +17 -0
- package/dist/lib/logfeed/store.js +52 -0
- package/dist/lib/middlewares/tracer.js +172 -0
- package/dist/lib/mixins/db.js +267 -0
- package/dist/lib/mixins/logfeed.js +34 -0
- package/dist/lib/mixins/session.errors.js +142 -0
- package/dist/lib/moleculer.js +2 -0
- package/dist/lib/trace.js +147 -0
- package/dist/lib/traceContext.js +116 -0
- package/dist/moleculer.config.js +274 -0
- package/dist/services/features/telegram-mcp/approval.service.js +33 -0
- package/dist/services/features/telegram-mcp/browser.service.js +42 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
- package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
- package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
- package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
- package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
- package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
- package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
- package/dist/services/features/telegram-mcp/notify.service.js +33 -0
- package/dist/services/features/telegram-mcp/pair.service.js +33 -0
- package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
- package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
- package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
- package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
- package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
- package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
- package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
- package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
- package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
- package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
- package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
- package/package.json +110 -0
- package/scripts/postinstall.js +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,1262 @@
|
|
|
1
|
+
# TellyMCP
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [Русский](README-ru.md)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@deadragdoll/tellymcp)
|
|
6
|
+
[](https://www.npmjs.com/package/@deadragdoll/tellymcp)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
TellyMCP is a Telegram Human-in-the-Loop MCP server for coding agents.
|
|
11
|
+
|
|
12
|
+
It lets an agent:
|
|
13
|
+
|
|
14
|
+
- ask a human for clarification through Telegram
|
|
15
|
+
- receive unsolicited Telegram messages later through an inbox
|
|
16
|
+
- pair multiple agent sessions
|
|
17
|
+
- collaborate across local and remote sessions
|
|
18
|
+
- open a live tmux view inside Telegram Mini App
|
|
19
|
+
- exchange notes, screenshots, and files through `.mcp-xchange`
|
|
20
|
+
|
|
21
|
+
Current tools:
|
|
22
|
+
|
|
23
|
+
- `create_session_pair_code`
|
|
24
|
+
- `clear_session_pairing`
|
|
25
|
+
- `set_session_context`
|
|
26
|
+
- `set_tmux_target`
|
|
27
|
+
- `get_tmux_target`
|
|
28
|
+
- `get_session_context`
|
|
29
|
+
- `clear_session_context`
|
|
30
|
+
- `rename_session`
|
|
31
|
+
- `notify_telegram`
|
|
32
|
+
- `get_telegram_inbox_count`
|
|
33
|
+
- `get_telegram_inbox`
|
|
34
|
+
- `delete_telegram_inbox_message`
|
|
35
|
+
- `ask_user_telegram`
|
|
36
|
+
- `browser_open`
|
|
37
|
+
- `browser_reload`
|
|
38
|
+
- `browser_click`
|
|
39
|
+
- `browser_fill`
|
|
40
|
+
- `browser_press`
|
|
41
|
+
- `browser_wait_for`
|
|
42
|
+
- `browser_wait_for_url`
|
|
43
|
+
- `browser_console`
|
|
44
|
+
- `browser_errors`
|
|
45
|
+
- `browser_network_failures`
|
|
46
|
+
- `browser_clear_logs`
|
|
47
|
+
- `browser_dom`
|
|
48
|
+
- `browser_computed_style`
|
|
49
|
+
- `browser_screenshot`
|
|
50
|
+
- `browser_close`
|
|
51
|
+
- `refresh_tools_markdown`
|
|
52
|
+
- `send_partner_note`
|
|
53
|
+
- `send_partner_file`
|
|
54
|
+
|
|
55
|
+
## Prerequisites
|
|
56
|
+
|
|
57
|
+
- Node.js 24+
|
|
58
|
+
- `tmux`
|
|
59
|
+
- Redis
|
|
60
|
+
- a Telegram bot token from BotFather
|
|
61
|
+
- for `gateway` / `both`: Postgres
|
|
62
|
+
- optional for durable fanout on gateway: RabbitMQ
|
|
63
|
+
|
|
64
|
+
## tmux is strongly recommended
|
|
65
|
+
|
|
66
|
+
TellyMCP works best when the agent itself runs inside `tmux`.
|
|
67
|
+
|
|
68
|
+
Without `tmux`, the service can still run, but you lose the full interactive path:
|
|
69
|
+
|
|
70
|
+
- no Live View
|
|
71
|
+
- no tmux nudges
|
|
72
|
+
- no direct tmux control from Telegram Mini App
|
|
73
|
+
|
|
74
|
+
Typical start:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
tmux new -s backend
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
or attach later:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
tmux attach -t backend
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Why the tmux session name matters:
|
|
87
|
+
|
|
88
|
+
- it helps you distinguish running agents
|
|
89
|
+
- it appears in tmux-related UI and diagnostics
|
|
90
|
+
- it makes Telegram session switching and Live targeting easier to understand
|
|
91
|
+
|
|
92
|
+
Use short, meaningful names such as:
|
|
93
|
+
|
|
94
|
+
- `backend`
|
|
95
|
+
- `frontend`
|
|
96
|
+
- `review`
|
|
97
|
+
- `ops`
|
|
98
|
+
|
|
99
|
+
If you run multiple agents, put each one in its own tmux session or pane and pair them separately.
|
|
100
|
+
|
|
101
|
+
## Quick start
|
|
102
|
+
|
|
103
|
+
### Standalone client node
|
|
104
|
+
|
|
105
|
+
This is the simplest setup. No shared gateway, no Postgres, no RabbitMQ.
|
|
106
|
+
|
|
107
|
+
1. Install:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm install -g @deadragdoll/tellymcp
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
2. Create a client config:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
tellymcp init client
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
3. Edit the generated `.env` and set at minimum:
|
|
120
|
+
|
|
121
|
+
- `TELEGRAM_BOT_TOKEN`
|
|
122
|
+
- `TELEGRAM_BOT_USERNAME`
|
|
123
|
+
- `REDIS_HOST`
|
|
124
|
+
- `MCP_HTTP_BEARER_TOKEN`
|
|
125
|
+
|
|
126
|
+
4. Validate the setup:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
tellymcp doctor --env .env
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
5. Run the node:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
tellymcp run --env .env
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
6. Add MCP to your agent:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
tellymcp mcp --help
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Typical local MCP endpoint in `client` mode:
|
|
145
|
+
|
|
146
|
+
- `http://127.0.0.1:8787/mcp`
|
|
147
|
+
|
|
148
|
+
Detailed step-by-step guide:
|
|
149
|
+
|
|
150
|
+
- [STANDALONE.md](STANDALONE.md)
|
|
151
|
+
- [STANDALONE-ru.md](STANDALONE-ru.md)
|
|
152
|
+
|
|
153
|
+
### Shared gateway or combined `both` node
|
|
154
|
+
|
|
155
|
+
Use this when you want:
|
|
156
|
+
|
|
157
|
+
- cross-machine collaboration
|
|
158
|
+
- cross-bot projects
|
|
159
|
+
- gateway-relayed Live View
|
|
160
|
+
- persistent gateway-side project and delivery state
|
|
161
|
+
|
|
162
|
+
1. Create a gateway or combined config:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
tellymcp init gateway
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
or
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
tellymcp init both
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
2. Edit `.env` and configure:
|
|
175
|
+
|
|
176
|
+
- `DISTRIBUTED_MODE=gateway|both`
|
|
177
|
+
- `PORT`
|
|
178
|
+
- `ROOT_PREFIX=/api`
|
|
179
|
+
- `TELEGRAM_BOT_TOKEN`
|
|
180
|
+
- `REDIS_*`
|
|
181
|
+
- `DB_*`
|
|
182
|
+
- `WEBAPP_PUBLIC_URL`
|
|
183
|
+
- `GATEWAY_PUBLIC_URL`
|
|
184
|
+
- `GATEWAY_WS_URL`
|
|
185
|
+
- optional `RMQ_*`
|
|
186
|
+
|
|
187
|
+
3. Put the node behind nginx or another reverse proxy on the same prefix:
|
|
188
|
+
|
|
189
|
+
- `/api/mcp`
|
|
190
|
+
- `/api/webapp`
|
|
191
|
+
- `/api/gateway`
|
|
192
|
+
- `/api/healthz`
|
|
193
|
+
|
|
194
|
+
4. Validate the setup:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
tellymcp doctor --env .env
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
5. Run it:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
tellymcp run --env .env
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Typical public MCP endpoint in `gateway` / `both` mode:
|
|
207
|
+
|
|
208
|
+
- `https://your-host.example/api/mcp`
|
|
209
|
+
|
|
210
|
+
## Start with the bot from inside an agent
|
|
211
|
+
|
|
212
|
+
Once MCP is connected, you can start Telegram pairing by asking the agent in plain language.
|
|
213
|
+
|
|
214
|
+
Typical phrases the agent should understand:
|
|
215
|
+
|
|
216
|
+
- `pair with Telegram`
|
|
217
|
+
- `link to Telegram`
|
|
218
|
+
- `connect this session to Telegram`
|
|
219
|
+
- `register this session in Telegram`
|
|
220
|
+
- `create a Telegram pairing code`
|
|
221
|
+
- `bind this agent to Telegram`
|
|
222
|
+
|
|
223
|
+
Expected pairing flow:
|
|
224
|
+
|
|
225
|
+
1. The agent calls `create_session_pair_code`.
|
|
226
|
+
2. It returns a short code and, when possible, a deep link.
|
|
227
|
+
3. You open Telegram and send `/start <code>` or `/link <code>` to the bot.
|
|
228
|
+
4. After successful pairing, `/menu` opens the session menu.
|
|
229
|
+
|
|
230
|
+
Recommended prompt if you want to be explicit:
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
Pair this session with Telegram and give me the link code.
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
If the agent works inside `tmux`, it should also pass tmux attributes and `cwd` during pairing so Live View and nudges work immediately.
|
|
237
|
+
|
|
238
|
+
### Telegram setup
|
|
239
|
+
|
|
240
|
+
1. Open BotFather in Telegram.
|
|
241
|
+
2. Create a bot with `/newbot`.
|
|
242
|
+
3. Save the bot token.
|
|
243
|
+
4. Set `TELEGRAM_BOT_USERNAME` if you want deep-link pairing hints.
|
|
244
|
+
|
|
245
|
+
## MCP configuration helper
|
|
246
|
+
|
|
247
|
+
TellyMCP does not modify your agent config automatically.
|
|
248
|
+
|
|
249
|
+
Use:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
tellymcp mcp --help
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
This prints ready-to-paste MCP JSON snippets for:
|
|
256
|
+
|
|
257
|
+
- local standalone client
|
|
258
|
+
- shared gateway endpoint
|
|
259
|
+
- optional bearer token usage
|
|
260
|
+
|
|
261
|
+
## Doctor
|
|
262
|
+
|
|
263
|
+
`doctor` is mode-aware.
|
|
264
|
+
|
|
265
|
+
`client` checks:
|
|
266
|
+
|
|
267
|
+
- `tmux`
|
|
268
|
+
- `.env`
|
|
269
|
+
- Redis
|
|
270
|
+
- local MCP bind
|
|
271
|
+
- external gateway `healthz` when `GATEWAY_PUBLIC_URL` is configured
|
|
272
|
+
- `GATEWAY_WS_URL`
|
|
273
|
+
- `WEBAPP_PUBLIC_URL`
|
|
274
|
+
|
|
275
|
+
`gateway` / `both` checks:
|
|
276
|
+
|
|
277
|
+
- `tmux`
|
|
278
|
+
- `.env`
|
|
279
|
+
- Redis
|
|
280
|
+
- local `healthz`
|
|
281
|
+
- public `healthz`
|
|
282
|
+
- public `ws`
|
|
283
|
+
- public `webapp`
|
|
284
|
+
- Postgres
|
|
285
|
+
- RabbitMQ when `RMQ_*` is configured
|
|
286
|
+
|
|
287
|
+
## Important configuration
|
|
288
|
+
|
|
289
|
+
Common:
|
|
290
|
+
|
|
291
|
+
- `TELEGRAM_BOT_TOKEN`
|
|
292
|
+
- `TELEGRAM_BOT_USERNAME`
|
|
293
|
+
- `REDIS_HOST`
|
|
294
|
+
- `REDIS_PORT`
|
|
295
|
+
- `REDIS_DB`
|
|
296
|
+
- `MODE=queue|reject`
|
|
297
|
+
- `PAIR_CODE_TTL_SECONDS`
|
|
298
|
+
- `MCP_HTTP_HOST`
|
|
299
|
+
- `MCP_HTTP_PORT`
|
|
300
|
+
- `MCP_HTTP_PATH`
|
|
301
|
+
- `MCP_HTTP_BEARER_TOKEN`
|
|
302
|
+
- `TMUX_SOCKET_PATH`
|
|
303
|
+
- `TMUX_NUDGE_ENABLED`
|
|
304
|
+
- `TMUX_NUDGE_DEBOUNCE_SECONDS`
|
|
305
|
+
- `TMUX_NUDGE_COOLDOWN_SECONDS`
|
|
306
|
+
- `WEBAPP_ENABLED`
|
|
307
|
+
- `WEBAPP_BASE_PATH`
|
|
308
|
+
- `WEBAPP_LAUNCH_MODE=default|expand|fullscreen`
|
|
309
|
+
- `MCP_XCHANGE_DIR`
|
|
310
|
+
- `PROXY_USE=http|socks5`
|
|
311
|
+
- `HTTP_PROXY`
|
|
312
|
+
- `SOCKS5_PROXY`
|
|
313
|
+
|
|
314
|
+
Client-only:
|
|
315
|
+
|
|
316
|
+
- `DISTRIBUTED_MODE=client`
|
|
317
|
+
- `GATEWAY_PUBLIC_URL` optional
|
|
318
|
+
- `GATEWAY_WS_URL` optional
|
|
319
|
+
- `GATEWAY_WS_PATH`
|
|
320
|
+
- `GATEWAY_AUTH_TOKEN` optional
|
|
321
|
+
|
|
322
|
+
Gateway / both:
|
|
323
|
+
|
|
324
|
+
- `DISTRIBUTED_MODE=gateway|both`
|
|
325
|
+
- `PORT`
|
|
326
|
+
- `ROOT_PREFIX=/api`
|
|
327
|
+
- `DB_HOST`
|
|
328
|
+
- `DB_PORT`
|
|
329
|
+
- `DB_USER`
|
|
330
|
+
- `DB_PASSWORD`
|
|
331
|
+
- `DB_NAME`
|
|
332
|
+
- optional `RMQ_HOST`
|
|
333
|
+
- optional `RMQ_PORT`
|
|
334
|
+
- optional `RMQ_USER`
|
|
335
|
+
- optional `RMQ_PASSWORD`
|
|
336
|
+
- optional `RMQ_VHOST`
|
|
337
|
+
- optional `RMQ_EXCHANGE`
|
|
338
|
+
|
|
339
|
+
For ready-to-edit templates, use:
|
|
340
|
+
|
|
341
|
+
- `.env.example.client`
|
|
342
|
+
- `.env.example.gateway`
|
|
343
|
+
- `tellymcp init client|gateway|both`
|
|
344
|
+
|
|
345
|
+
## What it does
|
|
346
|
+
|
|
347
|
+
Flow:
|
|
348
|
+
|
|
349
|
+
1. The MCP client creates or updates a session context.
|
|
350
|
+
2. The MCP client creates a short one-time 3-digit session pairing code.
|
|
351
|
+
It should also pass the agent `cwd` when available.
|
|
352
|
+
3. The human user links that session in Telegram with `/start <code>` or `/link <code>`.
|
|
353
|
+
4. After pairing, Telegram shows an inline menu for session switching, inbox, content export, live tmux view, and maintenance actions. `/menu` opens the root switcher.
|
|
354
|
+
5. The MCP client calls `ask_user_telegram` with the linked `session_id`.
|
|
355
|
+
6. The server sends a redacted Telegram message and waits for the answer.
|
|
356
|
+
7. The answer is returned as structured MCP tool output.
|
|
357
|
+
8. Unsolicited Telegram messages are stored in a per-session inbox for later agent processing.
|
|
358
|
+
9. If the Telegram message contains a photo or document, the file is written into the session `.mcp-xchange/` and delivered according to the currently open session or collaboration target.
|
|
359
|
+
|
|
360
|
+
## Architecture
|
|
361
|
+
|
|
362
|
+
- TypeScript, strict mode
|
|
363
|
+
- official MCP SDK over Streamable HTTP
|
|
364
|
+
- `grammy` for Telegram transport
|
|
365
|
+
- pluggable `HumanTransport` interface
|
|
366
|
+
- `ioredis` for Redis access
|
|
367
|
+
- `@grammyjs/storage-redis` for Redis-backed session storage
|
|
368
|
+
- FSD-inspired backend structure
|
|
369
|
+
|
|
370
|
+
Telegram is implemented as the first transport backend. Tool orchestration does not depend on Telegram-specific APIs directly.
|
|
371
|
+
|
|
372
|
+
For maintainers and future extension work, see [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md).
|
|
373
|
+
|
|
374
|
+
Canonical instructions:
|
|
375
|
+
|
|
376
|
+
- gateway `TOOLS.md` is the canonical instruction source
|
|
377
|
+
- `TOOLS.md` now carries a human-readable version marker near the top of the file
|
|
378
|
+
- gateway/client sync still relies on content hash, not on the version string
|
|
379
|
+
- gateway/client runtime compatibility is checked separately in `ws hello/hello_ack`
|
|
380
|
+
- protocol major mismatch blocks gateway transport until the older side is upgraded
|
|
381
|
+
- when behavior changes materially, bump both:
|
|
382
|
+
- the `TOOLS.md` version marker
|
|
383
|
+
- the file content itself
|
|
384
|
+
|
|
385
|
+
Logs are written in two places at the same time:
|
|
386
|
+
|
|
387
|
+
- pretty console output to `stderr`
|
|
388
|
+
- JSONL file at `.telegram-human-mcp/log.jsonl`
|
|
389
|
+
|
|
390
|
+
If Telegram access requires a proxy, the bot transport can use:
|
|
391
|
+
|
|
392
|
+
- HTTP proxy through `HTTP_PROXY`
|
|
393
|
+
- SOCKS5 proxy through `SOCKS5_PROXY`
|
|
394
|
+
|
|
395
|
+
The chosen proxy mode is controlled by `PROXY_USE`.
|
|
396
|
+
|
|
397
|
+
Debug/admin HTTP routes are disabled by default:
|
|
398
|
+
|
|
399
|
+
- `/sessions` requires `MCP_HTTP_ENABLE_DEBUG_ROUTES=true`
|
|
400
|
+
- `/prune` requires `MCP_HTTP_ENABLE_PRUNE_ROUTE=true`
|
|
401
|
+
|
|
402
|
+
If exposed outside localhost, also set `MCP_HTTP_BEARER_TOKEN`.
|
|
403
|
+
|
|
404
|
+
## Distributed modes
|
|
405
|
+
|
|
406
|
+
The service now has a role-oriented distributed scaffold:
|
|
407
|
+
|
|
408
|
+
- `DISTRIBUTED_MODE=client`
|
|
409
|
+
- current default
|
|
410
|
+
- full local Telegram/MCP/tmux/browser flow
|
|
411
|
+
- local `🏠 Local` flow works directly
|
|
412
|
+
- remote `👥 Collab` flow goes through gateway when `GATEWAY_PUBLIC_URL` is configured
|
|
413
|
+
- `DISTRIBUTED_MODE=gateway`
|
|
414
|
+
- enables `/gateway/*` HTTP surface
|
|
415
|
+
- serves as the shared relay/control plane
|
|
416
|
+
- `DISTRIBUTED_MODE=both`
|
|
417
|
+
- exposes both local service behavior and gateway HTTP surface in one process
|
|
418
|
+
|
|
419
|
+
Current implementation status:
|
|
420
|
+
|
|
421
|
+
- `GET /gateway/healthz` works
|
|
422
|
+
- `POST /gateway/client/register` works
|
|
423
|
+
- `POST /gateway/projects/create` works
|
|
424
|
+
- `POST /gateway/projects/join` works
|
|
425
|
+
- `POST /gateway/sessions/register` works
|
|
426
|
+
- `POST /gateway/partner-note` works
|
|
427
|
+
- `ws` control-plane is active
|
|
428
|
+
- optional `RabbitMQ` exchange can be enabled for durable gateway-side event fanout
|
|
429
|
+
- if `GATEWAY_PUBLIC_URL` is configured, partner-note delivery goes through the gateway HTTP surface
|
|
430
|
+
- in `DISTRIBUTED_MODE=both`, this also covers same-bot local delivery transparently
|
|
431
|
+
- remote project messaging and delivery status go through the gateway DB and `ws`
|
|
432
|
+
- gateway-relayed `Live View` goes through `ws` for client nodes without their own public domain
|
|
433
|
+
- `Collab -> Tools -> History` sends a markdown export of the last 5 Collab events
|
|
434
|
+
for the current active session
|
|
435
|
+
- `TOOLS.md` sync is state-based:
|
|
436
|
+
- client sends per-session `tools_hash` in `ws hello`
|
|
437
|
+
- gateway compares against canonical gateway `TOOLS.md`
|
|
438
|
+
- mismatch triggers `tools_event`
|
|
439
|
+
- client also self-checks on `hello_ack`
|
|
440
|
+
- gateway periodically rechecks online sockets for changed gateway `TOOLS.md`
|
|
441
|
+
|
|
442
|
+
Mode-specific runtime requirements:
|
|
443
|
+
|
|
444
|
+
- `client`
|
|
445
|
+
- local Redis
|
|
446
|
+
- `GATEWAY_PUBLIC_URL`
|
|
447
|
+
- no gateway Postgres bootstrap is performed
|
|
448
|
+
- `gateway`
|
|
449
|
+
- Postgres is required for gateway persistence
|
|
450
|
+
- optional `RMQ_*` enables durable gateway-side event dispatch
|
|
451
|
+
- `both`
|
|
452
|
+
- Postgres is required because the gateway role is active
|
|
453
|
+
- optional `RMQ_*` enables durable gateway-side event dispatch
|
|
454
|
+
|
|
455
|
+
Current file model:
|
|
456
|
+
|
|
457
|
+
- exchange files and screenshots live directly in local `.mcp-xchange`
|
|
458
|
+
- remote delivery sends payloads through gateway delivery events
|
|
459
|
+
- `vfs/minio` are no longer part of the active Telegram file exchange path
|
|
460
|
+
- if an agent must send a real local file to a partner, prefer `send_partner_file`
|
|
461
|
+
over plain `send_partner_note`
|
|
462
|
+
|
|
463
|
+
Current presence model:
|
|
464
|
+
|
|
465
|
+
- gateway knows whether a client node is online through active `ws`
|
|
466
|
+
- gateway also updates `gateway_clients.last_seen_at`
|
|
467
|
+
- there is no separate heartbeat of the coding agent process inside each session yet
|
|
468
|
+
- because of that, a status screen can honestly show client `online/offline`, but not guaranteed agent `online/offline`
|
|
469
|
+
|
|
470
|
+
## Mini App
|
|
471
|
+
|
|
472
|
+
If `WEBAPP_ENABLED=true`, the session menu exposes `🖥 Live`.
|
|
473
|
+
|
|
474
|
+
The Mini App:
|
|
475
|
+
|
|
476
|
+
- is served by this same Node service under `WEBAPP_BASE_PATH`
|
|
477
|
+
- in `client` mode can also be opened through the shared gateway domain
|
|
478
|
+
- uses vanilla JS and reads the visible tmux pane area through gateway/client relay
|
|
479
|
+
- validates Telegram `initData` server-side using the official hash check
|
|
480
|
+
- can auto-apply launch mode from env:
|
|
481
|
+
- `default`
|
|
482
|
+
- `expand`
|
|
483
|
+
- `fullscreen` with fallback to `expand` when the Telegram client does not support fullscreen
|
|
484
|
+
- requires the Telegram user from `initData` to match the bound session user
|
|
485
|
+
- resolves the active session from the bound Telegram user, so a session id in the URL is not required for normal use
|
|
486
|
+
- deletes the temporary `Open Live View` launcher message after successful Mini App bootstrap
|
|
487
|
+
- allows only a fixed control set:
|
|
488
|
+
- `Esc`
|
|
489
|
+
- `Tab`
|
|
490
|
+
- `/`
|
|
491
|
+
- `Backspace`
|
|
492
|
+
- `Up`
|
|
493
|
+
- `Down`
|
|
494
|
+
- `Enter`
|
|
495
|
+
|
|
496
|
+
`WEBAPP_VISIBLE_SCREENS` controls how much content the live viewport captures relative to the visible tmux height. The default `2` means about two visible screens of content.
|
|
497
|
+
|
|
498
|
+
`WEBAPP_PUBLIC_URL` is only required when the node exposes its own public Mini App URL directly. In `DISTRIBUTED_MODE=client` with `GATEWAY_PUBLIC_URL` configured, `🖥 Live` can be opened through the gateway domain instead.
|
|
499
|
+
|
|
500
|
+
## Browser feedback
|
|
501
|
+
|
|
502
|
+
The service can also launch an internal Playwright runtime and keep one isolated browser context per `session_id`.
|
|
503
|
+
|
|
504
|
+
Current browser model:
|
|
505
|
+
|
|
506
|
+
- one shared browser process
|
|
507
|
+
- one isolated `BrowserContext + Page` per MCP session
|
|
508
|
+
- events are captured per session:
|
|
509
|
+
- console messages
|
|
510
|
+
- page runtime errors
|
|
511
|
+
- failed or HTTP-error network requests
|
|
512
|
+
- screenshots are written into the same `.mcp-xchange` flow as Telegram file exchange
|
|
513
|
+
- exchange files use the same local `.mcp-xchange` handoff model as Telegram uploads
|
|
514
|
+
|
|
515
|
+
Recommended local dev settings:
|
|
516
|
+
|
|
517
|
+
- `BROWSER_ENABLED=true`
|
|
518
|
+
- `BROWSER_HEADLESS=false`
|
|
519
|
+
- `BROWSER_ADDRESS=http://localhost:5173`
|
|
520
|
+
- start your SPA dev server on `0.0.0.0:5173`
|
|
521
|
+
- open it through `browser_open`
|
|
522
|
+
|
|
523
|
+
Recommended Docker settings:
|
|
524
|
+
|
|
525
|
+
- `BROWSER_HEADLESS=true`
|
|
526
|
+
- target the host dev server through `http://host.docker.internal:3000`
|
|
527
|
+
|
|
528
|
+
Current browser tools:
|
|
529
|
+
|
|
530
|
+
- `browser_open`
|
|
531
|
+
- `browser_reload`
|
|
532
|
+
- `browser_click`
|
|
533
|
+
- `browser_fill`
|
|
534
|
+
- `browser_press`
|
|
535
|
+
- `browser_wait_for`
|
|
536
|
+
- `browser_wait_for_url`
|
|
537
|
+
- `browser_console`
|
|
538
|
+
- `browser_errors`
|
|
539
|
+
- `browser_network_failures`
|
|
540
|
+
- `browser_clear_logs`
|
|
541
|
+
- `browser_dom`
|
|
542
|
+
- `browser_computed_style`
|
|
543
|
+
- `browser_screenshot`
|
|
544
|
+
- `browser_close`
|
|
545
|
+
|
|
546
|
+
Browser target convention:
|
|
547
|
+
|
|
548
|
+
- browser interaction tools support `ai_tag` in addition to `selector` and `text`
|
|
549
|
+
- frontend code may annotate elements with:
|
|
550
|
+
- `data-drive-tag="save-button"`
|
|
551
|
+
- or `ai-tag="save-button"`
|
|
552
|
+
- recommended convention is `data-drive-tag="..."` with an explicit value
|
|
553
|
+
|
|
554
|
+
If `BROWSER_ADDRESS` is configured, `browser_open` may use either:
|
|
555
|
+
|
|
556
|
+
- a full URL like `http://localhost:5173/settings`
|
|
557
|
+
- or a relative path like `/settings`
|
|
558
|
+
|
|
559
|
+
`browser_screenshot` returns:
|
|
560
|
+
|
|
561
|
+
- `file_path` full path to the written screenshot file
|
|
562
|
+
- `workspace_dir` the resolved workspace root for that session
|
|
563
|
+
- `exchange_dir` the resolved `.mcp-xchange` directory used for the write
|
|
564
|
+
- `telegram_message_id` when `send_to_telegram=true`
|
|
565
|
+
|
|
566
|
+
## Telegram UI
|
|
567
|
+
|
|
568
|
+
The Telegram bot exposes one root entrypoint:
|
|
569
|
+
|
|
570
|
+
- `/menu`
|
|
571
|
+
|
|
572
|
+
Current root menu behavior:
|
|
573
|
+
|
|
574
|
+
- shows the current active session
|
|
575
|
+
- shows the last worked session and update time
|
|
576
|
+
- shows tmux status
|
|
577
|
+
- lists paired sessions as one button per row
|
|
578
|
+
- keeps `Refresh` and `Tools` on the final row
|
|
579
|
+
|
|
580
|
+
Current session menu behavior:
|
|
581
|
+
|
|
582
|
+
- title is `Session: <name>`
|
|
583
|
+
- first row: `Live | Content | Browser`
|
|
584
|
+
- second row: `Local | Collab`
|
|
585
|
+
- third row: `Inbox | Storage | Settings`
|
|
586
|
+
- final row: `Back`
|
|
587
|
+
|
|
588
|
+
`Settings` contains:
|
|
589
|
+
|
|
590
|
+
- `Info`
|
|
591
|
+
- `Rename`
|
|
592
|
+
- `Unpair`
|
|
593
|
+
- `Back`
|
|
594
|
+
|
|
595
|
+
Current browser menu behavior:
|
|
596
|
+
|
|
597
|
+
- `Screenshots`
|
|
598
|
+
- browser screenshots are separated from ordinary uploaded files
|
|
599
|
+
|
|
600
|
+
Current storage behavior:
|
|
601
|
+
|
|
602
|
+
- `Storage` shows `.mcp-xchange` contents for the active session
|
|
603
|
+
- storage entries can be opened and sent back to Telegram as files
|
|
604
|
+
|
|
605
|
+
Current file behavior:
|
|
606
|
+
|
|
607
|
+
- top-level `Files` menu is removed
|
|
608
|
+
- `Browser -> Screenshots` still shows screenshots created by `browser_screenshot`
|
|
609
|
+
- if the user is inside:
|
|
610
|
+
- the current session
|
|
611
|
+
- `🏠 Local -> Напарник`
|
|
612
|
+
- `👥 Collab -> Project -> Member`
|
|
613
|
+
then the next uploaded file is delivered directly into that target
|
|
614
|
+
|
|
615
|
+
Local link behavior:
|
|
616
|
+
|
|
617
|
+
- `Link` opens a list of other sessions visible to the same Telegram identity
|
|
618
|
+
- choosing one creates a mutual partner link between the two sessions
|
|
619
|
+
- once linked, the button becomes `Unlink`
|
|
620
|
+
- this link is intended for backend/frontend or similar agent collaboration
|
|
621
|
+
- linked agents should use `send_partner_note` for structured collaboration
|
|
622
|
+
|
|
623
|
+
Local partner menu behavior:
|
|
624
|
+
|
|
625
|
+
- `Local` opens a linked-session collaboration menu
|
|
626
|
+
- available actions are:
|
|
627
|
+
- `Ask`
|
|
628
|
+
- `Share`
|
|
629
|
+
- `Unlink`
|
|
630
|
+
- the Telegram prompt format is:
|
|
631
|
+
- first line = short summary
|
|
632
|
+
- optional blank line
|
|
633
|
+
- remaining text = full message body
|
|
634
|
+
- partner wake-up semantics:
|
|
635
|
+
- `TMUX_PARTNER_NUDGE_MESSAGE` is for collaboration notes, not for human Telegram inbox
|
|
636
|
+
- the receiving agent should read `.mcp-xchange/SHARED_INDEX.md` and the newest note first
|
|
637
|
+
|
|
638
|
+
Linked-session collaboration contract:
|
|
639
|
+
|
|
640
|
+
- `send_partner_note` writes one note per event into the partner workspace
|
|
641
|
+
- collaborative notes live under `.mcp-xchange/shares/`
|
|
642
|
+
- copied artifacts live under `.mcp-xchange/shares/files/<share_id>/`
|
|
643
|
+
- `.mcp-xchange/SHARED_INDEX.md` acts as the append-only index of partner-facing notes
|
|
644
|
+
- `.mcp-xchange/LOCAL_INDEX.md` acts as the append-only index of local agent-facing handoffs
|
|
645
|
+
- supported note kinds are:
|
|
646
|
+
- `share`
|
|
647
|
+
- `question`
|
|
648
|
+
- `reply`
|
|
649
|
+
- `request`
|
|
650
|
+
- `handoff`
|
|
651
|
+
- useful partner-facing content usually includes:
|
|
652
|
+
- API summaries
|
|
653
|
+
- what changed
|
|
654
|
+
- current errors
|
|
655
|
+
- sample payloads
|
|
656
|
+
- relevant git changes from the agent workspace
|
|
657
|
+
- do not send raw implementation source files as partner artifacts; prefer summaries, specs, payload examples, logs, screenshots, and Markdown notes
|
|
658
|
+
- recommended mapping:
|
|
659
|
+
- `question` for "what APIs do you expose?", "what's new?", "send the error details"
|
|
660
|
+
- `reply` for direct answers, usually with `in_reply_to`
|
|
661
|
+
- `share` for one-way status updates
|
|
662
|
+
- `request` for explicit teammate actions
|
|
663
|
+
- `handoff` for transferring results or artifacts
|
|
664
|
+
- before sending a local partner note, the agent should call `get_session_context` and verify that `linked_session_id` exists
|
|
665
|
+
|
|
666
|
+
Collab project behavior:
|
|
667
|
+
|
|
668
|
+
- `👥 Collab` is the project-based multi-machine and multi-bot collaboration flow
|
|
669
|
+
- target session is chosen from `Projects -> <project> -> <member>`
|
|
670
|
+
- member screen layout is:
|
|
671
|
+
- first row: `Ask | Share`
|
|
672
|
+
- second row: `Live`
|
|
673
|
+
- semantics inside `Project -> Member` depend on the action:
|
|
674
|
+
- `Ask` sends a task to the selected member session
|
|
675
|
+
- expected reply route is `member -> current session`
|
|
676
|
+
- `Share` creates a task for the current session
|
|
677
|
+
- expected send route is `current session -> member`
|
|
678
|
+
- `Live` now uses an approval flow before opening the selected member session
|
|
679
|
+
- after approval, the requester receives a fresh `Open Live View` button through the existing webapp relay path
|
|
680
|
+
- direct file uploads still go to that exact target session when a member screen is open
|
|
681
|
+
- if an old member-menu message becomes stale, clicking it deletes that outdated Telegram message instead of leaving a dead keyboard
|
|
682
|
+
|
|
683
|
+
Recommended share-note structure:
|
|
684
|
+
|
|
685
|
+
```md
|
|
686
|
+
---
|
|
687
|
+
share_id: 2026-05-12T22-10-00Z-frontend-question-api
|
|
688
|
+
kind: question
|
|
689
|
+
from_session_id: frontend-session
|
|
690
|
+
to_session_id: backend-session
|
|
691
|
+
created_at: 2026-05-12T22:10:00Z
|
|
692
|
+
requires_reply: true
|
|
693
|
+
in_reply_to: null
|
|
694
|
+
artifacts: []
|
|
695
|
+
---
|
|
696
|
+
|
|
697
|
+
# Summary
|
|
698
|
+
Need an up-to-date backend API summary.
|
|
699
|
+
|
|
700
|
+
# Message
|
|
701
|
+
- what endpoints exist
|
|
702
|
+
- what auth is required
|
|
703
|
+
- what changed recently
|
|
704
|
+
|
|
705
|
+
# Expected Reply
|
|
706
|
+
Short Markdown summary plus spec or sample payload files when available.
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Current content menu behavior:
|
|
710
|
+
|
|
711
|
+
- `Visible`
|
|
712
|
+
- `Full`
|
|
713
|
+
- `Last 300`
|
|
714
|
+
- `Last 1000`
|
|
715
|
+
|
|
716
|
+
`Tools` currently contains:
|
|
717
|
+
|
|
718
|
+
- `Broadcast`
|
|
719
|
+
- `Prune all`
|
|
720
|
+
|
|
721
|
+
`Broadcast` uses a one-shot prompt. After a successful broadcast, only that prompt is deleted. Cancel returns to `Tools` without destroying the existing menu message.
|
|
722
|
+
|
|
723
|
+
## Telegram file exchange
|
|
724
|
+
|
|
725
|
+
Ordinary Telegram messages may include:
|
|
726
|
+
|
|
727
|
+
- text only
|
|
728
|
+
- photo with optional caption
|
|
729
|
+
- document with optional caption
|
|
730
|
+
|
|
731
|
+
When a photo or document arrives:
|
|
732
|
+
|
|
733
|
+
- the file is downloaded into `MCP_XCHANGE_DIR`, default `.mcp-xchange`, under the paired agent workspace
|
|
734
|
+
- if the user is already inside a concrete target context, the upload itself is the handoff action
|
|
735
|
+
- otherwise the file is delivered into the currently open session as a local session handoff
|
|
736
|
+
- there is no separate `Files` confirmation screen anymore
|
|
737
|
+
|
|
738
|
+
Runtime note:
|
|
739
|
+
|
|
740
|
+
- the main service writes these files directly in the local workspace
|
|
741
|
+
|
|
742
|
+
## Default session identity
|
|
743
|
+
|
|
744
|
+
If a tool call omits `session_id`, the server derives a stable default session automatically.
|
|
745
|
+
|
|
746
|
+
Resolution order for the human-readable project/session title:
|
|
747
|
+
|
|
748
|
+
1. `PROJECT_NAME` from `.env`
|
|
749
|
+
2. `package.json` `name`
|
|
750
|
+
3. git root directory name
|
|
751
|
+
4. current working directory name
|
|
752
|
+
|
|
753
|
+
The derived `session_id` is built from that title plus a short stable hash of the project path, so it remains consistent across restarts.
|
|
754
|
+
|
|
755
|
+
This means you can call session-oriented tools without explicitly passing `session_id` when working in a single project context.
|
|
756
|
+
|
|
757
|
+
## Repository development
|
|
758
|
+
|
|
759
|
+
```bash
|
|
760
|
+
yarn install
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
### Build
|
|
764
|
+
|
|
765
|
+
```bash
|
|
766
|
+
yarn build
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Run
|
|
770
|
+
|
|
771
|
+
Development:
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
yarn dev:gw
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
Production build:
|
|
778
|
+
|
|
779
|
+
```bash
|
|
780
|
+
yarn build
|
|
781
|
+
yarn start:gw
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
After startup you should see readiness logs in the console.
|
|
785
|
+
|
|
786
|
+
In repository dev mode, the HTTP service exposes:
|
|
787
|
+
|
|
788
|
+
- MCP endpoint at `http://127.0.0.1:8787/mcp` by default
|
|
789
|
+
- health check at `http://127.0.0.1:8787/healthz`
|
|
790
|
+
|
|
791
|
+
If `MCP_HTTP_BEARER_TOKEN` is configured:
|
|
792
|
+
|
|
793
|
+
- `/mcp` requires `Authorization: Bearer ...`
|
|
794
|
+
- `/sessions` and `/prune` also require the same bearer when enabled
|
|
795
|
+
- Telegram Mini App does not use this bearer directly; it has its own `initData` bootstrap and a short-lived WebApp session token
|
|
796
|
+
|
|
797
|
+
`yarn dev:gw:telegram` is still available, but it only starts the `telegram_mcp` feature node.
|
|
798
|
+
It does not expose HTTP by itself anymore. `/mcp`, `/webapp`, and `/healthz` are now served only through the Moleculer API gateway aliases in the full `dev:gw` / `start:gw` runtime, or through a separate gateway node in the same namespace.
|
|
799
|
+
|
|
800
|
+
## Optional Docker deployment
|
|
801
|
+
|
|
802
|
+
Docker is no longer required for the default product install flow.
|
|
803
|
+
|
|
804
|
+
This repository still includes a single-container deployment path without an internal nginx layer for ops/self-hosted scenarios.
|
|
805
|
+
|
|
806
|
+
Inside the container:
|
|
807
|
+
|
|
808
|
+
- `node` runs the MCP HTTP service on `0.0.0.0:8787`
|
|
809
|
+
- `redis-server` runs on `127.0.0.1:6379`
|
|
810
|
+
- the application itself serves:
|
|
811
|
+
- `/mcp`
|
|
812
|
+
- `/webapp`
|
|
813
|
+
- `/healthz`
|
|
814
|
+
- `/sessions`
|
|
815
|
+
- `/prune`
|
|
816
|
+
|
|
817
|
+
This means an external reverse proxy can forward directly to container port `8787`, while all app routing stays inside the Node service.
|
|
818
|
+
|
|
819
|
+
Build the image fully inside Docker:
|
|
820
|
+
|
|
821
|
+
```bash
|
|
822
|
+
docker compose build
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
Run it:
|
|
826
|
+
|
|
827
|
+
```bash
|
|
828
|
+
docker compose up -d
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
Stop it:
|
|
832
|
+
|
|
833
|
+
```bash
|
|
834
|
+
docker compose down
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
The compose file:
|
|
838
|
+
|
|
839
|
+
- builds the image from this repository
|
|
840
|
+
- injects `.env`
|
|
841
|
+
- overrides runtime networking so the app talks to local in-container Redis and listens on `0.0.0.0:8787`
|
|
842
|
+
- publishes only `8787:8787`
|
|
843
|
+
- keeps `host.docker.internal` available for optional host-side development integrations
|
|
844
|
+
- persists Redis state in `./data/redis`
|
|
845
|
+
|
|
846
|
+
After startup:
|
|
847
|
+
|
|
848
|
+
- MCP is reachable at `http://<host>:8787/mcp`
|
|
849
|
+
- Mini App static/API routes are reachable under `http://<host>:8787/webapp/`
|
|
850
|
+
- health check is at `http://<host>:8787/healthz`
|
|
851
|
+
|
|
852
|
+
Recommended external reverse proxy pattern:
|
|
853
|
+
|
|
854
|
+
- external proxy forwards `/mcp` to `http://<container-host>:8787/mcp`
|
|
855
|
+
- external proxy forwards `/webapp/` to `http://<container-host>:8787/webapp/`
|
|
856
|
+
- or, if you prefer, the external proxy can forward a wider prefix directly to `http://<container-host>:8787`
|
|
857
|
+
- no direct external access is needed to in-container Redis
|
|
858
|
+
- `tmux` access is expected to be direct from the running `tellymcp` process
|
|
859
|
+
|
|
860
|
+
Important:
|
|
861
|
+
|
|
862
|
+
- pairing state
|
|
863
|
+
- active session bindings
|
|
864
|
+
- inbox messages
|
|
865
|
+
- menu payload buffers
|
|
866
|
+
- WebApp launch/session state
|
|
867
|
+
|
|
868
|
+
are all stored in Redis. In the Docker deployment they survive restarts because `./data/redis` is mounted into the container and Redis AOF is enabled.
|
|
869
|
+
|
|
870
|
+
Optional if the local tmux server uses a non-default socket:
|
|
871
|
+
|
|
872
|
+
```bash
|
|
873
|
+
TMUX_SOCKET_PATH=/tmp/tmux-1000/default tellymcp run
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
## MCP usage
|
|
877
|
+
|
|
878
|
+
### 1. Save session context
|
|
879
|
+
|
|
880
|
+
Call `set_session_context`:
|
|
881
|
+
|
|
882
|
+
```json
|
|
883
|
+
{
|
|
884
|
+
"session_id": "backend-refactor",
|
|
885
|
+
"session_label": "Backend refactor",
|
|
886
|
+
"task": "Admin API cleanup",
|
|
887
|
+
"summary": "We are simplifying admin API response shapes and need product confirmations on compatibility-sensitive changes.",
|
|
888
|
+
"files": [
|
|
889
|
+
"backend/src/routes/admin.ts",
|
|
890
|
+
"backend/src/services/adminService.ts"
|
|
891
|
+
],
|
|
892
|
+
"decisions": ["Keep Telegram as the human clarification channel"],
|
|
893
|
+
"risks": ["Breaking existing clients"]
|
|
894
|
+
}
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
### 2. Inspect session state
|
|
898
|
+
|
|
899
|
+
Call `get_session_context`:
|
|
900
|
+
|
|
901
|
+
```json
|
|
902
|
+
{
|
|
903
|
+
"session_id": "backend-refactor"
|
|
904
|
+
}
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
This returns:
|
|
908
|
+
|
|
909
|
+
- saved context if it exists
|
|
910
|
+
- whether the session is currently paired
|
|
911
|
+
- stored tmux targeting data if configured
|
|
912
|
+
- Telegram binding metadata if pairing exists
|
|
913
|
+
- a `status_message` describing whether pairing and tmux delivery are active
|
|
914
|
+
|
|
915
|
+
### 2. Bind tmux context for Telegram delivery
|
|
916
|
+
|
|
917
|
+
If Codex is running inside tmux, capture the current tmux context before you leave the workstation. A reliable way is:
|
|
918
|
+
|
|
919
|
+
```bash
|
|
920
|
+
tmux display-message -p '#{session_name} #{window_name} #{window_index} #{pane_id} #{pane_index}'
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
The preferred path is to pass these attributes, together with the agent workspace `cwd`, directly into `create_session_pair_code`, so pairing immediately creates a distinct session identity for this agent and gives the server the correct `.mcp-xchange` root:
|
|
924
|
+
|
|
925
|
+
```json
|
|
926
|
+
{
|
|
927
|
+
"tmux_session_name": "dev",
|
|
928
|
+
"tmux_window_name": "test",
|
|
929
|
+
"tmux_window_index": 1,
|
|
930
|
+
"tmux_pane_id": "%7",
|
|
931
|
+
"tmux_pane_index": 0
|
|
932
|
+
}
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
Important:
|
|
936
|
+
|
|
937
|
+
- if you pair without tmux attributes, Telegram linking still succeeds
|
|
938
|
+
- but `tmux_target` stays empty
|
|
939
|
+
- in that state tmux nudges and Mini App controls will not work until `set_tmux_target` is called later
|
|
940
|
+
|
|
941
|
+
You can still call `set_tmux_target` later if you need to update or override the stored target:
|
|
942
|
+
|
|
943
|
+
```json
|
|
944
|
+
{
|
|
945
|
+
"session_id": "backend-refactor",
|
|
946
|
+
"tmux_session_name": "work",
|
|
947
|
+
"tmux_window_name": "test",
|
|
948
|
+
"tmux_window_index": 1,
|
|
949
|
+
"tmux_pane_id": "%7",
|
|
950
|
+
"tmux_pane_index": 0,
|
|
951
|
+
"tmux_target": "%7"
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
After that, when the paired session receives an unsolicited inbox message, the service can run:
|
|
956
|
+
|
|
957
|
+
```bash
|
|
958
|
+
tmux send-keys -t %7 "проверь inbox" C-m
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
The service does not forward the Telegram message text into tmux. It only nudges the agent. The agent still reads actual message contents through `get_telegram_inbox` and `delete_telegram_inbox_message`, or through `get_telegram_inbox_count` first in passive no-tmux mode.
|
|
962
|
+
If several Telegram messages arrive close together, the nudge is debounced by `TMUX_NUDGE_DEBOUNCE_SECONDS` so the agent gets one wake-up for the batch instead of one wake-up per message.
|
|
963
|
+
Ordinary Telegram messages are always stored in the inbox of the currently active session for that Telegram identity.
|
|
964
|
+
|
|
965
|
+
### 3. Pair a session
|
|
966
|
+
|
|
967
|
+
If the user asks to register or link the current agent in Telegram, the agent should first collect:
|
|
968
|
+
|
|
969
|
+
- current `cwd`
|
|
970
|
+
- tmux attributes when running inside tmux
|
|
971
|
+
|
|
972
|
+
Only after that should it call `create_session_pair_code`.
|
|
973
|
+
|
|
974
|
+
Call `create_session_pair_code` with a stable session id:
|
|
975
|
+
|
|
976
|
+
```json
|
|
977
|
+
{
|
|
978
|
+
"session_id": "backend-refactor",
|
|
979
|
+
"session_label": "Backend refactor"
|
|
980
|
+
}
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
The tool returns a short-lived code, a status message for the agent, and optionally a Telegram deep link.
|
|
984
|
+
|
|
985
|
+
If you omit `session_id`, the server derives one automatically.
|
|
986
|
+
|
|
987
|
+
If multiple agents work from different tmux windows or panes, pass tmux attributes during pairing so the server derives distinct session identities automatically:
|
|
988
|
+
|
|
989
|
+
```json
|
|
990
|
+
{
|
|
991
|
+
"tmux_session_name": "dev",
|
|
992
|
+
"tmux_window_name": "test",
|
|
993
|
+
"tmux_window_index": 1,
|
|
994
|
+
"tmux_pane_id": "%7",
|
|
995
|
+
"tmux_pane_index": 0
|
|
996
|
+
}
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
With tmux attributes present, they participate in the derived default `session_id` and `session_label`, which prevents multiple agents from collapsing into one Telegram session even if they share similar project structure. In practice this means `/menu` can later show both agents separately and let Telegram switch the active async context between them.
|
|
1000
|
+
|
|
1001
|
+
### 4. Link in Telegram
|
|
1002
|
+
|
|
1003
|
+
In Telegram, send one of:
|
|
1004
|
+
|
|
1005
|
+
```text
|
|
1006
|
+
/start ABCD-EFGH
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
or
|
|
1010
|
+
|
|
1011
|
+
```text
|
|
1012
|
+
/link ABCD-EFGH
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
After successful pairing, the bot sends a main inline menu. You can also reopen it later with:
|
|
1016
|
+
|
|
1017
|
+
```text
|
|
1018
|
+
/menu
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
### 5. Ask the user
|
|
1022
|
+
|
|
1023
|
+
Call `ask_user_telegram`:
|
|
1024
|
+
|
|
1025
|
+
```json
|
|
1026
|
+
{
|
|
1027
|
+
"session_id": "backend-refactor",
|
|
1028
|
+
"question": "Can I change the response shape for the admin API?",
|
|
1029
|
+
"task": "Admin API cleanup",
|
|
1030
|
+
"context": "The old shape is inconsistent and adds special cases in the client.",
|
|
1031
|
+
"options": [
|
|
1032
|
+
"Keep current response shape",
|
|
1033
|
+
"Change response shape and update all callers"
|
|
1034
|
+
],
|
|
1035
|
+
"recommended_option": "Keep current response shape",
|
|
1036
|
+
"fallback_if_timeout": "Keep current response shape"
|
|
1037
|
+
}
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
If you want the saved session context to be appended automatically, set:
|
|
1041
|
+
|
|
1042
|
+
```json
|
|
1043
|
+
{
|
|
1044
|
+
"use_saved_context": true
|
|
1045
|
+
}
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
### 6. Clear session context
|
|
1049
|
+
|
|
1050
|
+
Call `clear_session_context`:
|
|
1051
|
+
|
|
1052
|
+
```json
|
|
1053
|
+
{
|
|
1054
|
+
"session_id": "backend-refactor"
|
|
1055
|
+
}
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
This removes saved context and also removes Telegram pairing for the same session.
|
|
1059
|
+
|
|
1060
|
+
### 7. Clear session pairing
|
|
1061
|
+
|
|
1062
|
+
Call `clear_session_pairing`:
|
|
1063
|
+
|
|
1064
|
+
```json
|
|
1065
|
+
{
|
|
1066
|
+
"session_id": "backend-refactor"
|
|
1067
|
+
}
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
This removes the Telegram binding so the session can be paired again.
|
|
1071
|
+
|
|
1072
|
+
### 8. Send one-way notification
|
|
1073
|
+
|
|
1074
|
+
Call `notify_telegram`:
|
|
1075
|
+
|
|
1076
|
+
```json
|
|
1077
|
+
{
|
|
1078
|
+
"session_id": "backend-refactor",
|
|
1079
|
+
"message": "Build finished successfully. Ready for review.",
|
|
1080
|
+
"task": "Admin API cleanup",
|
|
1081
|
+
"risk_level": "low",
|
|
1082
|
+
"use_saved_context": true
|
|
1083
|
+
}
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
This sends a Telegram message without waiting for a reply.
|
|
1087
|
+
|
|
1088
|
+
### 9. Poll unsolicited Telegram inbox messages
|
|
1089
|
+
|
|
1090
|
+
If the user writes to the bot without replying to an active question, the message is stored in the session inbox.
|
|
1091
|
+
|
|
1092
|
+
If the paired session has a tmux target, the preferred path is event-driven:
|
|
1093
|
+
|
|
1094
|
+
- Telegram message arrives
|
|
1095
|
+
- service stores it in inbox
|
|
1096
|
+
- service nudges tmux
|
|
1097
|
+
- agent wakes up and calls `get_telegram_inbox`
|
|
1098
|
+
|
|
1099
|
+
If there is no tmux nudge path, use passive mode. First call `get_telegram_inbox_count`:
|
|
1100
|
+
|
|
1101
|
+
```json
|
|
1102
|
+
{
|
|
1103
|
+
"session_id": "backend-refactor"
|
|
1104
|
+
}
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
Only if `total > 0`, call `get_telegram_inbox`:
|
|
1108
|
+
|
|
1109
|
+
```json
|
|
1110
|
+
{
|
|
1111
|
+
"session_id": "backend-refactor"
|
|
1112
|
+
}
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
After the agent processes an inbox item, delete it explicitly with `delete_telegram_inbox_message`:
|
|
1116
|
+
|
|
1117
|
+
```json
|
|
1118
|
+
{
|
|
1119
|
+
"session_id": "backend-refactor",
|
|
1120
|
+
"message_id": "inbox_20260504120000_ab12cd"
|
|
1121
|
+
}
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
## Telegram menu
|
|
1125
|
+
|
|
1126
|
+
The bot now exposes a small inline menu for Telegram-side control:
|
|
1127
|
+
|
|
1128
|
+
- `Inbox` shows the latest unsolicited inbox messages for the active session
|
|
1129
|
+
- tapping an inbox item opens its full contents
|
|
1130
|
+
- the detail card has a `Delete` action
|
|
1131
|
+
- `Session: ...` shows the currently active linked session
|
|
1132
|
+
- `Refresh` re-renders the current menu state
|
|
1133
|
+
|
|
1134
|
+
Menu callback payloads stay short. Buttons only carry a short Redis key, while the actual menu state is stored server-side with TTL in Redis.
|
|
1135
|
+
|
|
1136
|
+
## Queue mode
|
|
1137
|
+
|
|
1138
|
+
`MODE=reject`
|
|
1139
|
+
|
|
1140
|
+
- if one request is already active, the next tool call fails immediately
|
|
1141
|
+
|
|
1142
|
+
`MODE=queue`
|
|
1143
|
+
|
|
1144
|
+
- requests are queued FIFO
|
|
1145
|
+
- queued requests are not sent to Telegram until they become active
|
|
1146
|
+
|
|
1147
|
+
## Connect to Codex
|
|
1148
|
+
|
|
1149
|
+
Recommended long-running service flow:
|
|
1150
|
+
|
|
1151
|
+
1. Start the service.
|
|
1152
|
+
|
|
1153
|
+
For local client mode:
|
|
1154
|
+
|
|
1155
|
+
```bash
|
|
1156
|
+
yarn dev:client
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
Then register:
|
|
1160
|
+
|
|
1161
|
+
```bash
|
|
1162
|
+
codex mcp add telegramHuman --url http://127.0.0.1:8787/mcp
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
For gateway/both mode behind nginx:
|
|
1166
|
+
|
|
1167
|
+
```bash
|
|
1168
|
+
yarn dev:builder
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
2. Register the already-running MCP endpoint in Codex:
|
|
1172
|
+
|
|
1173
|
+
```bash
|
|
1174
|
+
codex mcp add telegramHuman --url http://127.0.0.1:8080/api/mcp
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
If you enable bearer auth with `MCP_HTTP_BEARER_TOKEN`, register it like this:
|
|
1178
|
+
|
|
1179
|
+
```bash
|
|
1180
|
+
export TELEGRAM_MCP_BEARER_TOKEN="your-token"
|
|
1181
|
+
codex mcp add telegramHuman \
|
|
1182
|
+
--url http://127.0.0.1:8080/api/mcp \
|
|
1183
|
+
--bearer-token-env-var TELEGRAM_MCP_BEARER_TOKEN
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
Why these URLs differ:
|
|
1187
|
+
|
|
1188
|
+
- `dev:client` serves MCP directly from the local standalone listener, by default at `http://127.0.0.1:8787/mcp`
|
|
1189
|
+
- `dev:builder` / `both` mode serves MCP through the shared backend ingress, by default at `http://127.0.0.1:8080/api/mcp`
|
|
1190
|
+
|
|
1191
|
+
For externally exposed deployments:
|
|
1192
|
+
|
|
1193
|
+
- prefer enabling `MCP_HTTP_BEARER_TOKEN`
|
|
1194
|
+
- keep `/sessions` and `/prune` disabled unless you actively need them
|
|
1195
|
+
- leave WebApp access to Telegram `initData` validation plus its short-lived session token flow
|
|
1196
|
+
|
|
1197
|
+
This project no longer uses stdio mode. MCP access is exposed only through the HTTP endpoint.
|
|
1198
|
+
|
|
1199
|
+
Current Moleculer feature services:
|
|
1200
|
+
|
|
1201
|
+
- `telegramMcp.runtime`
|
|
1202
|
+
- `telegramMcp.pair`
|
|
1203
|
+
- `telegramMcp.sessionContext`
|
|
1204
|
+
- `telegramMcp.notify`
|
|
1205
|
+
- `telegramMcp.inbox`
|
|
1206
|
+
- `telegramMcp.approval`
|
|
1207
|
+
- `telegramMcp.browser`
|
|
1208
|
+
- `telegramMcp.collaboration`
|
|
1209
|
+
- `telegramMcp.mcpServer`
|
|
1210
|
+
- `telegramMcp.http`
|
|
1211
|
+
|
|
1212
|
+
## Example AGENTS.md snippet
|
|
1213
|
+
|
|
1214
|
+
```md
|
|
1215
|
+
## Telegram clarification
|
|
1216
|
+
|
|
1217
|
+
If you need clarification from the user and the answer is required to continue safely,
|
|
1218
|
+
use the MCP tools `create_session_pair_code` and `ask_user_telegram`.
|
|
1219
|
+
|
|
1220
|
+
Rules:
|
|
1221
|
+
|
|
1222
|
+
- prefer explicit `session_id` when multiple projects or sessions share one Telegram bot; otherwise the derived default session is acceptable
|
|
1223
|
+
- save or refresh session context before risky question flows when it helps reuse context
|
|
1224
|
+
- if the agent runs inside tmux, capture `#{session_name} #{window_name} #{window_index} #{pane_id} #{pane_index}` and pass them to `create_session_pair_code`; use `set_tmux_target` later only if you need to refresh or override the target
|
|
1225
|
+
- if the session is not linked yet, create a pair code first
|
|
1226
|
+
- if a paired session has a configured tmux target, treat a tmux nudge as the signal to check the inbox
|
|
1227
|
+
- if a paired session has no tmux target, periodically call `get_telegram_inbox_count`
|
|
1228
|
+
- call `get_telegram_inbox` only if the count is greater than zero
|
|
1229
|
+
- before the final answer in passive no-tmux mode, check `get_telegram_inbox_count`
|
|
1230
|
+
- after handling an inbox item, call `delete_telegram_inbox_message`
|
|
1231
|
+
- include concise task context
|
|
1232
|
+
- include affected files when relevant
|
|
1233
|
+
- include a conservative fallback if the request times out
|
|
1234
|
+
- never send secrets, tokens, private keys, database URLs, or raw customer data
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
## Verification
|
|
1238
|
+
|
|
1239
|
+
Commands run locally:
|
|
1240
|
+
|
|
1241
|
+
- `npm run format:check`
|
|
1242
|
+
- `npm run build`
|
|
1243
|
+
- `npm run lint`
|
|
1244
|
+
|
|
1245
|
+
Tests are not implemented in this iteration.
|
|
1246
|
+
|
|
1247
|
+
## Known limitations
|
|
1248
|
+
|
|
1249
|
+
- Telegram is the only transport backend implemented right now
|
|
1250
|
+
- no webhook support, long polling only
|
|
1251
|
+
- no automated tests in the current iteration
|
|
1252
|
+
- queued requests are coordinated in-process, with Redis used as the shared state backend
|
|
1253
|
+
- session context tools are implemented, but there is no version history or merge strategy beyond last write wins
|
|
1254
|
+
- inbox polling is explicit; unsolicited Telegram messages are not pushed into the agent automatically
|
|
1255
|
+
- MCP HTTP sessions are kept in-process; restarting the service drops active MCP client sessions and they reconnect cleanly
|
|
1256
|
+
|
|
1257
|
+
## Security notes
|
|
1258
|
+
|
|
1259
|
+
- all outbound question content is redacted before sending to Telegram
|
|
1260
|
+
- replies are accepted only from the Telegram user/chat bound to the session
|
|
1261
|
+
- pairing codes are short-lived and one-time use
|
|
1262
|
+
- do not use this server to send secrets, raw `.env` content, tokens, private keys, or customer data
|