V20 Update 10 Alpha: MCP, AI Server & More Admin Control

N_G

Founder
Joined
Jun 6, 2006
Messages
4,863
Reaction score
9,319

Connect AI assistants, deploy dedicated AI infrastructure, build real-time voice applications and gain more control over administration, privacy and integrations.​

V20 Update 10 Alpha makes 3CX a more open and programmable business communications platform. Rather than simply adding new AI features, this release enables external AI assistan...
Continue reading the Original Blog Post.
 
Nice! Thanks for restoring support for the Yealink Android phones. Also the new permission to view recordings is a great addition, especially for call center customers.

I'm off to the basement now to try out the MCP integration... see you in a few days! ;)xD
 
Last edited:
My top 3 of this alpha :

- Music on hold by department
- Users with multiple assigned DIDs can now choose which number to use when placing an outbound call from supported 3CX Apps
- Separate permissions for reports and call recordings.


What a big update, odoo integration is really cool too !
Thank you 3CX.
 
Nick, this is absolutely huge. These new features are going to propel 3CX into a truly enterprise ready communications system. I think the decision it to build the tools that developer can use to integrate all of their systems into 3CX is a much better path than forcing enterprise to conform to something you've created.

You have no idea how excited I am to start building out applications for this.

Bravo to the entire 3CX team! Can't wait to see what we all create!
 
Wow amazing update which I can't wait to start testing.
Adding all these features is making 3CX standout from other competitors. As @dallaskincaid said, building the tool for developers is the way to go!

Adding moh per department is huge.
 
Great release 3CX Team!

Just to confirm, Department-specific Music on Hold - this is on hold only and not Park?

For the "Users with multiple assigned DIDs can now choose which number to use when placing an outbound call from supported 3CX Apps." - I don't see any options in the PWA or iOS app as yet - is this something which needs to be enabled first? I couldn't see any obvious places to enable.

Thanks as always :) Lots to play with.

Best
Lance
 
For the "Users with multiple assigned DIDs can now choose which number to use when placing an outbound call from supported 3CX Apps." - I don't see any options in the PWA or iOS app as yet - is this something which needs to be enabled first? I couldn't see any obvious places to enable.
Answered my own question. Looks like PWA is good, Mobile will no doubt come in time. 1785450317339.png
 
Last edited:
Just to confirm, Department-specific Music on Hold - this is on hold only and not Park?
Yes music on hold only, if a call is parked it uses the music on hold that you set within System —- Call Parking —- Music on hold file for parked calls.
 
Yes music on hold only, if a call is parked it uses the music on hold that you set within System —- Call Parking —- Music on hold file for parked calls.
What if the park spots are assigned to a department? Will that play department moh?
 
Hello Alejandro-

As mentioned internal calls to an AI agent answer normally. External calls to an AI agent produce the AI Bridge error in 3CX Event Viewer.

Here is the failed external call in 3CX AI log.

Id: 28
sdpType: WRTCConfirmed
other_party_displayname: "RYAN FISHER"
other_party_number: "+12488xxxxxx"
transactionId: 1
sdp: ""
SIPDialogID: "OzSmLAi_BRcjMK5fNA1_zQ..0e5089cbe"

