botmsg 0.1.0
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/README.md +984 -0
- package/dist/index.js +2617 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
# botmsg
|
|
2
|
+
|
|
3
|
+
> Universal MCP Server for multi-platform bot messaging — one interface, seven platforms.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/botmsg)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
Send messages to **DingTalk (钉钉)**, **WeCom (企业微信)**, **Feishu (飞书)**, **Lark**, **Slack**, **Discord**, and **Telegram** through a unified MCP (Model Context Protocol) interface. Configure bots via environment variables or YAML/JSON config files, then let AI assistants send notifications, alerts, and reports across all your team channels.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
- [Features](#features)
|
|
16
|
+
- [How It Works](#how-it-works)
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [MCP Client Configuration](#mcp-client-configuration)
|
|
19
|
+
- [Claude Desktop](#claude-desktop)
|
|
20
|
+
- [VS Code (Copilot)](#vs-code-copilot)
|
|
21
|
+
- [Cursor](#cursor)
|
|
22
|
+
- [Windsurf](#windsurf)
|
|
23
|
+
- [Cline](#cline)
|
|
24
|
+
- [Generic / stdio](#generic--stdio)
|
|
25
|
+
- [Configuration](#configuration)
|
|
26
|
+
- [Mode A: Environment Variables](#mode-a-environment-variables)
|
|
27
|
+
- [Mode B: External Config File (YAML/JSON)](#mode-b-external-config-file-yamljson)
|
|
28
|
+
- [Bot Naming Convention](#bot-naming-convention)
|
|
29
|
+
- [Global Settings](#global-settings)
|
|
30
|
+
- [Platform Setup Guides](#platform-setup-guides)
|
|
31
|
+
- [DingTalk (钉钉)](#dingtalk-钉钉)
|
|
32
|
+
- [WeCom (企业微信)](#wecom-企业微信)
|
|
33
|
+
- [Feishu (飞书)](#feishu-飞书)
|
|
34
|
+
- [Lark (International)](#lark-international)
|
|
35
|
+
- [Slack](#slack)
|
|
36
|
+
- [Discord](#discord)
|
|
37
|
+
- [Telegram](#telegram)
|
|
38
|
+
- [MCP Tools Reference](#mcp-tools-reference)
|
|
39
|
+
- [send_message](#send_message)
|
|
40
|
+
- [send_file](#send_file)
|
|
41
|
+
- [send_broadcast](#send_broadcast)
|
|
42
|
+
- [send_batch](#send_batch)
|
|
43
|
+
- [list_bots](#list_bots)
|
|
44
|
+
- [message_status](#message_status)
|
|
45
|
+
- [render_template](#render_template)
|
|
46
|
+
- [Message Types & Platform Mapping](#message-types--platform-mapping)
|
|
47
|
+
- [Template Engine](#template-engine)
|
|
48
|
+
- [Built-in Helpers](#built-in-helpers)
|
|
49
|
+
- [Conditional Logic](#conditional-logic)
|
|
50
|
+
- [Partials](#partials)
|
|
51
|
+
- [Rate Limiting & Retry](#rate-limiting--retry)
|
|
52
|
+
- [Audit Logging](#audit-logging)
|
|
53
|
+
- [Dry Run Mode](#dry-run-mode)
|
|
54
|
+
- [Error Handling](#error-handling)
|
|
55
|
+
- [Development](#development)
|
|
56
|
+
- [Troubleshooting](#troubleshooting)
|
|
57
|
+
- [License](#license)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- **7 platforms, 1 interface** — Unified message API across DingTalk, WeCom, Feishu, Lark, Slack, Discord, and Telegram
|
|
64
|
+
- **7 message types** — `text`, `markdown`, `link`, `image`, `card`, `news`, `file` with automatic cross-platform adaptation
|
|
65
|
+
- **Template engine** — Handlebars templates with 12+ custom helpers (`{{date}}`, `{{uppercase}}`, `{{if_eq}}`, `{{now}}`, etc.)
|
|
66
|
+
- **Broadcast** — Send one message to multiple bots across different platforms simultaneously
|
|
67
|
+
- **Batch send** — Send to multiple targets (e.g., Telegram groups) through a single bot
|
|
68
|
+
- **Rate limiting** — Per-platform Bottleneck limiters matching each API's rate limits, with exponential backoff retry
|
|
69
|
+
- **Audit logging** — In-memory ring buffer + optional JSONL file persistence for full message tracking
|
|
70
|
+
- **Dual configuration** — Environment variables for quick setup, YAML/JSON files for complex deployments
|
|
71
|
+
- **Dry run mode** — Preview message payloads without actually sending
|
|
72
|
+
- **Zero-config binary** — Runs via `npx botmsg`, no global installation needed
|
|
73
|
+
|
|
74
|
+
## How It Works
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
┌──────────────┐ MCP (stdio) ┌──────────┐ HTTP/HTTPS ┌─────────────────┐
|
|
78
|
+
│ AI Assistant │ ◄────────────────► │ botmsg │ ────────────────► │ Bot Platforms │
|
|
79
|
+
│ (Claude, │ JSON-RPC tools │ MCP │ Webhook APIs │ DingTalk, WeCom │
|
|
80
|
+
│ VS Code, │ │ Server │ │ Feishu, Slack.. │
|
|
81
|
+
│ Cursor...) │ │ │ │ │
|
|
82
|
+
└──────────────┘ └──────────┘ └─────────────────┘
|
|
83
|
+
│
|
|
84
|
+
▼
|
|
85
|
+
┌──────────┐
|
|
86
|
+
│ Audit │
|
|
87
|
+
│ Log │
|
|
88
|
+
└──────────┘
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
1. Your AI assistant (Claude, VS Code Copilot, Cursor, etc.) discovers `botmsg` via MCP protocol
|
|
92
|
+
2. It calls tools like `send_message`, `send_broadcast`, etc. with structured arguments
|
|
93
|
+
3. `botmsg` applies template rendering, rate limiting, and routes to the correct platform adapter
|
|
94
|
+
4. The platform adapter translates the unified message format into the platform-specific API payload
|
|
95
|
+
5. Audit logger records every send attempt with status, latency, and error details
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Installation
|
|
100
|
+
|
|
101
|
+
No installation needed — just use `npx`:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx -y botmsg
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Or install globally:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm install -g botmsg
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Requirements:** Node.js >= 18.0.0
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## MCP Client Configuration
|
|
118
|
+
|
|
119
|
+
### Claude Desktop
|
|
120
|
+
|
|
121
|
+
Edit your Claude Desktop config file:
|
|
122
|
+
|
|
123
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
124
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"mcpServers": {
|
|
129
|
+
"botmsg": {
|
|
130
|
+
"command": "npx",
|
|
131
|
+
"args": ["-y", "botmsg"],
|
|
132
|
+
"env": {
|
|
133
|
+
"BOTMSG_DINGTALK_OPS_WEBHOOK": "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN",
|
|
134
|
+
"BOTMSG_WECOM_DEV_WEBHOOK": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY",
|
|
135
|
+
"BOTMSG_FEISHU_ALERT_WEBHOOK": "https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_HOOK",
|
|
136
|
+
"BOTMSG_SLACK_GENERAL_WEBHOOK": "https://hooks.slack.com/services/T00/B00/xxx",
|
|
137
|
+
"BOTMSG_DISCORD_GAMING_WEBHOOK": "https://discord.com/api/webhooks/123456/TOKEN",
|
|
138
|
+
"BOTMSG_TELEGRAM_BOT_TOKEN": "123456:ABC-DEF...",
|
|
139
|
+
"BOTMSG_TELEGRAM_BOT_CHAT_ID": "-1001234567890"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
> **Windows Note:** If `npx` is not found, wrap with `cmd`:
|
|
147
|
+
> ```json
|
|
148
|
+
> {
|
|
149
|
+
> "mcpServers": {
|
|
150
|
+
> "botmsg": {
|
|
151
|
+
> "command": "cmd",
|
|
152
|
+
> "args": ["/c", "npx", "-y", "botmsg"],
|
|
153
|
+
> "env": { "..." : "..." }
|
|
154
|
+
> }
|
|
155
|
+
> }
|
|
156
|
+
> }
|
|
157
|
+
> ```
|
|
158
|
+
|
|
159
|
+
### VS Code (Copilot)
|
|
160
|
+
|
|
161
|
+
Create `.vscode/mcp.json` in your project root:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"servers": {
|
|
166
|
+
"botmsg": {
|
|
167
|
+
"command": "npx",
|
|
168
|
+
"args": ["-y", "botmsg"],
|
|
169
|
+
"env": {
|
|
170
|
+
"BOTMSG_DINGTALK_OPS_WEBHOOK": "${env:DINGTALK_WEBHOOK}",
|
|
171
|
+
"BOTMSG_SLACK_GENERAL_WEBHOOK": "${env:SLACK_WEBHOOK}"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Cursor
|
|
179
|
+
|
|
180
|
+
Open Settings > MCP > Add new MCP server, or edit `~/.cursor/mcp.json`:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"mcpServers": {
|
|
185
|
+
"botmsg": {
|
|
186
|
+
"command": "npx",
|
|
187
|
+
"args": ["-y", "botmsg"],
|
|
188
|
+
"env": {
|
|
189
|
+
"BOTMSG_DINGTALK_OPS_WEBHOOK": "https://oapi.dingtalk.com/robot/send?access_token=xxx"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Windsurf
|
|
197
|
+
|
|
198
|
+
Add to your Windsurf MCP config:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"mcpServers": {
|
|
203
|
+
"botmsg": {
|
|
204
|
+
"command": "npx",
|
|
205
|
+
"args": ["-y", "botmsg"],
|
|
206
|
+
"env": {
|
|
207
|
+
"BOTMSG_CONFIG": "/path/to/bots.yaml"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Cline
|
|
215
|
+
|
|
216
|
+
Add to Cline MCP settings:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"mcpServers": {
|
|
221
|
+
"botmsg": {
|
|
222
|
+
"command": "npx",
|
|
223
|
+
"args": ["-y", "botmsg"],
|
|
224
|
+
"env": {
|
|
225
|
+
"BOTMSG_TELEGRAM_BOT_TOKEN": "123456:ABC...",
|
|
226
|
+
"BOTMSG_TELEGRAM_BOT_CHAT_ID": "-1001234"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Generic / stdio
|
|
234
|
+
|
|
235
|
+
`botmsg` speaks MCP over stdio. Any MCP-compatible client can launch it:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
node node_modules/botmsg/dist/index.js
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Or directly:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npx -y botmsg
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Configuration
|
|
250
|
+
|
|
251
|
+
### Mode A: Environment Variables
|
|
252
|
+
|
|
253
|
+
The simplest way. Pattern: `BOTMSG_{PLATFORM}_{INSTANCE}_{FIELD}`
|
|
254
|
+
|
|
255
|
+
Each bot is identified by a **name** composed of `{platform}-{instance}`. For example, `dingtalk-ops` creates a DingTalk bot named "ops".
|
|
256
|
+
|
|
257
|
+
#### DingTalk (钉钉)
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
BOTMSG_DINGTALK_OPS_WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN
|
|
261
|
+
BOTMSG_DINGTALK_OPS_SECRET=SEC... # Optional: for HMAC-SHA256
|
|
262
|
+
BOTMSG_DINGTALK_OPS_SECURITY=sign # keyword (default) | ip | sign
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### WeCom (企业微信)
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
BOTMSG_WECOM_DEV_WEBHOOK=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### Feishu (飞书)
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
BOTMSG_FEISHU_ALERT_WEBHOOK=https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_HOOK
|
|
275
|
+
BOTMSG_FEISHU_ALERT_SECRET=YOUR_SECRET # Optional: HMAC-SHA256
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### Lark (International Feishu)
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
BOTMSG_LARK_GLOBAL_WEBHOOK=https://open.larksuite.com/open-apis/bot/v2/hook/YOUR_HOOK
|
|
282
|
+
BOTMSG_LARK_GLOBAL_SECRET=YOUR_SECRET # Optional
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### Slack
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
BOTMSG_SLACK_GENERAL_WEBHOOK=https://hooks.slack.com/services/T00000/B00000/xxxxx
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Discord
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
BOTMSG_DISCORD_GAMING_WEBHOOK=https://discord.com/api/webhooks/WEBHOOK_ID/TOKEN
|
|
295
|
+
BOTMSG_DISCORD_GAMING_USERNAME=MyBot # Optional: override username
|
|
296
|
+
BOTMSG_DISCORD_GAMING_AVATAR_URL=https://... # Optional: override avatar
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### Telegram
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
BOTMSG_TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
|
|
303
|
+
BOTMSG_TELEGRAM_BOT_CHAT_ID=-1001234567890 # Group/channel ID
|
|
304
|
+
BOTMSG_TELEGRAM_BOT_PARSE_MODE=MarkdownV2 # MarkdownV2 | HTML | (empty)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Multiple Instances
|
|
308
|
+
|
|
309
|
+
You can configure multiple bots per platform by using different instance names:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
BOTMSG_DINGTALK_OPS_WEBHOOK=https://oapi.dingtalk.com/...?access_token=TOKEN_A
|
|
313
|
+
BOTMSG_DINGTALK_ALERTS_WEBHOOK=https://oapi.dingtalk.com/...?access_token=TOKEN_B
|
|
314
|
+
BOTMSG_SLACK_ENGINEERING_WEBHOOK=https://hooks.slack.com/services/...
|
|
315
|
+
BOTMSG_SLACK_MARKETING_WEBHOOK=https://hooks.slack.com/services/...
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
This creates 4 bots: `dingtalk-ops`, `dingtalk-alerts`, `slack-engineering`, `slack-marketing`.
|
|
319
|
+
|
|
320
|
+
### Mode B: External Config File (YAML/JSON)
|
|
321
|
+
|
|
322
|
+
For complex deployments, point `BOTMSG_CONFIG` to a config file:
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"mcpServers": {
|
|
327
|
+
"botmsg": {
|
|
328
|
+
"command": "npx",
|
|
329
|
+
"args": ["-y", "botmsg"],
|
|
330
|
+
"env": {
|
|
331
|
+
"BOTMSG_CONFIG": "/path/to/bots.yaml"
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### YAML Format (`bots.yaml`)
|
|
339
|
+
|
|
340
|
+
```yaml
|
|
341
|
+
bots:
|
|
342
|
+
dingtalk-ops:
|
|
343
|
+
platform: dingtalk
|
|
344
|
+
webhook: "https://oapi.dingtalk.com/robot/send?access_token=xxx"
|
|
345
|
+
secret: "SEC..."
|
|
346
|
+
security: sign
|
|
347
|
+
|
|
348
|
+
wecom-dev:
|
|
349
|
+
platform: wecom
|
|
350
|
+
webhook: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
|
|
351
|
+
|
|
352
|
+
feishu-alert:
|
|
353
|
+
platform: feishu
|
|
354
|
+
webhook: "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
|
|
355
|
+
secret: "xxx"
|
|
356
|
+
|
|
357
|
+
lark-global:
|
|
358
|
+
platform: lark
|
|
359
|
+
webhook: "https://open.larksuite.com/open-apis/bot/v2/hook/xxx"
|
|
360
|
+
|
|
361
|
+
slack-general:
|
|
362
|
+
platform: slack
|
|
363
|
+
webhook: "https://hooks.slack.com/services/T.../B.../xxx"
|
|
364
|
+
|
|
365
|
+
discord-gaming:
|
|
366
|
+
platform: discord
|
|
367
|
+
webhook: "https://discord.com/api/webhooks/xxx/yyy"
|
|
368
|
+
username: "GameBot"
|
|
369
|
+
|
|
370
|
+
telegram-bot:
|
|
371
|
+
platform: telegram
|
|
372
|
+
token: "123456:ABC..."
|
|
373
|
+
chat_id: "-1001234567"
|
|
374
|
+
parse_mode: "MarkdownV2"
|
|
375
|
+
|
|
376
|
+
settings:
|
|
377
|
+
log_level: info
|
|
378
|
+
audit_log: "/tmp/botmsg-audit.jsonl"
|
|
379
|
+
max_retries: 3
|
|
380
|
+
dry_run: false
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### JSON Format (`bots.json`)
|
|
384
|
+
|
|
385
|
+
```json
|
|
386
|
+
{
|
|
387
|
+
"bots": {
|
|
388
|
+
"dingtalk-ops": {
|
|
389
|
+
"platform": "dingtalk",
|
|
390
|
+
"webhook": "https://oapi.dingtalk.com/robot/send?access_token=xxx",
|
|
391
|
+
"secret": "SEC...",
|
|
392
|
+
"security": "sign"
|
|
393
|
+
},
|
|
394
|
+
"telegram-bot": {
|
|
395
|
+
"platform": "telegram",
|
|
396
|
+
"token": "123456:ABC...",
|
|
397
|
+
"chat_id": "-1001234567"
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
"settings": {
|
|
401
|
+
"log_level": "info",
|
|
402
|
+
"max_retries": 3
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### Mixed Mode
|
|
408
|
+
|
|
409
|
+
File config takes priority, env vars supplement:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
BOTMSG_CONFIG=/path/to/bots.yaml
|
|
413
|
+
BOTMSG_SLACK_EXTRA_WEBHOOK=https://hooks.slack.com/... # Added on top of file config
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Bot Naming Convention
|
|
417
|
+
|
|
418
|
+
Bot names are auto-generated as `{platform}-{instance}`:
|
|
419
|
+
|
|
420
|
+
| Env Variable | Bot Name |
|
|
421
|
+
|---|---|
|
|
422
|
+
| `BOTMSG_DINGTALK_OPS_WEBHOOK` | `dingtalk-ops` |
|
|
423
|
+
| `BOTMSG_WECOM_DEV_WEBHOOK` | `wecom-dev` |
|
|
424
|
+
| `BOTMSG_TELEGRAM_BOT_TOKEN` | `telegram-bot` |
|
|
425
|
+
| `BOTMSG_SLACK_GENERAL_WEBHOOK` | `slack-general` |
|
|
426
|
+
|
|
427
|
+
Use these names when calling tools: `{ "bot": "dingtalk-ops", ... }`
|
|
428
|
+
|
|
429
|
+
### Global Settings
|
|
430
|
+
|
|
431
|
+
| Variable | Default | Description |
|
|
432
|
+
|---|---|---|
|
|
433
|
+
| `BOTMSG_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
|
434
|
+
| `BOTMSG_AUDIT_LOG` | _(none)_ | Path to JSONL audit log file for persistent message tracking |
|
|
435
|
+
| `BOTMSG_MAX_RETRIES` | `3` | Maximum retry attempts on transient failures (0-10) |
|
|
436
|
+
| `BOTMSG_DRY_RUN` | `false` | When `true`, build payloads but don't send (useful for testing) |
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Platform Setup Guides
|
|
441
|
+
|
|
442
|
+
### DingTalk (钉钉)
|
|
443
|
+
|
|
444
|
+
1. Open the target group chat > Group Settings > Smart Group Assistant > Add Robot
|
|
445
|
+
2. Select "Custom (via Webhook)" robot type
|
|
446
|
+
3. Set security mode (recommended: **Sign** for HMAC-SHA256)
|
|
447
|
+
4. Copy the webhook URL (contains `access_token`)
|
|
448
|
+
5. If using sign mode, copy the `SEC...` secret
|
|
449
|
+
|
|
450
|
+
**API Docs:** https://open.dingtalk.com/document/orgapp/custom-robots-send-group-messages
|
|
451
|
+
|
|
452
|
+
### WeCom (企业微信)
|
|
453
|
+
|
|
454
|
+
1. Open the target group chat > Group Settings > Group Bots > Add Bot
|
|
455
|
+
2. Select "Webhook Bot"
|
|
456
|
+
3. Copy the webhook URL (contains `key=...`)
|
|
457
|
+
|
|
458
|
+
**API Docs:** https://developer.work.weixin.qq.com/document/path/99110
|
|
459
|
+
|
|
460
|
+
### Feishu (飞书)
|
|
461
|
+
|
|
462
|
+
1. Open the target group chat > Settings > Bots > Add Bot
|
|
463
|
+
2. Select "Custom Bot"
|
|
464
|
+
3. Copy the webhook URL (contains `/hook/...`)
|
|
465
|
+
4. Optionally enable signature verification and copy the secret
|
|
466
|
+
|
|
467
|
+
**API Docs:** https://open.feishu.cn/document/uktmuktmuktm/uctm5yjl3eto24ynxkjn
|
|
468
|
+
|
|
469
|
+
### Lark (International)
|
|
470
|
+
|
|
471
|
+
Same process as Feishu, but on the Lark (international) platform. The webhook URL will use `open.larksuite.com` instead of `open.feishu.cn`.
|
|
472
|
+
|
|
473
|
+
**API Docs:** https://open.larksuite.com/document/client-docs/bot-v3/add-custom-bot
|
|
474
|
+
|
|
475
|
+
### Slack
|
|
476
|
+
|
|
477
|
+
1. Go to https://api.slack.com/apps > Create New App
|
|
478
|
+
2. Select "From scratch", give it a name and workspace
|
|
479
|
+
3. Enable "Incoming Webhooks" in the sidebar
|
|
480
|
+
4. Click "Add New Webhook to Workspace" and select a channel
|
|
481
|
+
5. Copy the webhook URL (`https://hooks.slack.com/services/...`)
|
|
482
|
+
|
|
483
|
+
**API Docs:** https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks
|
|
484
|
+
|
|
485
|
+
### Discord
|
|
486
|
+
|
|
487
|
+
1. Open your Discord server > Server Settings > Integrations > Webhooks
|
|
488
|
+
2. Click "New Webhook", name it, select a channel
|
|
489
|
+
3. Copy the webhook URL (`https://discord.com/api/webhooks/...`)
|
|
490
|
+
|
|
491
|
+
**API Docs:** https://discord.com/developers/docs/resources/webhook
|
|
492
|
+
|
|
493
|
+
### Telegram
|
|
494
|
+
|
|
495
|
+
1. Open Telegram, search for `@BotFather`
|
|
496
|
+
2. Send `/newbot`, follow the prompts to create a bot
|
|
497
|
+
3. Copy the bot token (`123456:ABC-DEF...`)
|
|
498
|
+
4. Add the bot to your target group/chat
|
|
499
|
+
5. Get the chat ID (for groups, it starts with `-100`; you can use `@userinfobot` or the `getUpdates` API)
|
|
500
|
+
|
|
501
|
+
**API Docs:** https://core.telegram.org/bots/api
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## MCP Tools Reference
|
|
506
|
+
|
|
507
|
+
### `send_message`
|
|
508
|
+
|
|
509
|
+
Send a message to a configured bot. This is the primary tool.
|
|
510
|
+
|
|
511
|
+
**Parameters:**
|
|
512
|
+
|
|
513
|
+
| Parameter | Type | Required | Description |
|
|
514
|
+
|---|---|---|---|
|
|
515
|
+
| `bot` | string | Yes | Bot instance name (e.g., `dingtalk-ops`) |
|
|
516
|
+
| `type` | string | Yes | Message type: `text`, `markdown`, `link`, `image`, `card`, `news`, `file` |
|
|
517
|
+
| `content` | string | Yes | Message body. Supports Handlebars templates: `{{variable}}` |
|
|
518
|
+
| `title` | string | No | Title for markdown/link/card messages |
|
|
519
|
+
| `variables` | object | No | Template variables as key-value pairs |
|
|
520
|
+
| `at` | object | No | @mention config: `{ users: [...], mobiles: [...], all: bool }` |
|
|
521
|
+
| `link_url` | string | No | URL for link-type messages |
|
|
522
|
+
| `pic_url` | string | No | Thumbnail/picture URL |
|
|
523
|
+
| `buttons` | array | No | Buttons for card messages: `[{ title, url }]` |
|
|
524
|
+
| `single_button_text` | string | No | Single button text (DingTalk actionCard) |
|
|
525
|
+
| `single_button_url` | string | No | Single button URL |
|
|
526
|
+
| `news_items` | array | No | News items: `[{ title, description?, url, pic_url? }]` |
|
|
527
|
+
| `image_url` | string | No | Image URL for image-type messages |
|
|
528
|
+
| `image_base64` | string | No | Base64-encoded image (WeCom only) |
|
|
529
|
+
|
|
530
|
+
**Example — Text with @mention:**
|
|
531
|
+
|
|
532
|
+
```json
|
|
533
|
+
{
|
|
534
|
+
"bot": "dingtalk-ops",
|
|
535
|
+
"type": "text",
|
|
536
|
+
"content": "Server CPU exceeded 90%",
|
|
537
|
+
"at": { "mobiles": ["13800138000"], "all": false }
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Example — Markdown with template variables:**
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"bot": "slack-engineering",
|
|
546
|
+
"type": "markdown",
|
|
547
|
+
"content": "## Deploy Report\n*Service:* {{service}}\n*Status:* {{status}}\n*Duration:* {{duration}}",
|
|
548
|
+
"variables": { "service": "user-api", "status": "Success", "duration": "3m 24s" },
|
|
549
|
+
"title": "Deploy Notification"
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Example — Link card:**
|
|
554
|
+
|
|
555
|
+
```json
|
|
556
|
+
{
|
|
557
|
+
"bot": "wecom-dev",
|
|
558
|
+
"type": "link",
|
|
559
|
+
"content": "PR #142 merged to main branch",
|
|
560
|
+
"title": "PR Merged",
|
|
561
|
+
"link_url": "https://github.com/org/repo/pull/142",
|
|
562
|
+
"pic_url": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Example — Interactive card with buttons:**
|
|
567
|
+
|
|
568
|
+
```json
|
|
569
|
+
{
|
|
570
|
+
"bot": "feishu-alert",
|
|
571
|
+
"type": "card",
|
|
572
|
+
"content": "A deployment requires your approval.",
|
|
573
|
+
"title": "Deploy Approval",
|
|
574
|
+
"buttons": [
|
|
575
|
+
{ "title": "Approve", "url": "https://example.com/approve/123" },
|
|
576
|
+
{ "title": "Reject", "url": "https://example.com/reject/123" }
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
**Example — News feed:**
|
|
582
|
+
|
|
583
|
+
```json
|
|
584
|
+
{
|
|
585
|
+
"bot": "dingtalk-ops",
|
|
586
|
+
"type": "news",
|
|
587
|
+
"content": "",
|
|
588
|
+
"news_items": [
|
|
589
|
+
{ "title": "Weekly Report: Q2 Summary", "url": "https://example.com/reports/q2", "pic_url": "https://example.com/img/q2.png" },
|
|
590
|
+
{ "title": "New Feature: Bot Broadcast", "url": "https://example.com/blog/broadcast" },
|
|
591
|
+
{ "title": "Incident Postmortem: June 20", "url": "https://example.com/postmortem/0620" }
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### `send_file`
|
|
597
|
+
|
|
598
|
+
Send a file or image through a bot. Support varies by platform.
|
|
599
|
+
|
|
600
|
+
| Parameter | Type | Required | Description |
|
|
601
|
+
|---|---|---|---|
|
|
602
|
+
| `bot` | string | Yes | Bot instance name |
|
|
603
|
+
| `file_path` | string | Yes | Absolute path to the file |
|
|
604
|
+
| `caption` | string | No | Caption for the file |
|
|
605
|
+
|
|
606
|
+
**Platform support:**
|
|
607
|
+
|
|
608
|
+
| Platform | File Support |
|
|
609
|
+
|---|---|
|
|
610
|
+
| WeCom | Full support via media_id upload (max 20MB) |
|
|
611
|
+
| Discord | Full support via multipart upload (max 25MB) |
|
|
612
|
+
| Telegram | Full support via sendDocument (max 50MB) |
|
|
613
|
+
| DingTalk | Not supported (degrades to link) |
|
|
614
|
+
| Feishu/Lark | Not supported via webhook |
|
|
615
|
+
| Slack | Not supported via webhook |
|
|
616
|
+
|
|
617
|
+
```json
|
|
618
|
+
{
|
|
619
|
+
"bot": "wecom-dev",
|
|
620
|
+
"file_path": "/home/user/reports/monthly.pdf",
|
|
621
|
+
"caption": "Monthly Report - June 2025"
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### `send_broadcast`
|
|
626
|
+
|
|
627
|
+
Send the same message to multiple bots simultaneously. Ideal for cross-platform alerts.
|
|
628
|
+
|
|
629
|
+
| Parameter | Type | Required | Description |
|
|
630
|
+
|---|---|---|---|
|
|
631
|
+
| `bots` | string[] | Yes | List of bot names to broadcast to |
|
|
632
|
+
| `type` | string | Yes | Message type |
|
|
633
|
+
| `content` | string | Yes | Message content (supports templates) |
|
|
634
|
+
| `title` | string | No | Message title |
|
|
635
|
+
| `variables` | object | No | Template variables |
|
|
636
|
+
| _(all send_message params)_ | | | Same parameters as send_message |
|
|
637
|
+
|
|
638
|
+
**Example — Emergency alert to all platforms:**
|
|
639
|
+
|
|
640
|
+
```json
|
|
641
|
+
{
|
|
642
|
+
"bots": ["dingtalk-ops", "wecom-dev", "feishu-alert", "slack-engineering"],
|
|
643
|
+
"type": "markdown",
|
|
644
|
+
"content": "## P0 Incident\n**Service:** payment-gateway\n**Impact:** All payments failing\n**Started:** {{time}}\n\n[Status Page](https://status.example.com)",
|
|
645
|
+
"variables": { "time": "2025-06-24 16:30:00" },
|
|
646
|
+
"title": "P0 Alert"
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
**Response:**
|
|
651
|
+
|
|
652
|
+
```json
|
|
653
|
+
{
|
|
654
|
+
"total": 4,
|
|
655
|
+
"success": 3,
|
|
656
|
+
"failed": 1,
|
|
657
|
+
"results": [
|
|
658
|
+
{ "bot": "dingtalk-ops", "success": true, "platform": "dingtalk", "latency_ms": 245 },
|
|
659
|
+
{ "bot": "wecom-dev", "success": true, "platform": "wecom", "latency_ms": 312 },
|
|
660
|
+
{ "bot": "feishu-alert", "success": true, "platform": "feishu", "latency_ms": 189 },
|
|
661
|
+
{ "bot": "slack-engineering", "success": false, "error": "Slack error [403]: action_prohibited" }
|
|
662
|
+
]
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
### `send_batch`
|
|
667
|
+
|
|
668
|
+
Send the same message to multiple targets through one bot. Primarily useful for Telegram (multiple chat IDs).
|
|
669
|
+
|
|
670
|
+
| Parameter | Type | Required | Description |
|
|
671
|
+
|---|---|---|---|
|
|
672
|
+
| `bot` | string | Yes | Bot instance name |
|
|
673
|
+
| `targets` | string[] | Yes | Target IDs (e.g., Telegram chat_ids) |
|
|
674
|
+
| `type` | string | Yes | Message type |
|
|
675
|
+
| `content` | string | Yes | Message content |
|
|
676
|
+
| _(all send_message params)_ | | | Same parameters as send_message |
|
|
677
|
+
|
|
678
|
+
```json
|
|
679
|
+
{
|
|
680
|
+
"bot": "telegram-bot",
|
|
681
|
+
"targets": ["-1001111111", "-1002222222", "-1003333333"],
|
|
682
|
+
"type": "text",
|
|
683
|
+
"content": "Daily standup reminder: 10:00 AM"
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### `list_bots`
|
|
688
|
+
|
|
689
|
+
List all configured bot instances with their platform, status, and queue info.
|
|
690
|
+
|
|
691
|
+
**Parameters:** None
|
|
692
|
+
|
|
693
|
+
**Response:**
|
|
694
|
+
|
|
695
|
+
```json
|
|
696
|
+
{
|
|
697
|
+
"total": 3,
|
|
698
|
+
"bots": [
|
|
699
|
+
{ "name": "dingtalk-ops", "platform": "dingtalk", "enabled": true, "queue": { "queued": 0, "running": 0 } },
|
|
700
|
+
{ "name": "wecom-dev", "platform": "wecom", "enabled": true, "queue": { "queued": 0, "running": 0 } },
|
|
701
|
+
{ "name": "telegram-bot", "platform": "telegram", "enabled": true, "queue": { "queued": 0, "running": 0 } }
|
|
702
|
+
],
|
|
703
|
+
"platforms": ["dingtalk", "wecom", "telegram"]
|
|
704
|
+
}
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### `message_status`
|
|
708
|
+
|
|
709
|
+
Query the audit log for message delivery status.
|
|
710
|
+
|
|
711
|
+
| Parameter | Type | Required | Description |
|
|
712
|
+
|---|---|---|---|
|
|
713
|
+
| `message_id` | string | No | Specific message ID to look up |
|
|
714
|
+
| `audit_id` | string | No | Audit log entry ID |
|
|
715
|
+
| `bot` | string | No | Filter by bot name |
|
|
716
|
+
| `platform` | string | No | Filter by platform |
|
|
717
|
+
| `status` | string | No | Filter: `success` or `failed` |
|
|
718
|
+
| `since` | string | No | ISO timestamp — return entries after this time |
|
|
719
|
+
| `limit` | number | No | Max entries to return (default: 20) |
|
|
720
|
+
|
|
721
|
+
```json
|
|
722
|
+
{
|
|
723
|
+
"bot": "dingtalk-ops",
|
|
724
|
+
"status": "failed",
|
|
725
|
+
"since": "2025-06-24T00:00:00Z",
|
|
726
|
+
"limit": 10
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### `render_template`
|
|
731
|
+
|
|
732
|
+
Preview a Handlebars template rendering without sending. Useful for testing templates.
|
|
733
|
+
|
|
734
|
+
| Parameter | Type | Required | Description |
|
|
735
|
+
|---|---|---|---|
|
|
736
|
+
| `template` | string | Yes | Handlebars template string |
|
|
737
|
+
| `variables` | object | No | Variables to substitute |
|
|
738
|
+
|
|
739
|
+
```json
|
|
740
|
+
{
|
|
741
|
+
"template": "Service {{service}}: {{#if_eq status \"ok\"}}✅ Healthy{{else}}❌ Down{{/if_eq}}\nCPU: {{cpu}}% {{#if_gt cpu 90}}⚠️ CRITICAL{{/if_gt}}\nTime: {{now}}",
|
|
742
|
+
"variables": { "service": "api-gateway", "status": "ok", "cpu": "95" }
|
|
743
|
+
}
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**Response:**
|
|
747
|
+
|
|
748
|
+
```json
|
|
749
|
+
{
|
|
750
|
+
"template": "Service {{service}}: ...",
|
|
751
|
+
"variables_detected": ["service", "status", "cpu", "now"],
|
|
752
|
+
"variables_provided": ["service", "status", "cpu"],
|
|
753
|
+
"rendered": "Service api-gateway: ✅ Healthy\nCPU: 95% ⚠️ CRITICAL\nTime: 2025-06-24 16:30:00",
|
|
754
|
+
"has_expressions": true
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
---
|
|
759
|
+
|
|
760
|
+
## Message Types & Platform Mapping
|
|
761
|
+
|
|
762
|
+
Each message type is automatically translated to the platform's native format:
|
|
763
|
+
|
|
764
|
+
| Type | DingTalk | WeCom | Feishu/Lark | Slack | Discord | Telegram |
|
|
765
|
+
|---|---|---|---|---|---|---|
|
|
766
|
+
| `text` | text msgtype | text msgtype | text msg_type | plain text | content field | sendMessage |
|
|
767
|
+
| `markdown` | markdown msgtype | markdown msgtype | interactive card (markdown element) | Block Kit (mrkdwn section) | embed description | MarkdownV2 / HTML |
|
|
768
|
+
| `link` | link msgtype | news (1 article) | post (rich text with link) | section + button action | embed with URL | text with inline link |
|
|
769
|
+
| `image` | markdown `` fallback | image (base64+md5) | image (image_key) | image block | embed image | sendPhoto |
|
|
770
|
+
| `card` | actionCard (buttons) | template_card | interactive card (buttons) | Block Kit (actions) | embed + link buttons | inline_keyboard |
|
|
771
|
+
| `news` | feedCard | news msgtype (articles) | post (multi-paragraph) | multiple sections + dividers | multiple embeds | concatenated message |
|
|
772
|
+
| `file` | link fallback ↓ | file (media_id) | text fallback ↓ | text fallback ↓ | multipart upload | sendDocument |
|
|
773
|
+
|
|
774
|
+
> ↓ = graceful degradation when the platform doesn't support this type natively.
|
|
775
|
+
|
|
776
|
+
---
|
|
777
|
+
|
|
778
|
+
## Template Engine
|
|
779
|
+
|
|
780
|
+
`botmsg` uses [Handlebars](https://handlebarsjs.com/) as its template engine with `noEscape` mode (no HTML entity escaping, since messages are plain text).
|
|
781
|
+
|
|
782
|
+
### Built-in Helpers
|
|
783
|
+
|
|
784
|
+
| Helper | Syntax | Example | Output |
|
|
785
|
+
|---|---|---|---|
|
|
786
|
+
| **date** | `{{date value}}` | `{{date "2025-01-15T14:30:00Z"}}` | `2025-01-15 14:30:00` |
|
|
787
|
+
| date (ISO) | `{{date value "iso"}}` | `{{date "2025-01-15T14:30:00Z" "iso"}}` | `2025-01-15T14:30:00.000Z` |
|
|
788
|
+
| date (locale) | `{{date value "locale"}}` | `{{date "2025-01-15T14:30:00Z" "locale"}}` | `2025/1/15 14:30:00` |
|
|
789
|
+
| **uppercase** | `{{uppercase value}}` | `{{uppercase "hello"}}` | `HELLO` |
|
|
790
|
+
| **lowercase** | `{{lowercase value}}` | `{{lowercase "HELLO"}}` | `hello` |
|
|
791
|
+
| **capitalize** | `{{capitalize value}}` | `{{capitalize "hello world"}}` | `Hello world` |
|
|
792
|
+
| **truncate** | `{{truncate value len}}` | `{{truncate "Long text here" 8}}` | `Long tex...` |
|
|
793
|
+
| **json** | `{{json value}}` | `{{json data}}` | `{"key":"value"}` |
|
|
794
|
+
| **now** | `{{now}}` | `{{now}}` | `2025-06-24 16:30:00` |
|
|
795
|
+
| now (ISO) | `{{now "iso"}}` | `{{now "iso"}}` | `2025-06-24T16:30:00.000Z` |
|
|
796
|
+
| now (timestamp) | `{{now "timestamp"}}` | `{{now "timestamp"}}` | `1750783800` |
|
|
797
|
+
| **join** | `{{join arr sep}}` | `{{join items ", "}}` | `a, b, c` |
|
|
798
|
+
|
|
799
|
+
### Conditional Logic
|
|
800
|
+
|
|
801
|
+
```handlebars
|
|
802
|
+
{{#if_eq status "ok"}}
|
|
803
|
+
✅ Service is healthy
|
|
804
|
+
{{else}}
|
|
805
|
+
❌ Service is DOWN: {{error}}
|
|
806
|
+
{{/if_eq}}
|
|
807
|
+
|
|
808
|
+
{{#if_gt cpu 90}}
|
|
809
|
+
⚠️ CPU critical: {{cpu}}%
|
|
810
|
+
{{else}}
|
|
811
|
+
CPU normal: {{cpu}}%
|
|
812
|
+
{{/if_gt}}
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### Partials
|
|
816
|
+
|
|
817
|
+
Register reusable template fragments (via code, not MCP tools):
|
|
818
|
+
|
|
819
|
+
```handlebars
|
|
820
|
+
{{> header}}
|
|
821
|
+
Service: {{service}}
|
|
822
|
+
Status: {{status}}
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
---
|
|
826
|
+
|
|
827
|
+
## Rate Limiting & Retry
|
|
828
|
+
|
|
829
|
+
Each bot has an independent rate limiter using [Bottleneck](https://github.com/SGrondin/bottleneck), configured to stay safely below each platform's API limits:
|
|
830
|
+
|
|
831
|
+
| Platform | API Limit | botmsg Default | Strategy |
|
|
832
|
+
|---|---|---|---|
|
|
833
|
+
| DingTalk | 20 msg/min | 18 msg/min, 3s spacing | Token bucket |
|
|
834
|
+
| WeCom | 20 msg/min | 18 msg/min, 3s spacing | Token bucket |
|
|
835
|
+
| Feishu | 100 msg/min, 5/sec | 90 msg/min, 250ms spacing | Token bucket |
|
|
836
|
+
| Lark | 100 msg/min, 5/sec | 90 msg/min, 250ms spacing | Token bucket |
|
|
837
|
+
| Slack | ~1 msg/sec | 55 msg/min, 1.1s spacing | Fixed interval |
|
|
838
|
+
| Discord | 5 msg/2sec | 4 msg/2sec, 500ms spacing | Token bucket |
|
|
839
|
+
| Telegram | 30 msg/sec | 25 msg/sec, 40ms spacing | Token bucket |
|
|
840
|
+
|
|
841
|
+
**Retry behavior:** On HTTP 429 or 5xx errors, messages are retried with exponential backoff: 1s → 2s → 4s → 8s → 16s (configurable max via `BOTMSG_MAX_RETRIES`).
|
|
842
|
+
|
|
843
|
+
**High water mark:** If the queue exceeds the platform-specific limit (50-200 pending messages), oldest messages are dropped to prevent memory exhaustion.
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
847
|
+
## Audit Logging
|
|
848
|
+
|
|
849
|
+
Every message send attempt is recorded:
|
|
850
|
+
|
|
851
|
+
```json
|
|
852
|
+
{
|
|
853
|
+
"id": "msg_m1abc_2d3efg",
|
|
854
|
+
"messageId": "12345",
|
|
855
|
+
"bot": "dingtalk-ops",
|
|
856
|
+
"platform": "dingtalk",
|
|
857
|
+
"type": "markdown",
|
|
858
|
+
"contentHash": "## Deploy Alert\nService **user-ap...",
|
|
859
|
+
"status": "success",
|
|
860
|
+
"timestamp": "2025-06-24T16:30:00.000Z",
|
|
861
|
+
"latencyMs": 245,
|
|
862
|
+
"error": null
|
|
863
|
+
}
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
**Storage:**
|
|
867
|
+
|
|
868
|
+
- **In-memory:** Ring buffer holding the last 1,000 entries (always active)
|
|
869
|
+
- **File persistence:** Set `BOTMSG_AUDIT_LOG=/path/to/audit.jsonl` for JSONL file output
|
|
870
|
+
- **Query:** Use the `message_status` tool to search by bot, platform, status, time range
|
|
871
|
+
|
|
872
|
+
---
|
|
873
|
+
|
|
874
|
+
## Dry Run Mode
|
|
875
|
+
|
|
876
|
+
Set `BOTMSG_DRY_RUN=true` to preview message payloads without actually sending. Perfect for testing configurations and templates.
|
|
877
|
+
|
|
878
|
+
```json
|
|
879
|
+
{
|
|
880
|
+
"mcpServers": {
|
|
881
|
+
"botmsg": {
|
|
882
|
+
"command": "npx",
|
|
883
|
+
"args": ["-y", "botmsg"],
|
|
884
|
+
"env": {
|
|
885
|
+
"BOTMSG_DINGTALK_OPS_WEBHOOK": "https://oapi.dingtalk.com/robot/send?access_token=xxx",
|
|
886
|
+
"BOTMSG_DRY_RUN": "true"
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
In dry run mode, `send_message` returns the rendered content and the full platform-specific payload:
|
|
894
|
+
|
|
895
|
+
```json
|
|
896
|
+
{
|
|
897
|
+
"dry_run": true,
|
|
898
|
+
"bot": "dingtalk-ops",
|
|
899
|
+
"platform": "dingtalk",
|
|
900
|
+
"rendered_content": "Hello Team, deploy completed at 14:30",
|
|
901
|
+
"payload": {
|
|
902
|
+
"msgtype": "text",
|
|
903
|
+
"text": { "content": "Hello Team, deploy completed at 14:30" }
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## Error Handling
|
|
911
|
+
|
|
912
|
+
`botmsg` returns structured errors to the MCP client:
|
|
913
|
+
|
|
914
|
+
```json
|
|
915
|
+
{
|
|
916
|
+
"content": [{ "type": "text", "text": "Error: [PLATFORM_ERROR] [dingtalk] DingTalk error [310000]: keywords not in content" }],
|
|
917
|
+
"isError": true
|
|
918
|
+
}
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
**Common error codes:**
|
|
922
|
+
|
|
923
|
+
| Error | Cause | Solution |
|
|
924
|
+
|---|---|---|
|
|
925
|
+
| `BOT_NOT_FOUND` | Bot name not in config | Check `list_bots` for available names |
|
|
926
|
+
| `VALIDATION_ERROR` | Invalid parameters | Check tool parameter types and required fields |
|
|
927
|
+
| `PLATFORM_ERROR` | Platform API returned error | Check webhook URL, tokens, and security settings |
|
|
928
|
+
| `RATE_LIMIT_ERROR` | Exceeded rate limit | Messages auto-retry; reduce send frequency |
|
|
929
|
+
| `CONFIG_ERROR` | Config file parse error | Validate YAML/JSON syntax |
|
|
930
|
+
|
|
931
|
+
---
|
|
932
|
+
|
|
933
|
+
## Development
|
|
934
|
+
|
|
935
|
+
```bash
|
|
936
|
+
# Clone and install
|
|
937
|
+
git clone https://github.com/user/botmsg.git
|
|
938
|
+
cd botmsg
|
|
939
|
+
npm install
|
|
940
|
+
|
|
941
|
+
# Build (tsup + esbuild)
|
|
942
|
+
npm run build
|
|
943
|
+
|
|
944
|
+
# Run tests (vitest)
|
|
945
|
+
npm test
|
|
946
|
+
|
|
947
|
+
# Development mode (tsx hot-reload)
|
|
948
|
+
npm run dev
|
|
949
|
+
|
|
950
|
+
# Test MCP server locally
|
|
951
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/index.js
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
---
|
|
955
|
+
|
|
956
|
+
## Troubleshooting
|
|
957
|
+
|
|
958
|
+
**"npx: command not found"**
|
|
959
|
+
Ensure Node.js >= 18 is installed: `node --version`
|
|
960
|
+
|
|
961
|
+
**"Bot not found" errors**
|
|
962
|
+
Run the `list_bots` tool to see all configured bot names. Names follow the pattern `{platform}-{instance}`.
|
|
963
|
+
|
|
964
|
+
**Messages not delivered**
|
|
965
|
+
1. Check webhook URL is correct and not expired
|
|
966
|
+
2. For DingTalk: verify security mode matches your robot settings (keyword vs sign)
|
|
967
|
+
3. For signed webhooks: ensure system clock is accurate (within 1 hour)
|
|
968
|
+
4. Use `BOTMSG_DRY_RUN=true` to inspect payloads without sending
|
|
969
|
+
5. Check `message_status` tool for recent failures
|
|
970
|
+
|
|
971
|
+
**Rate limit errors (429)**
|
|
972
|
+
botmsg auto-retries with exponential backoff. If persistent, reduce send frequency or split across multiple bot instances.
|
|
973
|
+
|
|
974
|
+
**Windows: "npx not found" in MCP config**
|
|
975
|
+
Use `cmd` wrapper:
|
|
976
|
+
```json
|
|
977
|
+
{ "command": "cmd", "args": ["/c", "npx", "-y", "botmsg"] }
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
---
|
|
981
|
+
|
|
982
|
+
## License
|
|
983
|
+
|
|
984
|
+
MIT
|