Headless PBX control through MCP and HTTP API. Any AI, bot, or app connects and manages FreePBX through 219 tools. No GraphQL needed.
Connect via MCP and ask "why can't extension 101 make calls?" — Frogman runs live diagnostics, searches its built-in knowledge base, and hands the AI everything it needs to answer.
Connect via HTTP API with token auth and build dashboards, bots, or integrations on any platform.
Also includes a web console and CLI chat for direct access. Built entirely on FreePBX's native interfaces (BMO, AMI, fwconsole). Every action is validated, permission-gated, audit-logged, and requires confirmation before making changes.
- FreePBX 17.x
- Asterisk 20+ (tested on 22.8.2)
- PHP 8.2+
- API module (for GraphQL) 17.0.1+
Pick whichever path fits — all three install the same module.
- Download the latest tarball from the Releases page (
frogman-x.x.x.tgz). - In FreePBX, go to Admin → Module Admin.
- Click Upload modules, choose the
.tgz, and click Upload. - Find Frogman in the module list, set the action to Install, click Process, then Confirm.
- When the red Apply Config bar appears, click it.
Grabs the latest release URL from the GitHub API and installs it — no version to update:
URL=$(curl -s https://api.github.com/repos/mwtcmi/frogman/releases/latest | grep browser_download_url | grep '\.tgz' | cut -d'"' -f4)
fwconsole ma downloadinstall "$URL"
fwconsole reloadOr grab the URL by hand from the latest release page and pass it directly to fwconsole ma downloadinstall.
# Copy the module to your FreePBX modules directory
cp -r frogman /var/www/html/admin/modules/
# Install the module
fwconsole ma installlocal frogman
# Set permissions and apply
fwconsole chown
fwconsole reloadUse installlocal (not install) — install hits online repos and fails because Frogman isn't published to FreePBX's standard repos.
fwconsole ma list | grep frogman
# | frogman | x.x.x | Enabled | AGPLv3+ | Unsigned |To enable service management tools (start/stop/restart FreePBX, fix permissions, system update, etc.) from the chat console, run once as root:
echo 'asterisk ALL=(root) NOPASSWD: /usr/sbin/fwconsole' > /etc/sudoers.d/frogman
chmod 440 /etc/sudoers.d/frogmanThis is optional — all other tools work without it. Without this, service tools will show instructions on how to enable.
Frogman is the MCP server — the AI interface to the PBX. Frogman is the FreePBX module that provides the 219 tools it exposes. Together, they have two interfaces:
- MCP Server — the core product. Any AI connects via MCP and uses 219 tools to control, diagnose, and troubleshoot the PBX. This is where RAG, reasoning, and intelligent support happen.
- Web Console & CLI — a human-friendly chat interface using pattern matching. Same tools, no AI required. Useful for quick tasks without an MCP client.
Tools internally route by this priority:
- BMO PHP calls — preferred for all operations
- AMI commands — live call control, channel operations
- Direct DB reads — diagnostics and reporting
- fwconsole wrappers — system ops only (reload, restart, module admin, backup)
- Direct DB writes —
oc_*tables only
Frogman owns five tables (prefixed oc_*):
| Table | Purpose |
|---|---|
oc_audit_log |
Full audit trail of every tool execution |
oc_sessions |
Chat session tracking |
oc_saved_queries |
Saved GraphQL queries |
oc_jobs |
Async job queue (future use) |
oc_aliases |
Command aliases |
Reads from other modules' tables are fine. Writes to other modules go through BMO or GraphQL — never direct SQL.
- No arbitrary code generation. The tool surface is a fixed allowlist of PHP methods.
- Input validation on every tool before execution.
- Permission gating via FreePBX User Manager.
- Audit logging — intent recorded before execution, outcome recorded after.
- Confirmation required — all mutating operations return a dry-run preview unless
confirm: trueis passed. - No user-supplied PHP, SQL, or shell is ever executed.
Contributors: see CONTRIBUTING.md for the full rules, why they exist, and how to add a tool.
| Tool | Description |
|---|---|
fm_list_extensions |
List all extensions with optional tech/search filters |
fm_get_extension |
Full details for a single extension |
fm_get_extension_health |
Config + SIP registration + recent CDR |
fm_add_extension |
Create a new PJSIP extension + linked User Manager user [confirm] |
fm_update_extension |
Update extension name, secret, or CID [confirm] |
fm_set_extension_email |
Set/update email on the linked User Manager user + voicemail-to-email [confirm] |
fm_disable_extension |
Delete an extension [confirm] |
| Tool | Description |
|---|---|
fm_list_ringgroups |
List all ring groups |
fm_get_ringgroup |
Ring group details + member list |
fm_ringgroup_add_member |
Add member to ring group [confirm] |
fm_ringgroup_remove_member |
Remove member from ring group [confirm] |
| Tool | Description |
|---|---|
fm_list_trunks |
List all configured trunks |
fm_get_trunk_status |
Trunk config + PJSIP registration status |
| Tool | Description |
|---|---|
fm_list_active_calls |
Active calls via AMI |
fm_get_cdr |
Query call detail records with filters |
| Tool | Description |
|---|---|
fm_set_followme |
Configure Follow Me for an extension [confirm] — chat: set followme on 1001 to 1001,5551234567, set follow me (guided wizard), or set follow me 1001 (wizard with ext pre-filled) |
fm_clear_followme |
Remove Follow Me [confirm] |
| Tool | Description |
|---|---|
fm_get_call_forward |
Get call forwarding status for an extension |
fm_set_call_forward |
Set call forwarding (CF/CFB/CFU) [confirm] |
fm_clear_call_forward |
Clear call forwarding [confirm] |
fm_get_dnd |
Get Do Not Disturb status |
fm_toggle_dnd |
Toggle Do Not Disturb [confirm] |
| Tool | Description |
|---|---|
fm_list_voicemail |
List all voicemail boxes |
fm_get_voicemail |
Voicemail box details and message count |
| Tool | Description |
|---|---|
fm_list_queues |
List all call queues |
fm_get_queue |
Queue details by ID |
| Tool | Description |
|---|---|
fm_list_conferences |
List all conference rooms |
fm_get_conference |
Conference room details |
| Tool | Description |
|---|---|
fm_list_ivrs |
List all IVRs |
fm_get_ivr |
IVR details by ID |
| Tool | Description |
|---|---|
fm_list_announcements |
List all announcements |
| Tool | Description |
|---|---|
fm_list_time_conditions |
List all time conditions with current state |
fm_toggle_time_condition |
Toggle a time condition override [confirm] |
fm_list_daynight |
List all day/night call flow controls |
fm_toggle_daynight |
Toggle a day/night call flow [confirm] |
| Tool | Description |
|---|---|
fm_list_inbound_routes |
List all inbound routes (DIDs) |
fm_list_outbound_routes |
List all outbound routes |
fm_get_outbound_route |
Outbound route details by ID |
| Tool | Description |
|---|---|
fm_list_misc_dests |
List all misc destinations |
fm_add_misc_dest |
Create a misc destination [confirm] |
fm_remove_misc_dest |
Remove a misc destination [confirm] |
| Tool | Description |
|---|---|
fm_list_blacklist |
List all blacklisted numbers |
fm_add_blacklist |
Add a number to the blacklist [confirm] |
fm_remove_blacklist |
Remove a number from the blacklist [confirm] |
| Tool | Description |
|---|---|
fm_dialplan_show |
List custom dialplan contexts |
fm_dialplan_get_context |
Show contents of a custom context |
fm_dialplan_templates |
List available dialplan templates |
fm_dialplan_apply |
Generate and apply a dialplan template [confirm] |
fm_dialplan_remove |
Remove a custom dialplan context [confirm] |
| Tool | Description |
|---|---|
fm_list_paging |
List all paging/intercom groups |
fm_list_parking |
List parking lots and parked calls |
| Tool | Description |
|---|---|
fm_list_feature_codes |
List all feature codes with status |
fm_list_moh |
List music on hold categories |
fm_list_recordings |
List all system recordings |
| Tool | Description |
|---|---|
fm_reload |
Apply config changes (checks active calls first) [confirm] |
fm_module_list |
List FreePBX modules. Optional filters: status, license (commercial/gpl/gpl2/gpl3/agpl/other), all. Chat shows a clickable summary by default — chat: list modules, list modules commercial, list all modules |
fm_check_upgrades |
Query online repos for module upgrades (~10s, network call). Per-row "⬆️ Upgrade" chip and bottom "⬆️ Upgrade all" chip — chat: check for upgrades |
fm_module_status |
Detailed status of a specific module |
fm_get_asterisk_info |
Asterisk uptime, version, channels, registrations |
fm_get_firewall_status |
Firewall and intrusion detection status |
fm_get_sip_settings |
SIP/PJSIP settings — external IP, NAT, ports |
fm_repair_userman_links |
Restore default-group + assigned wiring on User Manager users so UCP login works [confirm] — chat: repair userman, fix ucp logins, repair userman 1001 |
| Tool | Level | Description |
|---|---|---|
fm_list_backup_jobs |
read | List configured backup jobs with schedule, destinations, retention, email — chat: list backup jobs |
fm_backup_status |
read | Per-job health: last successful run, in-flight, next/previous scheduled tick, missed-run inference — chat: backup status, backup status for <name> |
fm_list_backup_runs |
read | Real run history (success/running/failed) + synthetic failed_inferred rows for missed scheduled ticks — chat: list backup runs, list backup runs for <name>, list failed backup jobs |
fm_get_backup |
read | Full config of one backup job by ID — chat: show backup <id> |
fm_backup_create |
admin | Run a backup job by ID [confirm] |
| Tool | Level | Description |
|---|---|---|
fm_originate_call |
write | Click-to-call: ring an extension, connect to destination |
fm_hangup_call |
write | Hang up a specific channel |
fm_transfer_call |
write | Transfer a live call to another extension |
fm_park_call |
write | Park a live call |
fm_monitor_call |
write | Start recording a live call |
fm_stop_monitor_call |
write | Stop recording a live call |
fm_mute_call |
write | Mute or unmute a channel |
| Tool | Level | Description |
|---|---|---|
fm_queue_add_agent |
write | Add agent to queue dynamically |
fm_queue_remove_agent |
write | Remove agent from queue |
fm_queue_pause_agent |
write | Pause or unpause a queue agent |
fm_queue_status |
read | Real-time queue status |
| Tool | Level | Description |
|---|---|---|
fm_conference_participants |
read | List participants in a live conference |
fm_conference_kick |
write | Kick a participant |
fm_conference_mute |
write | Mute or unmute a participant |
fm_conference_lock |
write | Lock or unlock a conference room |
| Tool | Level | Description |
|---|---|---|
fm_pjsip_qualify |
read | Ping/qualify a PJSIP endpoint |
fm_pjsip_registrations |
read | List all inbound and outbound SIP registrations |
fm_pjsip_endpoint_details |
read | Deep endpoint health check — auth, transport, codecs, contacts, qualify |
fm_pjsip_show_channels |
read | Active SIP channels with codec/media stats |
fm_extension_states |
read | BLF/presence state for all extensions |
fm_rotate_logs |
admin | Rotate Asterisk log files |
| Tool | Level | Description |
|---|---|---|
fm_sip_trace |
admin | Time-bounded SIP trace capture (start/stop/status, max 30s) |
fm_diagnose_extension |
read | Composite diagnostic — endpoint + qualify + active calls + CDR + summary |
fm_diagnose_trunk |
read | Composite diagnostic — registration + qualify + routes + CDR + summary |
| Tool | Level | Description |
|---|---|---|
fm_astdb_get |
read | Read a value from the Asterisk database |
fm_astdb_put |
admin | Write a value to the Asterisk database |
| Tool | Level | Description |
|---|---|---|
fm_start |
admin | Start FreePBX and Asterisk |
fm_stop |
admin | Stop FreePBX and Asterisk |
fm_restart |
admin | Restart FreePBX and Asterisk |
fm_enable_trunk |
write | Enable a trunk |
fm_disable_trunk |
write | Disable a trunk |
fm_validate |
admin | Run security validation scan |
fm_chown |
admin | Fix file ownership/permissions |
fm_get_external_ip |
read | Get public IP address |
fm_sync_userman |
admin | Sync User Manager with external directory |
fm_system_update |
admin | Check for and apply system updates |
fm_update_activation |
admin | Refresh system activation and license from Sangoma portal |
| Tool | Level | Description |
|---|---|---|
fm_list_notifications |
read | List system notifications |
fm_delete_notification |
admin | Delete a notification |
fm_list_sounds |
read | List installed sound/language packs |
| Tool | Level | Description |
|---|---|---|
fm_pm2_manage |
admin | Restart or stop a PM2 process |
fm_update_certificates |
admin | Update/renew all SSL certificates |
fm_show_context |
read | Show any Asterisk dialplan context |
| Tool | Level | Description |
|---|---|---|
fm_save_query |
write | Save a named GraphQL query (validates parse) |
fm_run_saved_query |
read | Execute a saved query |
fm_list_saved_queries |
read | List all saved queries |
fm_delete_saved_query |
write | Delete a saved query |
| Tool | Level | Description |
|---|---|---|
fm_audit_search |
read | Search the audit log |
fm_list_permissions |
admin | List user permission levels |
fm_set_permission |
admin | Set a user's permission level |
| Tool | Level | Description |
|---|---|---|
fm_system_dashboard |
read | Quick system status — calls, extensions, notifications, uptime |
fm_search |
read | Search across extensions, ring groups, queues, IVRs, trunks |
fm_search_docs |
read | Search knowledge base — troubleshooting guides, how-to articles |
fm_trace_call_flow |
read | Trace call flow path for a DID or extension — Mermaid.js diagram |
The chat parser maps natural-language phrases to tools. A non-exhaustive sample:
| Phrase | Routes to |
|---|---|
add ext 1010 name "Jane" |
fm_add_extension |
add ext 1010 name "Jane" email jane@x.com |
fm_add_extension (with email + userman user creation) |
add ext 1010 name "Jane" with voicemail |
fm_add_extension then voicemail follow-up |
set email 1010 jane@x.com / email 1010 jane@x.com |
fm_set_extension_email |
enable voicemail 1010 / disable voicemail 1010 |
fm_enable_voicemail / fm_disable_voicemail |
list extensions, list ring groups, list trunks |
corresponding fm_list_* |
who's on the phone / live calls |
fm_whos_on_the_phone |
status, dashboard, how's the pbx |
fm_system_dashboard |
disk space, sys info |
corresponding read tools |
stats, peak hours, failed calls, busiest extensions |
CDR analytics |
update activation / refresh license |
fm_update_activation |
list certificates, update certificates |
fm_list_certificates / fm_update_certificates |
trace flow 1010 / where does 5551234 go |
fm_trace_call_flow |
did map / inbound map / where do my dids go |
fm_did_destination_map (Mermaid flowchart of every DID and where it lands) |
search jane / find queue 600 |
fm_search |
kb voicemail setup / how do i add a trunk / troubleshoot one-way audio |
fm_search_docs (knowledge base) |
Question ending in ? |
falls through to KB search |
yes / no |
confirms or cancels a pending action / follow-up |
skip / cancel |
aborts a free-text input prompt |
Type help in the chat to see the full list.
Follow-up chains: after add extension, the parser asks about voicemail; after voicemail enables, asks about email (with a clickable Skip and free-text input); after email, asks to apply changes. Click the ✅ Yes / ❌ No / ⏭ Skip pills or just type the answer.
# Interactive chat console (same commands as the web console)
fwconsole frogman:chat
# List all tools
fwconsole frogman:tool
# Run a tool
fwconsole frogman:tool fm_list_extensions '{}'
fwconsole frogman:tool fm_get_extension '{"ext":"1001"}'
# Write tools require confirm
fwconsole frogman:tool fm_add_extension '{"ext":"1002","name":"Jane","confirm":true}'See INTEGRATION.md for the full integration guide — authentication, token management, and examples for bots and web apps.
# Tool catalog (requires auth for remote, localhost bypasses)
curl http://localhost/admin/ajax.php?module=frogman&command=catalog
# Execute a tool
curl -X POST \
-H "Content-Type: application/json" \
-d '{"tool":"fm_list_extensions","params":{}}' \
http://localhost/admin/ajax.php?module=frogman&command=toolFrogman registers queries and mutations under the frogman_* namespace:
Queries: frogmanAuditLog, frogmanSavedQueries, frogmanSessions, frogmanAliases
Mutations: addFrogmanAlias, removeFrogmanAlias, addFrogmanSavedQuery, removeFrogmanSavedQuery
Scopes: read:frogman, write:frogman
The built-in web console at Admin > Frogman provides a chat interface for controlling the PBX with natural language.
Conversational flows — write operations ask for confirmation, then offer related follow-ups:
You: create extension 1010 for Mike White
Bot: Would create extension 1010 (Mike White) as PJSIP.
Reply yes to confirm or no to cancel.
You: yes
Bot: Extension 1010 (Mike White) created successfully.
Would you also like to enable voicemail for 1010?
You: yes
Bot: Voicemail enabled on extension 1010.
Would you like to apply the changes now?
You: yes
Bot: Configuration reload completed.
Combo commands — chain related actions in a single command:
create extension 1010 and voicemail for Mike White
create extension 1010 for Mike White with voicemail
create extension 1010 for Mike White and forward to 5551234
create extension 1010 for Mike White and ringgroup 600
Destructive actions get a warning:
You: delete extension 1010
Bot: ⚠️ This will delete extension 1010 (Mike White). This removes the device and user config.
Reply yes to confirm or no to cancel.
Other features:
- Up/down arrow key command history
- Quick view buttons in the sidebar (alphabetical)
- SIP Troubleshooting section with one-click diagnostics
- Whimsical error messages instead of generic "Error:"
Control your PBX from Discord with natural language. Type !create extension 1005 for Bob Smith, reply yes to confirm.
See DISCORD.md for the full setup guide.
The MCP server runs as a standalone PHP process and proxies tool calls to the FreePBX ajax endpoint. This is where the real power is — any AI can control and diagnose the PBX through MCP.
# Run directly
php /var/www/html/admin/modules/frogman/mcp-server.php
# Claude Desktop config (~/.claude/claude_desktop_config.json)
{
"mcpServers": {
"frogman": {
"command": "ssh",
"args": ["root@YOUR_FREEPBX_HOST", "php",
"/var/www/html/admin/modules/frogman/mcp-server.php"]
}
}
}Frogman ships with curated troubleshooting and how-to documentation in docs/. The fm_search_docs tool searches these articles by keyword and returns relevant sections.
Through MCP, this enables RAG (Retrieval-Augmented Generation):
- You ask: "Why doesn't extension 101 work?"
- AI runs diagnostics:
fm_diagnose_extension— checks registration, calls, CDR - AI searches docs:
fm_search_docs— finds relevant troubleshooting articles - AI reasons over both and gives you an actionable answer
No LLM runs on the PBX — Frogman handles the retrieval, the AI handles the reasoning. The knowledge base is 40KB of markdown files with zero server overhead.
In the web console, users can also search docs directly:
how to fix NAT
troubleshoot one way audio
kb registration failure
docs firewall
frogman/
├── module.xml # Module metadata, dependencies, DB schema
├── Frogman.class.php # BMO class — audit log, tool registry, HTTP endpoints
├── install.php # Post-install hooks (minimal)
├── uninstall.php # Cleanup hooks (minimal)
├── page.frogman.php # Admin GUI page (display=frogman)
├── mcp-server.php # MCP protocol server (stdio JSON-RPC)
├── mcp-config.example.json # Claude Desktop config example
├── Api/
│ └── Gql/
│ └── Frogman.php # GraphQL types, queries, mutations
├── Console/
│ ├── Tool.class.php # fwconsole frogman:tool command
│ └── Chat.class.php # fwconsole frogman:chat interactive console
├── Tools/
│ ├── AbstractTool.php # Base class for all tools
│ ├── GetExtension.php # ... (210 tool implementations)
│ └── ...
├── docs/ # Knowledge base articles (markdown)
├── views/
│ └── main.php # Admin page view
├── assets/
│ ├── css/
│ └── js/
└── i18n/
Frogman is developed collaboratively with AI assistance. AI is used for code generation, refactoring, testing, debugging, documentation, and architecture decisions. All code is reviewed, tested, and deployed by a human developer.
Frogman welcomes contributions — including vibe-coded ones. If you used AI to help write your PR, that's great. Just make sure it works, follows the existing patterns, and you've tested it.
See CLAUDE.md for codebase conventions and how to add new tools.
This software is experimental and provided as-is with no warranty of any kind. Use at your own risk.
Copyright (c) 2026 Sangoma Technologies
Licensed under the Affero General Public License (AGPL).
See LICENSE for the full license text.
This project uses FreePBX, Asterisk, and Frogman.
FreePBX and Asterisk are registered trademarks of Sangoma Technologies.