关于 pbx-mcp
pbx-mcp 是通过 AMI 和 ESL 检查 Asterisk 与 FreeSWITCH PBX 系统的 MCP 服务,为 AI 助手提供统一的检查工具;呼叫控制和 Asterisk 配置需分别显式启用。
主要功能
- 01检查 Asterisk 状态、通道、端点和拨号计划
- 02检查 FreeSWITCH 状态、通道、注册和 SIP
- 03预览挂断操作影响的通道
- 04显式启用拨号和挂断工具
- 05选择启用 Asterisk 中继与分机配置
适用场景
- 01检查离线分机或活动通话
- 02排查 SIP 中继注册状态
- 03预览挂断操作会影响哪些通道
- 04启用配置功能后创建 Asterisk 中继或 SIP 分机
MCP 相关
向 MCP 客户端提供已配置的 Asterisk 和/或 FreeSWITCH 检查工具。呼叫控制和 Asterisk 配置工具仅在分别启用对应选项后注册。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y pbx-mcpASTERISK_AMI_HOSTHostname or IP of the Asterisk server. Set this to enable the Asterisk tools.ASTERISK_AMI_PORTAsterisk Manager Interface port. Defaults to 5038.ASTERISK_AMI_USERNAMEAMI username from manager.conf.ASTERISK_AMI_PASSWORD密钥AMI secret from manager.conf.ASTERISK_AMI_TLSConnect to AMI over TLS. Set true if tlsenable=yes in manager.conf.FREESWITCH_ESL_HOSTHostname or IP of the FreeSWITCH server. Set this to enable the FreeSWITCH tools.FREESWITCH_ESL_PORTFreeSWITCH inbound event socket port. Defaults to 8021.FREESWITCH_ESL_PASSWORD密钥Event socket password from event_socket.conf.xml. Defaults to ClueCon, which you should change.PBX_MCP_ALLOW_WRITEUnlocks call control. When false the server is read-only and the originate and hangup tools are not registered at all. Placing a call on a live trunk costs real money, so leave this off unless you mean it.PBX_MCP_TIMEOUT_MSPer command timeout in milliseconds. Defaults to 10000.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
pbx-mcp
一个 MCP 服务,可让 AI 助手检查和控制 Asterisk 与 FreeSWITCH。
询问“现在有哪些分机处于离线状态?”或“我的 SIP 中继为什么无法注册?”,即可从正在运行的交换机获得准确答案,而不是猜测。
由 ICT Innovations 的 Tahir Almas 开发。该团队也是 ICTCore、ICTContact、ICTDialer、ICTFax 和 ICTPBX 的开发者。本仓库中的 AMI 和 ESL 客户端采用的协议基础,也正是这些产品所使用的。
为什么要用
调试 PBX 意味着要记住两套截然不同的命令。Asterisk 使用 AMI 和拥有数百个命令的 CLI。FreeSWITCH 使用 ESL,也有自己的一套术语。如果你同时运行两者,就得整天在不同上下文之间切换。
pbx-mcp 在两者前提供一套统一、描述清晰的工具接口,让助手可以从“通话失败了”直接转到 sofia status gateway,而不必由你逐步说明每个操作。
初次使用?用户指南介绍了 PBX 设置、客户端配置、示例和故障排除。本 README 是快速参考。
助手能看到什么
十二个只读工具,每种引擎各六个,每个工具都描述得足够清楚,让模型无需额外指示就能选对。这是运行在 MCP Inspector 下的服务:

四个写入工具 asterisk_originate、asterisk_hangup、freeswitch_originate 和 freeswitch_hangup,只有在设置 PBX_MCP_ALLOW_WRITE=true 后才会显示。
安装
npm install -g pbx-mcp
或者直接通过 npx 运行,这是大多数 MCP 客户端配置采用的方式:
npx -y pbx-mcp
需要 Node 18 或更高版本。
Docker
如果你不想在连接 PBX 的机器上安装 Node,可以使用预构建镜像。
docker run -i --rm \
-e ASTERISK_AMI_HOST=10.0.0.10 \
-e ASTERISK_AMI_USERNAME=mcp \
-e ASTERISK_AMI_PASSWORD=change-me \
ghcr.io/ictinnovations/pbx-mcp
如果从 Docker Hub 拉取更方便,也可以使用同一镜像:ictinnovations/pbx-mcp。
需要了解以下三点:
-i不能省略。该服务通过 stdio 使用 MCP 通信,因此如果没有连接 stdin,容器启动后就会一直沉默,看起来就像服务出故障了一样。- 无需发布端口,因为没有任何监听端口。
- 必须能够从容器内部访问 PBX。如果 Asterisk 运行在 Docker 主机本身上,在 Mac 和 Windows 上请将上面的 IP 替换为
host.docker.internal,在 Linux 上则添加--network host。
镜像以非 root 用户运行,并且与其他运行方式一样,默认以只读模式启动。
配置
所有配置都通过环境变量提供。可设置 Asterisk 配置块、FreeSWITCH 配置块,或同时设置两者。服务只会注册已配置的工具,因此仅使用 Asterisk 的环境中不会看到 FreeSWITCH 工具。
Asterisk
| 变量 | 默认值 | 说明 |
|---|---|---|
ASTERISK_AMI_HOST | (启用所必需) | Asterisk 主机的主机名或 IP |
ASTERISK_AMI_PORT | 5038 | manager.conf 中的 AMI 端口 |
ASTERISK_AMI_USERNAME | AMI 用户名 | |
ASTERISK_AMI_PASSWORD | AMI 密钥 | |
ASTERISK_AMI_TLS | false | 若 tlsenable=yes,则设为 true |
manager.conf 中的用户至少需要 read = system,call,command 和 write = command 权限。只有计划启用写入模式时才添加 originate。
[mcp]
secret = change-me
read = system,call,command
write = command
FreeSWITCH
| 变量 | 默认值 | 说明 |
|---|---|---|
FREESWITCH_ESL_HOST | (必填才能启用) | 交换机的主机名或 IP |
FREESWITCH_ESL_PORT | 8021 | 入站 ESL 端口 |
FREESWITCH_ESL_PASSWORD | ClueCon | 来自 event_socket.conf.xml |
共享
| 变量 | 默认值 | 说明 |
|---|---|---|
PBX_MCP_ALLOW_WRITE | false | 解锁呼叫控制。请先阅读安全部分 |
PBX_MCP_TIMEOUT_MS | 10000 | 每条命令的超时时间 |
配置(仅限 Asterisk,选择启用)
| 变量 | 默认值 | 说明 |
|---|---|---|
PBX_MCP_ALLOW_PROVISION | false | 注册六个中继和分机工具。与 PBX_MCP_ALLOW_WRITE 相互独立 |
PBX_MCP_TRUNK_ALLOW | (未设置) | 中继可指向的 IPv4 CIDR 和主机名,以逗号分隔。未设置时将拒绝 asterisk_trunk_create |
PBX_MCP_CONTEXT_ALLOW | (未设置) | 新对象可使用的拨号计划上下文,以逗号分隔。未设置时将拒绝所有创建操作 |
PBX_MCP_PJSIP_FILE | pjsip_mcp.conf | 配置写入的唯一包含文件。必须是独立的 pjsip_*.conf 文件名(绝不能是 pjsip.conf、manager.conf 或任何其他文件) |
Claude Desktop
将以下内容添加到 claude_desktop_config.json:
{
"mcpServers": {
"pbx": {
"command": "npx",
"args": ["-y", "pbx-mcp"],
"env": {
"ASTERISK_AMI_HOST": "10.0.0.10",
"ASTERISK_AMI_USERNAME": "mcp",
"ASTERISK_AMI_PASSWORD": "change-me",
"FREESWITCH_ESL_HOST": "10.0.0.11",
"FREESWITCH_ESL_PASSWORD": "ClueCon"
}
}
}
}
任何使用 stdio 的 MCP 客户端都可以采用相同的结构。副本位于 examples/claude_desktop_config.json。
若要使用 Docker 而非 npx 运行容器,请保留 env 块,并将 command 指向 Docker:
{
"mcpServers": {
"pbx": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "ASTERISK_AMI_HOST",
"-e", "ASTERISK_AMI_USERNAME",
"-e", "ASTERISK_AMI_PASSWORD",
"ghcr.io/ictinnovations/pbx-mcp"
],
"env": {
"ASTERISK_AMI_HOST": "10.0.0.10",
"ASTERISK_AMI_USERNAME": "mcp",
"ASTERISK_AMI_PASSWORD": "change-me"
}
}
}
}
每个不带值的 -e NAME 都会将 env 中对应的变量传递到容器中,从而避免机密出现在参数列表中。
工具
Asterisk
| 工具 | 功能 |
|---|---|
asterisk_status | 版本、运行时间、活动呼叫数和已处理呼叫数 |
asterisk_channels | 所有实时通道,包含主叫号码、状态、桥接、持续时间和拨号计划位置。可选子字符串筛选 |
asterisk_endpoints | PJSIP 端点的设备状态和联系人数量。在较旧的安装中会回退到 chan_sip 对等端 |
asterisk_dialplan | 转储一个上下文,或上下文中的一个分机 |
asterisk_cli | 执行任意 CLI 命令,但须遵守下方的安全策略 |
asterisk_hangup_preview | 显示挂断操作会断开的实时通道,但不会实际断开 |
asterisk_originate | 发起呼叫。仅写入模式可用 |
asterisk_hangup | 按名称终止通道。仅写入模式可用 |
FreeSWITCH
| 工具 | 功能 |
|---|---|
freeswitch_status | 版本、运行时间、当前会话数和最大会话数 |
freeswitch_channels | show channels 返回的所有实时呼叫腿。可选子字符串筛选,并保留标题行 |
freeswitch_registrations | Sofia 配置文件上的已注册用户,包含联系人 URI、用户代理和有效期 |
freeswitch_sofia_status | 所有 SIP 配置文件和网关,包括中继是否已在上游注册 |
freeswitch_api | 执行任意 API 命令,但须遵守下方的安全策略 |
freeswitch_hangup_preview | 显示挂断操作会断开的实时呼叫腿,但不会实际断开 |
freeswitch_originate | 发起呼叫。仅写入模式可用 |
freeswitch_hangup | 对通道 UUID 执行 uuid_kill。仅写入模式可用 |
安全
PBX 不是随手试验的地方。重新加载配置文件会丢失注册信息,而发起呼叫会在真实线路上产生实际费用。因此,默认采取只读模式,并设置多层防护:
默认只读。 asterisk_cli 接受一组用于检查的前缀白名单(core show、pjsip show、dialplan show、queue show 等)。freeswitch_api 接受同类白名单(status、show、sofia status、db list 等),并按命令开头进行匹配,因此子命令也会被计入。
FreeSWITCH 白名单允许子命令,不是拒绝包含危险词的命令。 sofia status 是读取操作;sofia profile internal restart 不在白名单中,因此会被拒绝。过去采用的方式正好相反:将每个单词与会更改状态的动词列表逐一比对,但这种方法只能捕获有人想到的单词。conference 3001 kick all 就直接绕过了检查。此问题由 Electrical-Place-458 在 r/mcp 上报告。
只读模式下不会注册写入工具。 除非设置 PBX_MCP_ALLOW_WRITE=true,否则 asterisk_originate 和其他三个工具不会出现在 tools/list 中。模型无法调用它看不到的工具。
挂断预览工具始终可用。 asterisk_hangup_preview 和 freeswitch_hangup_preview 会显示挂断操作会断开哪些活动通道,但不会实际断开它们。这样,你可以在启用写入标志前了解影响范围,也可以在执行实际操作前发现通道名称中的拼写错误。根据设计,它们是只读工具,但会使用写入路径所用的相同匹配逻辑。
两种传输方式都会在发送命令前拒绝 shell 元字符。
AMI 标头注入会被拦截。 每个写入 AMI 操作的字段都会检查是否包含回车符和换行符,避免主叫号码字符串混入额外标头。
输出限制为 20,000 个字符。 繁忙的交换机上执行一次 show channels,也不会挤满上下文窗口。
即便有这些防护,也应仅授予 AMI 用户能够回答你问题的最小权限集,并将 PBX 部署在防火墙之后,而不是放在公共互联网中。
配置中继和分机(Asterisk,可选启用)
另外有六个工具可通过 AMI UpdateConfig 创建、列出和删除 PJSIP 中继与 SIP 分机。只有在设置 PBX_MCP_ALLOW_PROVISION=true 时才会注册;它们与写入模式相互独立:启用其中一种不会启用另一种。
| 工具 | 功能 |
|---|---|
asterisk_trunk_create | IP 身份验证中继:endpoint、aor 和 identify。字段:name、host、port(5060)、transport(udp、tcp、tls)、codecs、context、dry_run |
asterisk_trunk_list / asterisk_trunk_delete | 列出或删除此服务创建的中继 |
asterisk_extension_create | SIP endpoint,电话会向其注册(endpoint、aor、auth),不是拨号计划分机。字段:number、context、codecs、dry_run。生成的密码仅返回一次 |
asterisk_extension_list / asterisk_extension_delete | 列出或删除此服务创建的分机。不会列出密码 |
编解码器为 ulaw、alaw、g722、g729、opus。名称和号码须匹配 ^[A-Za-z0-9_-]{1,32}$。
一次性设置
-
在
pjsip.conf旁创建空的托管文件(缺少 include 会导致错误),并允许 Asterisk 向其中写入:touch /etc/asterisk/pjsip_mcp.conf -
在
pjsip.conf末尾添加这一行。不会触碰pjsip.conf中的其他内容:#include pjsip_mcp.conf -
为 AMI 用户授予配置所需的额外权限。
config用于UpdateConfig/GetConfig,command用于重新加载和验证步骤;仅当你也使用写入模式时才需要originate:[mcp] secret = change-me deny = 0.0.0.0/0.0.0.0 permit = 192.0.2.0/24 read = system,call,command write = command,originate,config -
中继引用名为
transport-udp、transport-tcp或transport-tls的传输方式;请在pjsip.conf中定义你将使用的传输方式。
工作原理
- 所有内容都会写入托管文件:使用
UpdateConfig(NewCat、Append、RenameCat、DelCat)更新,然后执行module reload res_pjsip.so,再运行pjsip show endpoint mcp-<name>。如果 Asterisk 未报告该端点,就会再次移除更改,并返回错误。 - 每个对象的名称都是
mcp-<name>。列表和删除操作只会针对托管文件中的mcp-分区;不能将中继当作分机删除,反之亦然。 - 创建操作会拒绝已存在的名称。
dry_run=true会返回完整的配置块,且不会调用 AMI;对于分机,密码会显示为占位符。 - 所有配置调用都会在进程内串行执行,因为
UpdateConfig采用读取-修改-写入方式。每个托管文件只运行一个 pbx-mcp 配置程序。 - 分机会注册为
mcp-<number>,而不是不带前缀的号码。PJSIP 会根据注册用户名匹配端点及其 AOR,而且每个对象都必须带有mcp-前缀。创建响应会说明用户名。 - 密码是由
crypto.randomBytes生成的 24 个随机 URL 安全字符。它只会在创建响应中返回,也是唯一会显示或记录密码的地方;密码确实会保存在 PBX 上的托管文件中,这是 SIP 密码所必需的。
电话欺诈:启用前请阅读
SIP 中继允许呼叫离开 PBX;可注册且使用了可接通外呼路由的上下文的分机,也会让任何得知密码的人做到这一点。被盗的 SIP 凭据是产生高额电话账单的主要原因之一。
- 将
PBX_MCP_CONTEXT_ALLOW指向无法拨打 PSTN 的上下文,除非你确实有此意图。上下文是唯一决定已注册电话或中继可以呼叫哪些号码的因素。 - 尽可能严格地限制
PBX_MCP_TRUNK_ALLOW。主机名会按字面值比较,且不会解析,因此 DNS 无法扩大列表范围。不支持 IPv6。 - 允许列表为空时会拒绝所有内容:配置会默认失败关闭。
- 请将持有这些工具的助手视为有权更改哪些对象可以访问 PBX。检查它创建的内容(先使用
*_list或dry_run),不要将 SIP(5060)或 AMI(5038)暴露到互联网。 - 尝试使用时,优先选择实验室或预发布 PBX。
示例流程
仅使用文档专用地址(RFC 5737)。环境:
PBX_MCP_ALLOW_PROVISION=true
PBX_MCP_TRUNK_ALLOW=192.0.2.0/24,198.51.100.0/24
PBX_MCP_CONTEXT_ALLOW=from-trunk,from-internal
-
使用
asterisk_trunk_create和dry_run=true预览中继:{ "name": "carrier1", "host": "192.0.2.10", "port": 5060, "transport": "udp", "codecs": ["ulaw", "alaw"], "context": "from-trunk", "dry_run": true }返回内容如下:
[mcp-carrier1] type=endpoint transport=transport-udp context=from-trunk disallow=all allow=ulaw,alaw aors=mcp-carrier1 [mcp-carrier1] type=aor contact=sip:192.0.2.10:5060 [mcp-carrier1] type=identify endpoint=mcp-carrier1 match=192.0.2.10 -
不带
dry_run再运行一次。不在允许列表中的主机(例如203.0.113.5)会被拒绝。 -
创建分机:
{ "number": "1001", "context": "from-internal" }。回复会提供 SIP 用户名mcp-1001和密码,密码仅显示这一次。 -
使用这些凭据将电话连接到 PBX,然后通过
asterisk_endpoints检查。 -
asterisk_extension_list和asterisk_trunk_list会显示现有对象;使用1001调用asterisk_extension_delete,以及使用carrier1调用asterisk_trunk_delete,即可将其删除。
已针对 Asterisk 22(认证版本 22.8)进行测试。使用的 PJSIP 选项(identify、max_contacts、remove_existing、auth_type=userpass)和 UpdateConfig 功能(RenameCat、catfilter)都是标准功能,但在其他 Asterisk 版本上请重新确认。已生成 TCP 和 TLS 中继配置,但未对实时对端进行测试。
从源代码构建
git clone https://github.com/ictinnovations/pbx-mcp.git
cd pbx-mcp
npm install
npm run build
npm start
AMI 和 ESL 客户端没有第三方依赖。这两种协议都只是通过 TCP 传输带有帧结构的文本,手动实现它们可以让安装体积更小,行为也更可预测。仅有的运行时依赖是 MCP SDK 和 Zod。
独立使用协议客户端
如果你想在自己的 Node 代码中与 PBX 通信,而完全不需要 MCP,这个服务所用的两个客户端也单独发布了。协议功能相同,不依赖 MCP SDK、Zod 等任何组件:
- asterisk-ami-node - Asterisk Manager Interface 客户端。
npm install asterisk-ami-node - freeswitch-esl-node - FreeSWITCH Event Socket 客户端,采用入站模式。
npm install freeswitch-esl-node
两者均零依赖,使用 TypeScript,支持 ESM 和 CommonJS,要求 Node 18 或更高版本,并经过模拟交换机测试,因此无需 PBX 即可运行测试套件。
目录结构
src/
index.ts entry point, config to transport wiring
ami.ts Asterisk Manager Interface client
esl.ts FreeSWITCH Event Socket Layer client
config.ts environment config and the command safety policy
tools/
asterisk.ts Asterisk tool definitions
freeswitch.ts FreeSWITCH tool definitions
format.ts text table and truncation helpers
贡献
欢迎提交问题和拉取请求。如果你要添加工具,请像向从未接触过你的拨号计划的同事介绍那样描述它。模型会根据这些描述选择工具,所以描述含糊不清就等于工具无法正常工作。
关于
由 ICT Innovations 创始人 Tahir Almas 创建并维护。
ICT Innovations 自 2005 年以来一直推出开源和商业电话解决方案。如果 pbx-mcp 对你有用,其背后的完整技术栈或许也能帮到你:
- ICTCore - 开源电话框架,是下列产品的基础
- ICTPBX - 白标多租户 IP PBX,在 GitHub 上提供免费社区版
- ICTContact - 联络中心和统一通信
- ICTDialer - 自动拨号和预测式拨号器
- ICTFax - 开源传真服务
- asterisk-ami-node 和 freeswitch-esl-node - 本仓库中的协议客户端,现已单独发布
有关商业产品的问题,请通过 ICT Innovations 支持门户联系。有关 pbx-mcp 本身的问题,请在 GitHub 上提交问题,以便所有人都能看到答复。
许可证
MIT。请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。