2026-07-30 15:21:16.884|Trace|{'call': 28, 'dir': 'ai'} RTCPeerConnection() iceGatheringState gathering -> complete
2026-07-30 15:21:16.885| Info|{'call': 28, 'dir': 'ai'} OpenAI request: POST https://api.openai.com/v1/realtime/calls client_secret_hash=785d7ef6c52bd3bf888be48713532502a63182e82d91f5920b3e0fe85544b291
2026-07-30 15:21:16.893|Trace|{'call': 28, 'dir': 'pbx'} RTCIceTransport(controlling) - checking -> completed
2026-07-30 15:21:16.893|Trace|{'call': 28, 'dir': 'pbx'} RTCPeerConnection() iceConnectionState checking -> completed
2026-07-30 15:21:16.895|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) - State.NEW -> State.CONNECTING
2026-07-30 15:21:16.901|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) x DTLS handshake negotiated SRTP_AEAD_AES_256_GCM
2026-07-30 15:21:16.902|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) - DTLS handshake complete
2026-07-30 15:21:16.902|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) - State.CONNECTING -> State.CONNECTED
2026-07-30 15:21:16.902|Trace|{'call': 28, 'dir': 'pbx'} RTCPeerConnection() connectionState connecting -> connected
2026-07-30 15:21:16.903| Info|{'call': 28, 'dir': 'pbx'} endpoint_pc.state > connected
2026-07-30 15:21:16.978| Info|{'call': 28} Connected
2026-07-30 15:21:17.070| Info|{'call': 28, 'dir': 'ai'} OpenAI response: https://api.openai.com/v1/realtime/calls (500) http_version=HTTP/2 openai_call_id=/v1/realtime/calls/rtc_u1_E7Qbc321dEAa855sNOyBa request_id=None cf_ray=a236b9b88df2d66f-IAD
2026-07-30 15:21:17.071| Info|{'call': 28, 'dir': 'ai'} realtime/calls conn: http_version=HTTP/2 local_addr=('10.0.0.22', 58932) server_addr=('172.66.0.243', 443)
2026-07-30 15:21:17.071|Error|{'call': 28, 'dir': 'ai'} realtime/calls error body: retry_after=None body=Internal Server Error
2026-07-30 15:21:17.072|Error|{'call': 28} [FATAL] AI Session entered fatal error state: Failed to start AI session: Server error '500 Internal Server Error' for url 'https://api.openai.com/v1/realtime/calls'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500
2026-07-30 15:21:17.072| Warn|{} extract_call_api_error_message: unparsable HTTP error body: Internal Server Error
2026-07-30 15:21:17.072| Info|{} PBX eventlog report requested: type=fatal_error msg=Internal Server Error
2026-07-30 15:21:17.072| Info|{} PBX eventlog report SUPPRESSED (aggregated within window): type=fatal_error msg=Internal Server Error
2026-07-30 15:21:17.073| Info|{'call': 28} fatal fallback isn't configured: drop the call
2026-07-30 15:21:17.073|Debug|{'u': '1026'} Send RequestDropCall
2026-07-30 15:21:17.091|Debug|{'call': 28} PBX call closed, close scheduled
2026-07-30 15:21:17.091|Debug|{'call': 28} Closing the call
2026-07-30 15:21:17.091|Debug|{'call': 28} Closing endpoint_pc
2026-07-30 15:21:17.092|Debug|{'call': 28, 'dir': 'pbx'} Closing super
2026-07-30 15:21:17.093|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) - DTLS shutdown complete
2026-07-30 15:21:17.093|Trace|{'call': 28, 'dir': 'pbx'} RTCDtlsTransport(client) - State.CONNECTED -> State.CLOSED
2026-07-30 15:21:17.093|Trace|{'call': 28, 'dir': 'pbx'} RTCPeerConnection() connectionState connected -> closed
2026-07-30 15:21:17.093| Info|{'call': 28, 'dir': 'pbx'} endpoint_pc.state > closed
2026-07-30 15:21:17.094| Warn|{'call': 28, 'dir': 'pbx'} Endpoint PC lost connection; forcing idle & closing bridge
2026-07-30 15:21:17.094|Debug|{'call': 28, 'dir': 'pbx'} StunProtocol(Connection(9))#9 Socket RELEASED 10.0.0.22:59321 (close())
2026-07-30 15:21:17.095|Trace|{'call': 28, 'dir': 'pbx'} RTCIceTransport(controlling) - completed -> closed
2026-07-30 15:21:17.095|Trace|{'call': 28, 'dir': 'pbx'} RTCPeerConnection() iceConnectionState completed -> closed
2026-07-30 15:21:17.096|Debug|{'call': 28, 'dir': 'pbx'} Closing complete
2026-07-30 15:21:17.097|Debug|{'call': 28} Closing ai leg
2026-07-30 15:21:17.097| Info|{'call': 28, 'dir': 'ai'} downlink gate OPENED
2026-07-30 15:21:17.097| Info|{'call': 28, 'dir': 'ai'} OpenAI call CLOSE: openai_call_id=None
2026-07-30 15:21:17.098|Debug|{'call': 28, 'dir': 'ai'} Closing super
2026-07-30 15:21:17.098|Debug|{'call': 28, 'dir': 'ai'} StunProtocol(Connection(10))#11 Socket RELEASED 10.0.0.22:48147 (close())
2026-07-30 15:21:17.099|Trace|{'call': 28, 'dir': 'ai'} RTCIceTransport(controlling) - new -> closed
2026-07-30 15:21:17.099|Trace|{'call': 28, 'dir': 'ai'} RTCPeerConnection() iceConnectionState new -> closed
2026-07-30 15:21:17.099|Trace|{'call': 28, 'dir': 'ai'} RTCPeerConnection() connectionState new -> closed
2026-07-30 15:21:17.099|Debug|{'call': 28, 'dir': 'ai'} StunProtocol(Connection(11))#10 Socket RELEASED 10.0.0.22:57582 (close())
2026-07-30 15:21:17.100|Trace|{'call': 28, 'dir': 'ai'} RTCIceTransport(controlling) - new -> closed
2026-07-30 15:21:17.102|Debug|{'call': 28, 'dir': 'ai'} Closing complete
2026-07-30 15:21:17.102| Info|{'call': 28} transcript is enabled: True
2026-07-30 15:21:17.102| Info|{'call': 28} announcement type is: None, email extension is:
2026-07-30 15:21:17.103| Info|{'call': 28} USAGE CALL: {'duration_s': 1.0381203321740031, 'realtime': {'total_tokens': 0, 'input_tokens': 0, 'output_tokens': 0, 'input_text_tokens': 0, 'input_audio_tokens': 0, 'input_text_cached_tokens': 0, 'input_audio_cached_tokens': 0, 'output_text_tokens': 0, 'output_audio_tokens': 0, 'responses_count': 0, 'context_window_size': 0, 'model': 'gpt-realtime-2'}, 'transcription': {'usage_type': None, 'total_tokens': 0, 'input_tokens': 0, 'output_tokens': 0, 'input_text_tokens': 0, 'input_audio_tokens': 0, 'duration_seconds': 0, 'events_count': 0, 'model': 'gpt-realtime-whisper'}, 'analysis': {'total_tokens': 0, 'input_tokens': 0, 'output_tokens': 0, 'runs_count': 0, 'by_model': {}}}

