关于 WhatsMCP
WhatsMCP 是托管式 MCP 服务,让 AI Agent 使用已关联的普通 WhatsApp 账号。它通过远程 HTTP 端点提供消息和账号管理工具,并支持通过 SIP 转接通话。
主要功能
- 01读取和发送消息
- 02管理联系人和群组
- 03回应和编辑消息
- 04通过 webhook 接收消息
- 05获取消息附件
- 06通过 SIP 转接 WhatsApp 通话
适用场景
- 01让 Agent 查看并回复 WhatsApp 聊天
- 02通过 Agent 管理联系人和群组
- 03将收到的消息发送到 webhook
- 04将 WhatsApp 通话接入座机或 PBX
MCP 相关
WhatsMCP 通过托管的 Streamable HTTP 端点向 MCP 客户端提供 WhatsApp 账号和消息工具。客户端可使用 OAuth 或 API 密钥进行身份验证。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://api.whatsmcp.com/mcpclaude mcp add --transport http whatsmcp-715771 https://api.whatsmcp.com/mcp{"mcpServers":{"whatsmcp-715771":{"type":"http","url":"https://api.whatsmcp.com/mcp"}}}在 Cursor 中打开{"servers":{"whatsmcp-715771":{"type":"http","url":"https://api.whatsmcp.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"whatsmcp-715771":{"type":"http","url":"https://api.whatsmcp.com/mcp"}}}{"mcpServers":{"whatsmcp-715771":{"serverUrl":"https://api.whatsmcp.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
WhatsMCP
让你的 Agent 拥有一个真正的 WhatsApp 账号。
一个托管式Model Context Protocol 服务。
只需关联一次号码,然后让任意 MCP 客户端连接到一个 HTTPS 端点——无需 SDK、
无需安装任何内容,也无需在本地运行。
快速开始 · 连接客户端 · 工具 · 轮询 · Webhook · SIP 中继 · 安全性
你的 Agent 可以读取聊天记录、回复消息、在通讯录中查找联系人、对消息作出回应并编辑消息、管理群组、拉黑和解除拉黑联系人、获取附件,还能通过 Webhook 接收收到的消息。同一个已关联号码也可以接入 SIP 中继,这样 WhatsApp 来电就会转接到座机、软电话或 PBX,而你的分机也能以该号码拨打 WhatsApp 电话。请参阅通过 SIP 通话。
无需安装任何内容,也无需在本地运行——这是一个通过 Streamable HTTP 提供的远程 MCP 服务。你的客户端连接到 https://api.whatsmcp.com/mcp,并通过 OAuth 登录,或提供 API 密钥。
这不是 WhatsApp Business API。 无需使用模板,没有 24 小时会话窗口,没有消息审批,也没有按对话计费。你只需通过手机扫描二维码关联一个普通 WhatsApp 账号——就像使用 WhatsApp Web 一样——然后 Agent 就可以将其用作关联设备。
目录
- 快速开始
- 注册
- 关联 WhatsApp 号码
- 创建 API 密钥
- 连接客户端
- 工具
- 联系人
- 读取收到的消息
- Webhook
- 发送消息
- 群组和频道
- 通过 SIP 通话
- 套餐和限制
- 拒绝和错误处理
- 安全模型
- 状态和许可证
- 链接
快速开始
1. Create a workspace → https://console.whatsmcp.com/register
2. Link a WhatsApp number → Console → Pair device (scan the QR with your phone)
3. Give your client → https://api.whatsmcp.com/mcp
…and sign in when it asks. No key to paste.
对于 Claude Code,只需运行两条命令:
claude mcp add --transport http wamcp https://api.whatsmcp.com/mcp
claude mcp login wamcp
然后向你的 Agent 提问:“列出我的 WhatsApp 账号,并显示最近几条消息。”
无法登录的客户端——curl、CI 或任何不支持 OAuth 的客户端——可以改用请求头中的密钥:生成一个密钥,然后参阅连接客户端。
注册
注册可自行完成且免费——无需信用卡,也无需销售人员联系。
| 创建账户 | https://console.whatsmcp.com/register |
| 登录 | https://console.whatsmcp.com/login |
| 产品网站 | https://whatsmcp.com |
填写姓名和电子邮箱地址。我们会发送确认链接;打开链接后即可设置密码。确认后会为你创建免费套餐的工作区(租户),并进入简短的设置向导,引导你完成将基础账户变成可用集成的三个步骤:关联号码、创建密钥,以及——可选地——将Webhook指向你的端点。向导会根据你实际完成的操作来显示,而不是一个供你勾选的清单,因此设置完成后它会消失;如果你取消关联所有内容,它会再次出现。
所有内容都在控制台中:
| 控制台页面 | 用途 |
|---|---|
| 设备列表 | 所有关联的号码及其连接状态 |
| 配对设备 | 通过二维码关联新的 WhatsApp 号码 |
| API 密钥 | 创建和撤销密钥;复制粘贴连接示例 |
| 连接 | 你通过 OAuth 登录的客户端,以及每个客户端对应的撤销按钮 |
| Webhook | 入站投递端点及其近期尝试记录 |
| 用量 | 相对于套餐上限已发送的消息 |
| SIP | 为每个号码将通话接入托管 SIP 线路或你自己的 PBX |
| 帮助 | 你的工作区的连接详情,以及套餐包含哪些工具 |
控制台中每个账户下都有各自的号码页面(消息、联系人、通话、SIP)。
关联 WhatsApp 号码
WhatsMCP 以关联设备的方式连接,与 WhatsApp Web 使用相同的机制。你的手机仍是主设备,之后可以一直放在口袋里。
从控制台操作:打开配对设备,然后在手机上依次前往WhatsApp → 设置 → 已关联设备 → 关联设备并扫描二维码。

