pbx-mcp について
pbx-mcpはAMIとESLを通じてAsteriskおよびFreeSWITCHのPBXを調べるMCPサーバーです。AIアシスタント向けに共通の調査ツールを提供し、通話制御とAsteriskの設定はそれぞれ個別に有効化できます。
主な機能
- 01Asteriskの状態、チャネル、エンドポイント、ダイヤルプランの確認
- 02FreeSWITCHの状態、チャネル、登録、SIPの確認
- 03ハングアップ対象チャネルのプレビュー
- 04明示的な有効化による発信・切断ツール
- 05オプトインによるAsteriskのトランクと内線の設定
活用シーン
- 01オフラインの内線や通話中の呼の確認
- 02SIPトランクの登録状態の調査
- 03ハングアップで影響を受けるチャネルの事前確認
- 04設定機能を有効にしてAsteriskのトランクやSIP内線を作成
MCP 対応
設定済みのAsteriskおよび/またはFreeSWITCH向け調査ツールをMCPクライアントに公開します。通話制御と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
AI アシスタントが Asterisk と FreeSWITCH を調査し、制御できる MCP サーバーです。
「今オフラインの内線はどれ?」や「SIP トランクが登録されないのはなぜ?」と尋ねると、推測ではなく、稼働中のスイッチから実際の回答が得られます。
ICTCore、ICTContact、ICTDialer、ICTFax、ICTPBX を手がけるチームである ICT Innovations の Tahir Almas が開発しました。このリポジトリの AMI クライアントと ESL クライアントには、それらの製品が利用するものと同じプロトコル基盤が使われています。
その理由
PBX のデバッグでは、大きく異なる 2 種類のコマンドセットを覚える必要があります。Asterisk は AMI と何百もの動詞を持つ CLI を使用します。FreeSWITCH は独自の用語を持つ ESL を使用します。両方を運用していると、常にコンテキストを切り替えることになります。
pbx-mcp は両方に対して、単一のわかりやすいツール群を提供します。そのため、各手順をいちいち指示しなくても、アシスタントが「通話に失敗している」という状況から sofia status gateway の実行まで進められます。
初めての方へ。 ユーザーガイドでは、PBX のセットアップ、クライアント設定、使用例、トラブルシューティングについて説明しています。この README はクイックリファレンスです。
アシスタントに表示される内容
エンジンごとに 6 つ、合計 12 個の読み取り専用ツールがあります。それぞれ十分に説明されているため、モデルは指示されなくても適切なツールを選択できます。以下は MCP Inspector 上で実行されているサーバーです。