Hello @Ryan_Fisher_Techmode

What provider are you using for these external calls?

From the logs it seems that openai does not like something in how these calls are negotiated.

Things to try..

  1. Can you enable recording? Like this we force transcoding in case there is a codec incoming that openai does not like. \
  2. Can you get another VoIP Provider trunk (like callcentric) and call externally to understand if this is a provider specific issue or not.
  3. I can assure you that openai is A) Very permissive in what they support B) Handles SIP and WebRTC really well. We must have stumbled across a rare incompatability.
  4. Was this working before or is it the first time you try AI Agents?

    Contact me in PM And we will investigate together.

    God bless
 
I connected 3CX MCP to an AI agent and asked it to check for security risks. It found several IPs attempting attacks that hadn’t been blacklisted yet, so I simply told it to block them.

Amazing — this is next-level PBX management!
 
Alejandro-

If i change the behavior for AI fallback and that works as expected. The call fails and goes to the specified extension.
It doesn't change the fact that its still failing on external calls. I changed sip trunk provider and added a new DID and am getting the same results. I will move this conversation to a support ticket as to not clog up this forum post.

Curious if you tested using an external call on your test agents?
Same issue here. Is it possible that this is the same issue as the one with the AI Agents integration in U8 Alpha that was caused by the system "language/locale" settings?
 
  • Like
Reactions: nikolascx
I connected 3CX MCP to an AI agent and asked it to check for security risks. It found several IPs attempting attacks that hadn’t been blacklisted yet, so I simply told it to block them.

Amazing — this is next-level PBX management!

Nice one!!!
BTW - they were not blacklisted yet because the IP's did not yet reach the blacklist threshold. But cool that you did it for the server.
Great example - keep on exploring.. There are 29 tools in the mcp toolbox catalog for you to explore!!
 
Hi there,

With the recent enforcement of the extension-creation limit tied to the maximum allowed, we were wondering if there are any plans to add a feature to the 3CX portal (portal.3cx.com) that shows which customers have exceeded this limit?

We don't use external monitoring tools for our servers, so at the moment we have to log in to each PBX individually to check whether any of them have gone over the limit. Having this information available directly in the portal would make things much easier for us (and other partners).

Thanks in advance for any updates you can share!
 
Same issue here. Is it possible that this is the same issue as the one with the AI Agents integration in U8 Alpha that was caused by the system "language/locale" settings?

What is the provider you have? We need to see the logs.
If you call the AI from a local extension does it work?
You can contact me on pm on this case - I'm reserving some time today for the community..
 
  • Like
Reactions: Alejandro_3CX
Hi there,

With the recent enforcement of the extension-creation limit tied to the maximum allowed, we were wondering if there are any plans to add a feature to the 3CX portal (portal.3cx.com) that shows which customers have exceeded this limit?

We don't use external monitoring tools for our servers, so at the moment we have to log in to each PBX individually to check whether any of them have gone over the limit. Having this information available directly in the portal would make things much easier for us (and other partners).

Thanks in advance for any updates you can share!
Hey @Voiceking.be
As @nikolascx mentioned we do currently generate a warning message if you try to place an order on an existing subscription that has exceeded the limit.

We are actually planning to bring this visibility directly into the subscription list so that you can proactively filter or find these subscriptions without having to attempt placing an order first.
 
Im falling behind with the AI side of 3CX having touched none of it. Whats best for me to do as a starting point? I dont want to be stuck at the port waving the ship of as it leaves xD
 
This is a massive step forward for 3CX.

Native MCP support, the standalone 3CX AI Server, programmable voice applications, and greater administrative control are not simply new features, they are transforming 3CX into a much more flexible and enterprise ready communications platform.

Instead of forcing customers to adapt their operations to a fixed system, these capabilities will allow us to build around their actual business requirements.

We are genuinely excited to start testing these features and developing new solutions for our clients.

Shukran to Nick and the entire 3CX team. Update 10 looks like a major milestone, and we cannot wait to see what we can build with it.