二维码大约每 20 秒更新一次,页面也会自动刷新,因此不会出现二维码过期而无法扫描的情况。下方的步骤指示器会跟踪整个过程:手机接受二维码(已扫描),设备登录并拉取历史记录(同步中),随后号码才会变为就绪状态。
从 Agent 操作,使用 wa_pair_account 工具:
// 1. start pairing — returns a QR as a base64 PNG for the user to scan
wa_pair_account()
→ { "pair_id": "…", "state": "qr", "qr_png_base64": "iVBORw0…", "instructions": "…" }
// 2. the code rotates about every 20 seconds — poll for the current one
wa_pair_status({ "pair_id": "…" })
→ { "state": "qr", "qr_png_base64": "…" } // show the new image
→ { "state": "paired", "instructions": "Linked. …" } // done
当 state 为 paired 后,号码会显示在 wa_list_accounts 中,并可供使用。wa_unpair_account 会断开该号码的连接。
创建 API 密钥
**可选。**能够通过 OAuth 登录的客户端不需要密钥——请跳至连接客户端。密钥适用于 curl、CI,以及无法使用 OAuth 的客户端。
控制台 → API 密钥 → 创建密钥。
密钥的格式为 wamcp_live_XXXXXXXXXXXX_…,并且只会显示一次——我们只存储哈希,因此密钥丢失后只能替换,无法找回。为每个客户端或每个环境创建一个密钥,并分别撤销。
密钥就是工作区。每个工具都限定在该工作区内:无需传入租户参数,也无法通过一个工作区访问另一个工作区的消息。
连接客户端
任何支持 Streamable HTTP 的 MCP 客户端都可以使用。这里只有一个端点:
| 端点 | https://api.whatsmcp.com/mcp |
有两种方式可以向它证明你的身份。
OAuth — 推荐方式,也是下面列出的每个客户端默认采用的方式。 客户端会读取服务自身的元数据、注册自身,并将你带到控制台进行批准。无需在任何地方粘贴内容:不会创建密钥,也不会将密钥存储在配置文件中;你可以在不影响其他客户端的情况下,撤销单个客户端的访问权限,前往 控制台 → 连接。
API 密钥 — Authorization: Bearer <your key>;对于将 Authorization 保留给自行管理的令牌的客户端,请使用 x-api-key: <your key>。可将其用于 curl、CI,以及不支持 OAuth 的客户端。请参阅创建 API 密钥。
Claude Code
claude mcp add --transport http wamcp https://api.whatsmcp.com/mcp
然后在 Claude Code 中运行 /mcp,选择 Authenticate,并在打开的浏览器窗口中登录。也可以在命令行中运行 claude mcp login wamcp,完成相同操作。之后运行 claude mcp list,应该会看到 wamcp 已连接。
若改用密钥,则无需登录步骤:
claude mcp add --transport http wamcp https://api.whatsmcp.com/mcp \
--header "Authorization: Bearer YOUR_KEY"
Claude Desktop 和 claude.ai
打开 设置 → 连接器 → 添加自定义连接器,将端点填入 URL 字段,将 身份验证 保持为 OAuth,并在 Claude 提示时登录。对话框会自动发现授权流程。
添加连接器时,身份验证类型即已固定。 使用请求头或 API 密钥创建的连接器之后不会自行切换为 OAuth — 请删除该连接器并重新添加。
若要在此处改用密钥,请将 身份验证 设为 无,并在 其他请求标头 下添加一项:
| 标头名称 | x-api-key |
| 值 | YOUR_KEY |
单独粘贴密钥 — 前面不要加 Bearer 。对话框不提供 Authorization:它留给 Claude 自行管理的 OAuth 令牌使用。标头值只会存储一次,之后不再显示,因此如果连接器无法连接,请替换标头,而不要尝试读回密钥 — 从外部看,错误的密钥和缺少密钥没有区别。
如果你选择编辑配置文件,而不是使用对话框,则没有此限制:
{
"mcpServers": {
"wamcp": {
"type": "http",
"url": "https://api.whatsmcp.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_KEY"
}
}
}
}
ChatGPT
在 设置 → 安全和登录 下启用 开发者模式(是否可用取决于你的 ChatGPT 计划),然后前往 插件,按 +,并填入端点。
这里只能使用 OAuth。 ChatGPT 无法向 MCP 服务提供自定义 API 密钥,因此本页面中的密钥方式不适用于它 — 没有可用于填写密钥的标头字段。登录流程就是全部配置。
Codex
codex mcp add wamcp --url https://api.whatsmcp.com/mcp
codex mcp login wamcp
也可以直接将同一服务写入 ~/.codex/config.toml。auth 默认值为 "oauth":
[mcp_servers.wamcp]
url = "https://api.whatsmcp.com/mcp"
auth = "oauth"
若要改用密钥,请将密钥保存在环境中,而不是文件里:
[mcp_servers.wamcp]
url = "https://api.whatsmcp.com/mcp"
bearer_token_env_var = "WHATSMCP_API_KEY"
export WHATSMCP_API_KEY=wamcp_live_…
Codex 会将其作为 Authorization: Bearer … 发送。如果你希望自行设置标头,请使用 http_headers 设置静态值,并使用 env_http_headers 从环境中读取值。
其他所有客户端
不同客户端保存配置的位置各不相同,但都需要相同的设置:将端点添加为 远程 HTTP(而非 stdio)服务。支持 OAuth 的客户端只要获得 URL,就会自动找到登录流程。不支持 OAuth 的客户端则需要在 Authorization 中提供密钥;如果客户端不允许设置 Authorization,则使用 x-api-key。
如果客户端只提供“要运行的命令”,则它不支持远程服务 — 没有可供其连接的本地进程。
OAuth 流程的工作方式
仅当你要集成自己的客户端,或想知道你的 Agent 刚刚同意了什么时,才需要阅读。本流程完全采用标准 OAuth 2.1,没有自定义握手。
服务会发布两份元数据文档,客户端只需知道端点 URL,即可通过它们完成初始化:
/.well-known/oauth-protected-resource | RFC 9728 — 指定资源,并指向其授权服务器 |
/.well-known/oauth-authorization-server | RFC 8414 — 下方列出的端点、授权类型和权限范围 |
客户端可以通过动态客户端注册(RFC 7591,位于 /oauth/register)注册,也可以发布一个 URL 即为其客户端 ID 的客户端 ID 元数据文档;两种方式均受支持,上述厂商各自采用其中一种。之后便是常规的授权码流程,使用 PKCE(仅支持 S256):你会进入 console.whatsmcp.com/oauth/authorize 的授权页面,批准后,授权码会在 /oauth/token 处兑换。授权码只能使用一次;刷新令牌每次使用后都会轮换;重放已弃用的刷新令牌会撤销整个授权,而不是再签发一个令牌。令牌绑定到此资源(RFC 8707),并可在 /oauth/revoke 处撤销(RFC 7009)。
每项授权都会记录并公布七个权限范围:
| 权限范围 | 涵盖内容 |
|---|---|
wa:accounts | 列出你的号码、套餐和服务版本 |
wa:read | 消息、聊天、联系人、个人资料、群组、通话、媒体 |
wa:send | 发送、回应、编辑,以及群组和阻止列表变更 |
wa:pair | 关联和取消关联号码 |
wa:webhooks | 注册和管理入站消息投递 |
wa:egress:socks5、wa:egress:wireguard | 按账户配置出口连接 |
权限范围会被记录,但不会在工具层强制执行。 授权实际可以访问哪些工具,取决于你的套餐,与 API 密钥的情况完全相同。应将权限范围列表视为对连接用途的说明,而不是沙箱。
你可以在控制台 → 连接中查看和撤销授权。在此处撤销授权只会断开对应客户端,不会影响其他内容。
手动检查
curl -s https://api.whatsmcp.com/mcp \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
直接调用端点时,有两点容易让人措手不及:
- 响应可能采用服务器发送事件格式——每条消息占一行
data:。 - 工具结果是文本形式的 JSON,因此需要解析两次。
该端点是无状态的(MCP 2026-07-28 移除了协议会话),因此无需粘性路由,可从任何位置安全调用。若调用时未提供凭据,端点会以 401 响应,并返回指向受保护资源元数据的 WWW-Authenticate 标头,因此支持 OAuth 的客户端可以自行启动流程。
工具
共有 36 个工具。tools/list 中会显示哪些工具取决于你的套餐——套餐未包含的工具会缺席,而不是显示出来后拒绝调用。控制台 → 帮助会列出你的工作区可用的工具,并标明套餐包含的工具。
从 wa_list_accounts 开始。 其他所有工具都需要使用该工具返回的 account_id,且只有当账户的 state 为 connected 时才能使用。
账号、配对和套餐
| 工具 | 功能 |
|---|---|
wa_list_accounts | 列出已关联的号码:account_id、phone、push_name、state(pairing、connected、disconnected、logged_out、locked) |
wa_pair_account | 开始关联新号码;返回 base64 PNG 格式的二维码 |
wa_pair_status | 轮询配对状态;等待配对时会返回新的验证码 |
wa_unpair_account | 断开已关联的号码 |
wa_set_profile_photo | 替换或移除某个号码的头像——每位联系人看到的图片 |
wa_get_plan | 查看套餐、限制,以及消息和账号限额的当前用量——发送遭拒时可调用此工具,了解原因或查看剩余容量 |
消息
| 工具 | 功能 |
|---|---|
wa_send_message | 使用某个号码发送文本、图片、文档或音频 |
wa_list_messages | 跨账号读取消息,按时间从早到晚排列,并通过游标分页 |
wa_get_chat | 获取某个账号的近期消息;不使用游标,适用于一次性查漏 |
wa_get_message | 通过 WhatsApp ID 或游标获取一条已存储的消息,例如 Webhook 刚刚通知的消息 |
wa_get_media | 通过 message_id 下载收到的附件(base64 + mime) |
消息操作
以下工具均针对已存在的消息执行操作,因此每个工具都需要传入
wa_list_messages 提供的 message_id。
| 工具 | 功能 |
|---|---|
wa_react | 添加表情回应;空回应会移除你发送的回应 |
wa_edit_message | 编辑你发送的消息——WhatsApp 允许在约 20 分钟内编辑 |
wa_delete_message | 为所有人删除消息。WhatsApp 无法真正删除消息;此操作会撤回消息,所有现代客户端都会遵守 |
wa_set_presence | 向聊天发送正在输入状态(composing/paused),或将账号设为 available/unavailable。触发后即返回——不会确认是否送达 |
联系人和个人资料
| 工具 | 功能 |
|---|---|
wa_list_contacts | 分页列出账号的通讯录;也可通过 query 按姓名或号码搜索,并可选择包含头像 |
wa_get_profile | 查询某个号码在 WhatsApp 上的资料:是否已注册、公开姓名、个人简介、头像,以及企业账号的类别、联系方式和营业时间 |
与上面的 wa_list_contacts 不同,wa_get_profile 会向 WhatsApp 查询,而不是读取本地存储。
个人简介或头像为空,表示对方没有向此账号分享这些信息,并不代表
对方没有这些信息。
黑名单
| 工具 | 功能 |
|---|---|
wa_block_contact | 屏蔽联系人——对方将无法再致电或向此账号发送消息;或使用 unblock: true 解除屏蔽 |
wa_list_blocked | 列出此账号屏蔽的所有人 |
这两个工具都会报告对方是谁,而不只是号码:每个条目都包含号码、此账号通讯录中记录的姓名(从未保存在手机中的联系人则没有姓名),以及号码所属的国家。WhatsApp 不会记录联系人何时被屏蔽,因此无法提供日期。
群组和频道
| 工具 | 功能 |
|---|---|
wa_list_groups | 列出账号已加入的群组——JID、名称、成员数 |
wa_list_channels | 列出账号关注的频道——JID、名称、订阅者数 |
wa_join_group | 通过邀请链接加入群组 |
wa_follow_channel | 通过链接关注频道 |
wa_leave_chat | 退出群组或取消关注频道 |
wa_list_group_members | 列出群组成员,每位成员包含 JID、电话和管理员标记 |
wa_create_group | 创建群组;返回其 JID 和邀请链接 |
wa_delete_group | 移除所有其他成员,然后退出(WhatsApp 无法真正删除群组) |
群组管理
以下所有操作均遵循 WhatsApp 自身的规则:需要管理员权限的变更若没有相应权限就会失败,而不会悄无声息地无效返回。
| 工具 | 功能 |
|---|---|
wa_update_participants | 按电话号码或 JID 添加成员,或将成员提升为管理员、将管理员降级 — action 为 add、promote 或 demote |
wa_remove_participants | 将成员移出群组 |
wa_update_group | 更改群组的 name、description、是否仅管理员可更改设置(locked),以及是否仅管理员可发消息(announce)— 可在一次调用中更改其中任意项 |
wa_get_group_invite_link | 返回邀请链接;使用 reset 可撤销当前链接并生成新链接 |
通话
| 工具 | 功能 |
|---|---|
wa_list_calls | 按时间从早到晚分页显示通话记录 — 包括方向、对方、answered、seconds、reason、codec |
Webhook(付费套餐)
| 工具 | 功能 |
|---|---|
wa_set_webhook | 注册一个用于接收消息的 HTTPS 端点;返回一个仅显示一次的签名密钥 |
wa_get_webhook | 显示端点、是否启用,以及最近一次成功接收的时间 |
wa_enable_webhook | 暂停或恢复消息发送,不会更改端点或其密钥 |
wa_delete_webhook | 停止消息发送;仍可通过工具读取消息 |
如果只是想暂时停止消息发送,请使用 wa_enable_webhook,而不要删除后再重新创建:删除会生成新的密钥,所有使用旧密钥进行验证的内容都会失效。
联系人
你的 Agent 不应让你充当通讯录。wa_list_contacts 会读取从该账号关联的手机同步而来的联系人,这样 Agent 就能自行把*“给 Alice 发消息”*转换成电话号码。
它读取的是账号的本地联系人存储。这里不会与 WhatsApp 通信:不会通过网络进行查询,除套餐常规请求限流外,也不会产生任何速率费用。(下方的 wa_get_profile 是唯一会访问 WhatsApp 的工具。)
wa_list_contacts — 完整通讯录
wa_list_contacts({ "account_id": "acct_…", "limit": 500 })
→ {
"contacts": [
{ "phone": "447700900111", "name": "Alice Perreira", "name_source": "saved",
"jid": "[email protected]" },
{ "phone": "447700900222", "name": "Bakery", "name_source": "business", "jid": "…" },
{ "phone": "447700900333", "name": "dave", "name_source": "push", "jid": "…" }
],
"total": 482,
"next_cursor": "447700900333",
"has_more": true
}
| 字段 | 含义 |
|---|---|
phone | 仅包含数字的国际格式 — 可直接传给 wa_send_message。对于账号从未获知号码的 LID 格式联系人,此字段为空 |
name | 当前可用的最佳显示名称 |
name_source | saved — 账号所有者在自己的通讯录中填写的名称 · business — 已验证的企业名称 · push — 联系人为自己设置的名称,无人背书 |
jid | WhatsApp 自身的标识符 |
total | 超过分页上限之前匹配的联系人数量,模型据此可以判断当前页是整本通讯录还是其中一页 |
next_cursor / has_more | 分页读取,直到 has_more 为 false,即可读完所有联系人 |
分页使用游标并按稳定顺序(按电话号码排序),因此不会重复或跳过行。默认每页 500 条,最多 2000 条。
使用 query 搜索 — 查找某个人
传入 query,同一工具就会执行搜索,而不是列出联系人:
wa_list_contacts({ "account_id": "acct_…", "query": "+44 7700 900111" })
匹配不区分大小写,并会忽略号码中的标点,因此 "+44 7700 900111" 可以找到号码存为 447700900111 的联系人。搜索范围包括已保存的名称、企业名称、联系人为自己设置的名称以及电话号码。结果为空表示没有匹配项,并非错误。
使用 include_pictures 获取头像
设置 include_pictures: true 后,每位联系人都会附带 picture_url。此操作会在 WhatsApp 上查询当前页中的每位联系人,而不是读取本地存储,因此每页最多 10 条,最多可能需要半分钟 — 若要快速列出联系人,请保持关闭。如果 picture_url 为空,表示该账号看不到此联系人的头像,并不代表查询失败。
值得了解的事项
- 新关联的账号起初通讯录为空。 关联后不久,联系人会通过应用状态同步从手机导入,因此配对后立刻显示“没有联系人”通常只是“尚未同步”。工具会在
note中说明这一点,而不会让 Agent 报告一位有 500 个联系人的客户没有联系人。 - 只有保存在手机本机上的号码才算联系人。聊过天但从未保存的人没有通讯录条目,不过他们会作为
peer出现在wa_list_messages中。 - **如果账号处于离线状态,**读取操作会返回
account_not_connected和重试等待时间,而不是返回一本空通讯录,让人误以为“你谁也不认识”。 - 如果你更愿意直接查看,控制台会在 Contacts 下按号码显示同一份通讯录。
读取收到的消息
**服务端绝不会主动向你的 Agent 推送消息。**消息到达时,模型不会被打断,因此你的 Agent 会按自己的计划读取消息,而 游标可以确保这一过程可靠。
wa_list_messages 会按时间从早到晚返回消息,每条消息都带有一个 cursor,此外还会为当前页返回 next_cursor 和 has_more。将游标作为 after_cursor 传回,即可获取此后到达的消息——不会遗漏或重复,即使两条消息的时间戳精确到同一毫秒也一样;时间戳无法保证这一点。
after = 0
repeat:
r = wa_list_messages(after_cursor = after)
for m in r.messages:
if m.direction == "inbound":
handle(m) # e.g. reply with wa_send_message
after = r.next_cursor # advance — only newer rows next time
if not r.has_more:
sleep(a while) # caught up; poll again later
每一行都说明了发送者和所在位置:
| 字段 | 含义 |
|---|---|
direction | inbound(收到)或 outbound(你发出的) |
peer | 对方的号码。在群组或频道中,这是单个发送者,而不是对话本身 |
chat | 对话 JID——群组为 …@g.us,频道为 …@newsletter |
chat_kind | dm、group、channel 或 broadcast |
kind / text | 内容类型和正文(只有文本消息带有正文——其他内容请通过 wa_get_media 获取) |
at、message_id | RFC3339 时间戳和 WhatsApp 的消息 ID |
回复时:在 DM 中,将 to 设为对方的号码;在群组或频道中,将 to 设为 chat JID——如果发给单个发送者的号码,则会改为开启私人聊天。
在 Claude Code 中,
/loop命令可以自动完成这一过程:按固定间隔轮询,消息出现时执行操作,然后停止。使用/tasks查看正在运行的循环。
如果只想针对单个账号进行一次性补查,而不是轮询,wa_get_chat 会返回近期消息,且不带游标。
Webhooks
如果你不想轮询,wa_set_webhook 会在每条收到的消息到达时,将其发送到 HTTPS 端点(付费计划)。
{
"event": "message.inbound",
"delivery_id": "01JB…",
"tenant_id": "01JA…",
"account_id": "01J9…",
"account_phone": "447700900000",
"message_seq": 48210,
"message_id": "3EB0…",
"chat_jid": "[email protected]",
"peer": "447700900111",
"kind": "text",
"body": "are you open on Sunday?",
"at": "2026-09-02T14:21:07Z"
}
account_phone 是收到该消息的你自己的号码——路由规则、CRM 或支持队列通常会以此为索引。message_seq 与 wa_list_messages 使用的游标相同,因此如果使用方漏收了消息,可以进行核对,而不必猜测。
每个请求都带有:
| 请求头 | 值 |
|---|---|
X-WAMCP-Signature | t=<unix>,v1=<hex hmac-sha256> |
X-WAMCP-Delivery | 投递 ID,用于保证幂等性 |
X-WAMCP-Event | 事件名称,因此无需解析请求正文即可进行路由 |
验证签名——重新计算 HMAC-SHA256(secret, "<unix>" + "." + <raw body>),并以恒定时间进行比较,同时拒绝过期时间戳:
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
ts, sig = parts["t"], parts["v1"]
if abs(time.time() - int(ts)) > tolerance:
return False
mac = hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256)
return hmac.compare_digest(mac.hexdigest(), sig)
返回 2xx 以确认收到。每次尝试的时限为 10 秒;失败后会采用指数退避重试,最多 8 次。返回 410 Gone 会永久停止投递该消息——这表示端点明确告知不会再恢复。最近的尝试及其结果可在 Console → Webhooks 中查看。
发送
wa_send_message({
"account_id": "acct_…",
"to": "447700900111", // international form, digits only — or a …@g.us / …@newsletter JID
"text": "on my way"
})
→ { "status": "sent", "message_id": "3EB0…", "request_id": "01JB…" }
附件通过同一个工具发送。适用时,text 会成为说明文字:
| 参数 | 限制 | 备注 |
|---|---|---|
image_base64 + image_mime | 解码后 5 MiB | JPEG 或 PNG |
document_base64 + document_mime + document_filename | 解码后 20 MiB | 任意文件;接收方看到的文件名就是这里填写的文件名 |
audio_base64 + audio_mime(+ audio_seconds、audio_ptt) | 解码后 16 MiB | audio_ptt: true 会发送语音消息。音频没有说明文字 |
请检查返回的 status。这三个值含义不同:
status | 含义 |
|---|---|
sent | 已送达 WhatsApp;已设置 message_id |
queued | 已接收,但尚未确认。消息仍有可能送达——**请勿再次发送。**稍后通过 wa_list_messages,根据其 request_id 核对 |
refused | 未发送任何内容;refusal.reason 会说明重试是否有帮助 |
如果 Agent 将 queued 视为失败,就会向你的客户重复发送同一条消息。
群组和频道
列出群组和频道属于读取功能。加入、退出、发消息和群组管理要求账户在其桥接服务中启用群组和频道消息功能——请联系我们为某个号码开启。未启用时,账户会拒绝这些调用,并明确说明原因,而不是笼统地报错。
群组管理(wa_create_group、wa_update_participants、wa_remove_participants、wa_update_group、删除)遵循 WhatsApp 自身的规则:需要管理员权限的更改,在没有该权限时会失败。
wa_delete_group 会移除所有其他成员,然后退出群组,因为 WhatsApp 并没有真正的删除功能。
通过 SIP 拨打电话
*Beta。*WhatsMCP 可在两个方向上将 WhatsApp 语音通话桥接到 SIP。有人拨打你关联的号码时,SIP 电话或 PBX 会像收到普通 INVITE 一样响铃;分机拨打采用 E.164 格式的 WhatsApp 号码时,对方会在 WhatsApp 上接听,并且来电显示为你的号码。这不是 Meta Business Calling API——无需企业验证,也没有按分钟计费。
每个号码都需要在 控制台 → SIP 中单独设置,并且有两种连接方式。
托管 SIP 线路——无需 PBX
电话系统由我们运行:该号码会在我们的服务器上获得一个 SIP 账户,你可以将任意 SIP 电话、软电话或浏览器注册到该账户。控制台会显示服务器、用户名和密码(可使用 显示、复制和新密码),以及你的电话和 WhatsApp 桥接服务当前是否分别已注册。
为该线路选择电话类型——两种类型不能共用同一个端点:
| 电话类型 | 适用对象 | 连接方式 | 媒体 |
|---|---|---|---|
| SIP 电话 | 桌面电话、软电话、PBX | 通过 TLS 端口 5061 连接 SIP 服务器——仅当电话不支持 TLS 时,才使用普通 UDP 5060 | SRTP(SDES)——请在电话上启用。如果电话不支持,则使用普通 RTP |
| 浏览器(WebRTC) | 控制台内置的拨号器,或你自己的 WebRTC 客户端 | 控制台显示的 WebSocket URL(wss,端口 8089) | DTLS-SRTP,由浏览器自动处理 |
选择 浏览器 后,SIP 页面会提供一个拨号器:在浏览器中登录该线路,拨打 WhatsApp 号码或等待对方来电,然后通过麦克风通话——完全不需要硬件设备。
一条托管线路只能有一个注册设备,并且一次只能进行一通电话。第二台设备登录同一线路时,会接管第一台设备的注册,因此每条线路只运行一部电话。线路页面中的连接历史会显示你的电话和桥接服务的注册时间,以及任一方断开连接的时间。
你自己的 PBX 或 CRM 电话系统
桥接会以普通 SIP 分机的身份向你的注册服务器发起注册,因此无需为信令开放入站防火墙规则。请提供以下信息:
| 字段 | |
|---|---|
| 注册服务器 | host 或 host:port — 使用 UDP 时,端口默认为 5060;使用 TLS 时默认为 5061 |
| 传输协议 | UDP(大多数 PBX 开箱即用即可接受)或 TLS(用于加密信令)— 此时你的 PBX 必须为该主机提供由公开 CA 签发的证书。目前,传输到 PBX 的通话音频使用明文 RTP |
| 用户名 / 密码 | 你的 PBX 上的分机或中继账号。密码会加密存储,保存后不会再次显示 |
| 振铃分机 | WhatsApp 来电的转接目标 — 默认为 101,也可以设置为 caller / 9:caller,将来电者的号码传入你的拨号方案 |
保存前会先使用你的注册服务器验证凭据;按需点击测试连接会再次拨号,并告知你接通方。分机拨出时,请使用 E.164 格式的 WhatsApp 号码,省略前导 +。
编解码器
WhatsApp 会为每通电话自行选择编解码器 — Opus,或在网络受限时使用 Meta 的低码率编解码器 MLow — 并且通话过程中可能切换。桥接会解码来电音频,再为你这一侧重新编码,因此你的 PBX 无需知道 MLow 的存在:
| 你这一侧 | |
|---|---|
| G.722 | 优先提供 — 宽带(16 kHz),与 WhatsApp 使用的带宽相同 |
| G.711 µ-law (PCMU) | 所有 SIP 电话和 PBX 都支持的回退选项 — 窄带(8 kHz) |
| G.711 A-law (PCMA) | 你这一侧优先选择时接受 |
在中继上启用 g722,通话即可全程保持宽带;仅支持 G.711 的电话也能正常工作,音质相当于固定电话。
语音套餐
SIP 通话属于语音套餐,按线路计费,与消息套餐分开。套餐决定号码可以使用哪些通话方向 — 仅接听或接听和拨出 — SIP 页面会说明你的套餐允许哪些通话方向。如果通话方向不在套餐范围内,通话会被拒绝,而不会仅建立一半连接。价格按线路按月固定收取,不按分钟计费:请参阅 whatsmcp.com/sip。
所有通话,无论是否通过 SIP,都会记入号码的通话记录 — 包括方向、对端、是否接听、时长、结束原因和编解码器 — 可在控制台中查看,也可通过 wa_list_calls 工具获取。
先听听效果。 SIP 页面提供了一个可实时体验的演示号码: 在 WhatsApp 上给它发消息,它就会回拨给你。
需要一个只用于中继、不绑定手机的专用号码,或者需要多条线路?联系我们。
套餐和限制
每个工作区都会从免费套餐开始,足以关联一个号码并通过 Agent 驱动它。付费套餐会提高上限并增加功能:
| 套餐决定的内容 | |
|---|---|
| 账号 | 可同时关联的 WhatsApp 号码数量 |
| 消息 | 每小时和每 24 小时的发送上限 |
| 历史记录 | 已存储的消息正文在清除前保留多久 — wa_list_messages 只能读取此时间范围内的消息 |
| Webhook | 入站消息投递 — 付费功能,也是四个 wa_*_webhook 工具的启用条件 |
| 出口路由 | 通过你自己的 WireGuard 隧道或 SOCKS5 代理路由账号的桥接流量 |
| 语音 | 单独按线路计费的语音套餐,可让号码通过 SIP 通话 — 请参阅通过 SIP 通话 |
如果套餐不包含某项功能,对应工具不会显示为失败 — 它会完全缺席于 tools/list,因此模型不会提出注定失败的调用。
请向服务查询具体数值,而不是查看本页面:wa_get_plan 会返回你的套餐、限制和当前用量;控制台 → 用量也会显示相同的计数。
拒绝与错误处理
工具拒绝请求时不会引发协议错误,而是返回结构化的拒绝信息, 供模型读取并决定如何处理:
{
"refused": true,
"reason": "account_not_connected",
"message": "this account's bridge is not currently connected, so its contacts cannot be read; it reconnects on its own",
"retry_after_seconds": 30
}
reason | 含义 |
|---|---|
invalid_request | 参数错误或缺失,或者 ID 在你的工作区中不存在 |
account_not_connected | 号码处于离线状态。它会自动重新连接,可重试 |
account_locked | WhatsApp 已锁定此账户;message 中会附带原因 |
quota_exceeded | 当前时段内套餐的发送上限 |
plan_required | 此功能需要更高级别的套餐 |
throttled | 请求过多,或账户未能及时响应;可重试 |
未提供 retry_after_seconds 或其值为 0,表示重试没有帮助。
在传输层:无效或已撤销的凭证会得到 401(绝不会是 500,因此客户端不会无休止地重试失效凭证),且端点会按来源地址实施速率限制。
安全模型
- 凭证就是身份。 API 密钥和 OAuth 授权最终都指向同一对象:一个工作区;在任何工具运行之前,边缘层就会确定该工作区。凭证通过请求上下文传递,绝不会作为工具参数,因此不存在让一个工作区指定另一个工作区的字段。
- 外部 ID 会显示为“账户不存在”,而不是“禁止访问”——探测不会泄露任何信息。
- 密钥以哈希形式存储,创建时仅显示一次,并且可以单独撤销。
- OAuth 授权可按客户端撤销,路径为 控制台 → 连接。授权码只能使用一次,刷新令牌会轮换;重放已失效的令牌会撤销授权,而不会签发新令牌。
- Webhook 请求正文使用 HMAC-SHA256 签名,签名对象为带时间戳的负载。
- 你的 WhatsApp 账户仍归你所有:WhatsMCP 是一台关联设备,你可以随时通过手机(设置 → 已关联设备)或使用
wa_unpair_account将其移除。
状态与许可
WhatsMCP 已上线并可自行注册使用——此处介绍的服务已在生产环境运行,你现在就可以注册,无需联系任何人。
此仓库是该托管服务的公开文档。服务器源代码未公开,且本仓库内容未授予任何许可:内容可供公开阅读,但未获准复用或再分发。
WhatsMCP 是一项非官方集成。它与 Meta 或 WhatsApp 没有关联,也未获其授权或认可。
链接
| 产品网站 | https://whatsmcp.com |
| 文档 | https://whatsmcp.com/docs/mcp |
| 创建账户 | https://console.whatsmcp.com/register |
| 登录 | https://console.whatsmcp.com/login |
| 控制台 | https://console.whatsmcp.com |
| 帮助(你工作区专属的连接详情) | https://console.whatsmcp.com/help |
| MCP 端点 | https://api.whatsmcp.com/mcp |
| SIP ↔ WhatsApp 语音桥接 | https://whatsmcp.com/sip |
| SIP 控制台 | https://console.whatsmcp.com/sip |
| 工程博客 | https://whatsmcp.com/blog |
| Model Context Protocol | https://modelcontextprotocol.io |
| GitHub 上的组织 | https://github.com/whatsmcp |
| 隐私政策 | https://whatsmcp.com/privacy |
| 服务条款 | https://whatsmcp.com/terms |
| 联系 / 支持 | https://whatsmcp.com/contact |
有任何问题、需要启用群组消息的号码、需要评估容量的 SIP 中继,或套餐不合适—— 提交 issue、使用上方的联系链接,或通过控制台联系我们。
WhatsMCP — 一个端点,一个关联号码,让你的 Agent 用上 WhatsApp。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。