内容
# mcp-channel-mattermost
一个 [Claude Code 通道](https://code.claude.com/docs/en/channels-reference),将 Mattermost 机器人桥接到您的 Claude Code 会话中。向机器人发送私信、在频道中提及机器人以及在监视的频道中发布帖子,都会以 `<channel source="mattermost" …>` 事件的形式转发给 Claude;Claude 可以通过 `reply` 工具回复,而工具使用审批可以中继到 Mattermost,这样您可以在手机上批准或拒绝它们。
已针对 Mattermost **10.12.4**(团队版)进行测试。
## 功能
- 将输入帖子转发给 Claude:
- 给机器人的私信
- 在机器人加入的任何频道中 `@bot` 提及
- **线程跟进**:在机器人已经发布过的线程中回复会自动转发 - 用户不必再次 `@bot`。通过状态文件跟踪在频道服务器重启后仍然持续。
- 在通过 `MATTERMOST_LISTEN_CHANNELS` 列出的频道中(警报、操作室)的每个帖子
- 双向:`reply` MCP 工具回复到频道/私信,可选 `root_id` 用于线程
- 权限中继:工具使用提示(`Bash`、`Write`、`Edit` 等)会私信给允许的用户;回复 `yes <id>` / `no <id>` 以批准或拒绝
- 发送者控制,两种路径:
- 通过 `MATTERMOST_ALLOWED_USERS` 的静态允许列表(用户名或 26 个字符的 ID)
- 配对回退:未知私信用户会收到 6 位字符代码;操作员将其粘贴到 Claude Code 中,Claude 调用 `confirm_pairing`,用户被添加到持久化的允许列表中
- 自动重新连接的 WebSocket 消费者,具有指数级退避
## 要求
- 一个 Mattermost 服务器(此存储库包含用于 10.12.4 的 docker-compose)
- 一个具有个人访问令牌的机器人账户(参见 [设置机器人](#设置机器人))
- Claude Code **v2.1.81+** 用于权限中继;否则 v2.1.80+
- 以下之一:
- [Bun](https://bun.sh) ≥ 1.1(与官方通道示例匹配)
- Node.js ≥ 18 with [`tsx`](https://www.npmjs.com/package/tsx)
## 安装为插件
此存储库兼作 Claude Code 插件 - `.claude-plugin/plugin.json`、`.claude-plugin/marketplace.json` 和 `.mcp.json` 已就位。添加市场后,安装:
```text
/plugin marketplace add henkvanmaanen/mcp-channel-mattermost
/plugin install mattermost@mcp-channel-mattermost
```
(或者,对于本地开发,将市场指向克隆:`/plugin marketplace add /path/to/mcp-channel-mattermost`。)
安装后,配置插件:
```text
/mattermost:configure
```
`mattermost:configure` 技能引导您创建机器人、生成令牌、选择允许列表并导出 Claude Code 在启动时读取的环境变量。然后启用通道:
```sh
# 在研究预览期间,自定义通道需要开发标志:
claude --dangerously-load-development-channels plugin:mattermost@mcp-channel-mattermost
```
一旦发布到官方市场,您可以删除开发标志,只需使用 `--channels plugin:mattermost@mcp-channel-mattermost` 启用它。
## 快速入门(针对真正的 Mattermost)
### 1. 设置机器人
在 Mattermost 中作为系统管理员:
1. **系统控制台 → 集成 → 机器人账户 → 启用机器人账户创建:true**
2. **系统控制台 → 集成 → 个人访问令牌 → 启用:true**
3. **集成 → 机器人账户 → 添加机器人账户**,给予它一个用户名(例如 `claude`)
4. 创建后,保存机器人的用户 ID 和个人访问令牌
5. 将机器人添加到团队和您希望它监听的频道(`MATTERMOST_LISTEN_CHANNELS` 频道和用户将 `@claude` 的任何频道)
### 2. 安装
```sh
git clone https://github.com/henkvanmaanen/mcp-channel-mattermost
cd mcp-channel-mattermost
bun install # 或:npm install
```
### 3. 配置
复制 `.env.example` 到 `.env` 并填写,或在您的 shell 中设置变量。无论您怎么做,通道服务器都会从其自己的进程环境中读取它们(Claude Code 从 `.mcp.json` 的 `env` 块中传递)。
| 变量 | 必需 | 描述 |
| --- | --- | --- |
| `MATTERMOST_URL` | 是 | 基本 URL,没有尾随 `/api/v4` |
| `MATTERMOST_TOKEN` | 是 | 机器人个人访问令牌 |
| `MATTERMOST_TEAM` | 使用频道名称时 | 团队名称(URL 斜杠) |
| `MATTERMOST_ALLOWED_USERS` | 推荐 | 以逗号分隔的用户名或 26 个字符的用户 ID |
| `MATTERMOST_LISTEN_CHANNELS` | 可选 | 要转发每个帖子的以逗号分隔的频道名称或 ID |
| `MATTERMOST_STATE_FILE` | 可选 | 持久化配对允许列表的位置(默认 `~/.mcp-channel-mattermost/state.json`) |
### 4. 在 Claude Code 中注册
项目级(`.mcp.json` 在您的项目根目录)- 参见 `.mcp.json.example`:
```json
{
"mcpServers": {
"mattermost": {
"command": "bun",
"args": ["./mattermost.ts"],
"env": {
"MATTERMOST_URL": "https://mattermost.example.com",
"MATTERMOST_TOKEN": "…",
"MATTERMOST_TEAM": "myteam",
"MATTERMOST_ALLOWED_USERS": "alice,bob",
"MATTERMOST_LISTEN_CHANNELS": "ops-alerts"
}
}
}
}
```
要使用 Node 而不是 Bun,请使用 `"command": "npx", "args": ["tsx", "./mattermost.ts"]`。
### 5. 运行
在研究预览期间,通道由 Anthropic 挑选的允许列表控制,因此在测试您自己的通道时使用开发标志:
```sh
claude --dangerously-load-development-channels server:mattermost
```
从允许列表用户向机器人发送私信 - 消息会作为 `<channel source="mattermost" …>` 出现在您的 Claude Code 会话中。
## 使用 docker-compose 进行本地开发
包括一个完全脚本化的 Mattermost 10.12.4 设置。
```sh
npm install
npm run mm:up # 在 http://localhost:8065 启动 postgres + Mattermost
npm run mm:setup # 创建 admin、team、bot、alice;写入 .env.local
npm run smoke # 端到端集成测试(不需要 claude)
npm run cli-test # 启动真正的 claude CLI;验证注册 + 回复
```
设置脚本是幂等的。它写入一个 `.env.local`,烟雾测试会使用它;您也可以将生成的 `MATTERMOST_TOKEN` 指向同一个 Mattermost,以便 Claude Code 使用。
要关闭:
```sh
npm run mm:down # 停止容器并删除卷
```
## 针对真正的 claude CLI 进行测试
三个脚本使用实际的 `claude` CLI 测试通道:
```sh
npm run cli-test # 无头:注册 + 输出回复工具(4/4)
npm run cli-test:tmux # 交互式(通过 tmux):完整输入桥接(✓)
npm run cli-test:inbound # 诊断:记录 `--print` 限制
```
### 无头模式 (`--print`)
`cli-test` 运行 claude 时带有 `--print --input-format stream-json` 并验证无头合约:
1. claude 将 `mattermost` 注册为连接的 MCP 服务器
2. claude 广告 `mcp__mattermost__reply` 和 `mcp__mattermost__confirm_pairing`
3. 当 alice 在 `#ops-alerts` 中发布时,通道服务器发出 `notifications/claude/channel`
4. claude 可以调用回复工具并且消息返回到 Mattermost
`--print` 模式不执行的操作:使输入 `<channel source="mattermost" …>` 标签显示给模型。您可以使用 `cli-test:inbound` 证明这一点,它要求 claude 将其上下文中的每个通道标签转储到文件中。通道服务器的调试日志显示它发出了通知,但 claude 的转储文件显示
`NO_CHANNEL_TAGS_FOUND`。通道通知在当前 Claude Code(v2.1.132)中仅限交互模式。
### 交互模式(真正的聊天桥)
`cli-test:tmux` 在其自己的 tmux 会话(使用专用的 tmux 套接字,因此它永远不会影响您的其他会话)中启动 claude,通过信任和开发通道提示发送按键,发布 Mattermost 消息,并
断言机器人的回复返回到频道 - 验证完整的生产流程:
```
alice posts → channel server WS → notifications/claude/channel
→ Claude sees <channel> tag → reply tool → Mattermost
```
手动交互测试(无脚本):
```sh
# 项目根目录,带有指向此服务器的 .mcp.json
claude --dangerously-load-development-channels server:mattermost
```
从允许列表用户向机器人发送私信,或在允许列表频道中发布。Claude 打印输入的 `<channel>` 标签并通过回复工具响应。
## 通知格式
每个转发的帖子都作为以下内容到达 Claude 的上下文:
```
<channel
source="mattermost"
channel_id="..." 26 个字符的 Mattermost 频道 ID
channel_type="D|O|P|G" D=直接,O=公共,P=私有,G=群组私信
channel_name="..." 斜杠(或 DMs 为 "")
post_id="..." 此帖子的 ID
root_id="..." 线程根(= post_id 如果不在线程中)
user_id="..." 发送者的 26 个字符的用户 ID
username="..." 发送者的用户名(无 @)
>
…消息正文…
</channel>
```
标签属性键必须是标识符 - 字母、数字、下划线。短线
被 Claude Code 框架剥离,因此服务器避免使用它们。
## 长期使用:子代理委托
如果您想将此作为 24/7 Mattermost 机器人运行,主 Claude 会话的
上下文将累积每个通道事件并开始感到迟钝 - 所以
通道的 `instructions` 告诉 Claude **将每个输入消息
委托给子代理通过 Task 工具**。子代理有自己的全新上下文,
调用 `read_thread` 获取先前消息,构建回复,调用 `reply` 来
发布它,然后退出。主会话只看到一行“委托,已完成”
每条消息的跟踪 - 上下文增长保持有界,因此 `/compact`(或只是
耐心)让您长期运行。
您不需要做任何事情来选择加入 - Claude 在启动时读取委托
指令并遵循它。配对代码(`pair ABC123`)和
权限裁决(`yes <id>` / `no <id>`)不会被委托;它们
在主会话中处理(或对于裁决,由通道服务器在 Claude 看到它们之前处理)。
要“关闭”Mattermost 对话,以便该线程中的未来回复
不再自动转发而无需提及 @,请要求 Claude 调用 `clear_thread_state` 并带有
`root_id`。线程变为惰性,直到有人再次 @ 提及机器人。
## 工具
### `reply`
```ts
reply({ channel_id, message?, root_id?, attachments? })
```
发布消息回 Mattermost。要在线程中回复,请传递 `root_id`(如果非空,请使用输入标签中的 `root_id`,否则使用 `post_id`)。
要附加文件,请将 `attachments` 作为 `{ path, filename? }` 数组传递:
机器人读取每个本地文件,将其上传到 Mattermost,并将
生成的 file IDs 附加到帖子。`message` 或 `attachments` 必须是非空的。Mattermost 限制单个帖子最多 10 个附件。
```ts
reply({
channel_id: '...',
message: '截图已附上',
attachments: [{ path: '/tmp/screenshot.png' }],
})
```
### `read_thread`
```ts
read_thread({ root_id })
```
返回 Mattermost 线程的完整消息历史,按时间顺序格式化为
`@user (timestamp): message` 行。每个输入消息的 spawned 子代理
首先调用此方法以获取对话上下文。
### `clear_thread_state`
```ts
clear_thread_state({ root_id })
```
从通道服务器的跟踪线程集中删除线程 root_id,以便
该线程中的后续回复不再自动转发而无需 @ 提及。
持久化状态文件已更新。
### `confirm_pairing`
```ts
confirm_pairing({ code })
```
将_pending 配对代码背后的用户添加到持久化允许列表中。操作员
将 6 位字符代码输入到 Claude Code 中(例如 `pair ABC123`),Claude
看到模式在其指令中并调用此工具。代码在 10 分钟后过期。
## 权限中继
当您使用已注册的此通道启动会话时,Claude Code 将
工具使用审批提示(`Bash`、`Write`、`Edit` 等)转发到您的服务器。服务器
私信每个已批准的用户一条消息,如下所示:
> Claude 想要使用 **Bash**:列出当前目录中的文件
>
> ```
> {"command":"ls"}
> ```
>
> 回复 `yes abcde` 或 `no abcde`。
用 `yes <id>` 或 `no <id>` 回复,工具调用继续或被拒绝。
本地终端对话框在同一时间保持打开 - 哪一方先回答
获胜。
项目信任和 MCP 服务器同意对话框不被中继;只有工具使用
审批。
## 配对流程
1. 未知用户向机器人发送私信。
2. 机器人私信回复:`您的配对代码是 XYZ123。 与操作员共享。`
3. 用户与运行 Claude Code 的人员共享代码。
4. 操作员在 Claude Code 会话中粘贴 `pair XYZ123`。
5. Claude 读取其指令,看到模式,调用 `confirm_pairing({code})`。
6. 用户的 `user_id` 被追加到 `~/.mcp-channel-mattermost/state.json` 并私信确认。
持久化允许列表是 `MATTERMOST_ALLOWED_USERS` 的累加。要撤销
临时配对用户,请编辑(或删除)状态文件并重启通道。
## 安全注意事项
- 使用 **机器人账户**,而非个人令牌。机器人有清晰的审计轨迹。
- 始终设置 `MATTERMOST_ALLOWED_USERS`(或依赖配对)。无门控的通道是 Prompt 注入向量 - 任何可以向机器人发送私信的人都能够将文本置于 Claude 前面。
- 配对 TTL 为 10 分钟,代码为一次性使用。
- 监视频道转发和 `@mention` 转发仍然由发送者允许列表控制 - 如果 `ops-alerts` 中的某人不被允许,其帖子将被丢弃。
- 默认情况下,状态文件写入 `$HOME/.mcp-channel-mattermost/`。如果您运行多个会话或需要系统路径,请使用 `MATTERMOST_STATE_FILE` 覆盖。
## 故障排除
- **`/mcp` 显示通道为“无法连接”**:服务器崩溃。检查 `~/.claude/debug/<session-id>.txt` 获取 stderr 跟踪;常见原因是缺少环境变量或无法访问的 `MATTERMOST_URL`。
- **在频道中发布时没有事件到达**:机器人必须是该频道的成员。帖子的 WebSocket 事件仅传递给频道成员。
- **机器人不响应私信**:确保私信已启用(`系统控制台 → 站点配置 → 帖子 → 启用私信:服务器上的任何人`)并且机器人位于与发送者相同的团队中。
- **权限私信从未到达**:需要 Claude Code v2.1.81+ 进行中继;较旧版本会静默忽略 `claude/channel/permission` 能力。
- **`bot create failed: api.bot.create_disabled`**:启用机器人账户创建(`MM_SERVICESETTINGS_ENABLEBOTACCOUNTCREATION=true` 或通过系统控制台)。
## 工作原理
```
stdio (MCP)
Claude Code <─────────────────────> mattermost.ts
│
│ REST (POST /api/v4/posts, …)
│ WS (/api/v4/websocket)
▼
Mattermost
```
`mattermost.ts` 是一个独立的 MCP 服务器。启动时,它:
1. 通过机器人个人访问令牌验证 Mattermost
2. 解析配置的允许列表用户名和监视的频道名称为 ID
3. 从 `MATTERMOST_STATE_FILE` 加载持久化的配对允许列表
4. 注册两个 MCP 工具(`reply`、`confirm_pairing`)和一个通知处理程序(`notifications/claude/channel/permission_request`)
5. 连接到 `/api/v4/websocket` 并使用相同的令牌验证
6. 隐含订阅 `posted` 事件,解析每个帖子,并:
- 丢弃机器人自己发送的帖子
- 丢弃机器人未被 @ 提及的帖子(除私信或监视频道)
- 丢弃不在任一允许列表中的发送者(如果他们私信机器人,则发送配对代码)
- 解析 `yes/no <id>` 裁决并将它们转发为 `notifications/claude/channel/permission`
- 将其余部分转发为 `notifications/claude/channel`
## 项目布局
```
.
├── .claude-plugin/
│ ├── plugin.json # 插件清单(名称、版本、关键词)
│ └── marketplace.json # 指向此存储库的单一插件市场
├── .mcp.json # 插件运行时:通过 ${CLAUDE_PLUGIN_ROOT} 启动 mattermost.ts
├── mattermost.ts # 通道服务器(单文件)
├── package.json # 二进制:mattermost.ts;启动:bun install && bun mattermost.ts
├── tsconfig.json
├── skills/
│ └── configure/SKILL.md # /mattermost:configure 帮助程序
├── docker-compose.dev.yml # 本地 Mattermost 10.12.4 + postgres
├── scripts/
│ ├── setup-mattermost.sh # 通过 API 启动 admin/team/bot/user
│ ├── smoke-test.ts # 模拟客户端驱动服务器端到端
│ ├── cli-test.sh # 启动真正的 claude CLI(无头);注册 + 回复
│ ├── cli-test-tmux.sh # 启动真正的 claude CLI(交互式 via tmux);完整桥接
│ └── cli-test-inbound.sh # 诊断 -print 限制
├── .env.example
└── .mcp.json.example # 独立安装模板(当不作为插件使用时)
```
## 许可证
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器