4 つの書き込みツール asterisk_originate、asterisk_hangup、freeswitch_originate、freeswitch_hangup は、PBX_MCP_ALLOW_WRITE=true を設定するまで非表示です。
インストール
npm install -g pbx-mcp
または、ほとんどの MCP クライアント設定で使われている方法と同様に、npx から直接実行します。
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 にもあります。そちらのレジストリのほうが取得しやすい場合はご利用ください。
知っておくべき点は 3 つあります。
-iは必須です。サーバーは stdio 経由で MCP を使用するため、stdin を接続しないとコンテナは起動して何も出力しない状態になります。これはサーバーが壊れているように見えます。- 公開するポートはありません。リッスンするものがないためです。
- PBX にコンテナ内から到達できる必要があります。Asterisk が Docker ホスト自体で実行されている場合は、上記の IP を Mac と Windows では
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 | トランクと内線の 6 つのツールを登録します。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 にもあります。
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 | 発信者 ID、状態、ブリッジ、通話時間、ダイヤルプランの位置を含む、すべてのライブチャネル。任意の部分文字列でフィルター可能 |
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 はそのまま実行されてしまいました。r/mcp で Electrical-Place-458 から報告されました。
読み取り専用モードでは、書き込みツールは登録されません。 PBX_MCP_ALLOW_WRITE=true を設定しない限り、asterisk_originate などの4つのツールは tools/list に表示されません。モデルは、見えないツールを呼び出すことはできません。
ハングアップのプレビュー用ツールは常に利用できます。 asterisk_hangup_preview と freeswitch_hangup_preview は、実際に操作することなく、ハングアップによって切断される稼働中のチャネルを表示します。そのため、書き込みフラグを設定する前に影響範囲を確認したり、実際に実行する前にチャネル名の入力ミスに気付いたりできます。仕様上は読み取り専用ですが、書き込み処理と同じ照合を行います。
シェルのメタ文字は、コマンドを送信する前に、どちらのトランスポートでも拒否されます。
AMIヘッダーインジェクションを防止します。 AMIアクションに渡されるすべてのフィールドで復帰文字と改行文字を確認するため、発信者IDの文字列を使って追加のヘッダーを紛れ込ませることはできません。
出力は20,000文字に制限されます。 負荷の高いスイッチで show channels を実行しても、コンテキストウィンドウが出力で埋め尽くされることはありません。
これらの対策を講じていても、質問への回答に必要な最小限の権限だけをAMIユーザーに付与し、PBXはパブリックインターネットではなくファイアウォールの内側に設置してください。
トランクと内線のプロビジョニング(Asterisk、オプトイン)
AMIの UpdateConfig を介してPJSIPトランクとSIP内線を作成、一覧表示、削除するツールが6つ追加されています。これらは 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、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の隣に、空の管理対象ファイルを作成し(インクルード先が存在しない場合はエラーになります)、Asteriskがそのファイルに書き込めるようにします。touch /etc/asterisk/pjsip_mcp.conf -
pjsip.confの末尾に、次の1行だけを追加します。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 プロビジョナーは 1 つだけ実行してください。- 内線は、番号そのものではなく
mcp-<number>として登録します。 PJSIP は登録ユーザー名を使ってエンドポイントとその AOR を照合するため、すべてのオブジェクトにmcp-プレフィックスが必要です。作成時のレスポンスにユーザー名が記載されます。 - パスワードは
crypto.randomBytesで生成される、URL で安全に使用できる 24 文字のランダムな文字列です。返されるのは作成時のレスポンスのみで、表示またはログに記録されるのもそのときだけです。ただし、SIP パスワードであれば当然のこととして、PBX の管理対象ファイルには保存されます。
通話料金詐欺:有効にする前にお読みください
SIP トランクを使うと PBX から発信できます。また、発信ルートに到達できるコンテキストを持つ、登録可能な内線があれば、パスワードを知った人は誰でも同じことができます。SIP 認証情報の窃取は、高額な電話料金が発生する主な原因の 1 つです。
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とパスワードが 1 回だけ表示されます。 -
その認証情報を使って電話機を 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 のみです。
プロトコルクライアント単体での利用
MCP がまったく不要で、ご自身の Node コードから PBX に接続したい場合は、このサーバーの基盤となる 2 つのクライアントが個別に公開されています。同じプロトコル処理を行いますが、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
コントリビューション
Issue やプルリクエストを歓迎します。ツールを追加する場合は、ダイヤルプランを見たことがない同僚に説明するように、そのツールについて説明してください。モデルは説明をもとにツールを選ぶため、説明が曖昧だとツールとして機能しません。
概要
ICT Innovations の創業者である Tahir Almas が開発・保守しています。
ICT Innovations は 2005 年以来、オープンソースおよび商用のテレフォニー製品を提供してきました。pbx-mcp が役立つのであれば、その基盤となる製品群も役立つかもしれません。
- ICTCore - 以下の製品の基盤となるオープンソースのテレフォニーフレームワーク
- ICTPBX - ホワイトラベルのマルチテナント IP PBX。GitHub では無料のコミュニティエディションを提供しています
- ICTContact - コンタクトセンターおよびユニファイドコミュニケーション
- ICTDialer - オートダイヤラーおよび予測ダイヤラー
- ICTFax - オープンソースの FAX サーバー
- asterisk-ami-node および freeswitch-esl-node - このリポジトリのプロトコルクライアント。個別に公開されています
商用製品についてのお問い合わせは、ICT Innovations のサポートポータルからお願いします。pbx-mcp 自体についてのお問い合わせは、回答を誰でも読める GitHub の Issue にお寄せください。
ライセンス
MIT です。LICENSEをご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。