Dynamic Client Registration for MCP clients doesn't seem to get "Persistent" status — client registration eventually forgotten

lars.wolle

Silver Partner
Joined
Jun 7, 2023
Messages
2
Reaction score
0
We're integrating the 3CX MCP Server into our own internal assistant application (used for live agent status, call reports, etc.). Authentication follows the standard OAuth flow the MCP server advertises: automatic discovery of the endpoints, then Dynamic Client Registration (RFC 7591, POST /connect/register), followed by an Authorization Code flow with PKCE.


The core issue: a client registered this way does not seem to get "Persistent" status on the 3CX side. After some period without use, a new authorization attempt using the existing client ID is rejected with something like "unknown client id or redirect url" — it looks like the entire client registration gets discarded server-side, not just the access/refresh token. At that point a plain refresh-token exchange is no longer enough; a completely new, interactive login by a human in the browser is required to re-register and re-authorize.


Observation on the likely cause​


When using the official claude.ai connector (CIMD flow), the 3CX login/consent page shows an option along the lines of "Persistent client" / "Override console restrictions". With our own MCP client (created via Dynamic Client Registration), that option never appears — presumably because our app isn't requesting/able to request a token with sufficiently long-lived/unrestricted validity. We already explicitly request the standard offline_access scope (even though the server doesn't advertise it in scopes_supported), but that doesn't seem to solve the underlying problem.


Current workaround​


To reduce the risk of the registration being "forgotten" due to inactivity, we currently request a valid access token (refreshing it via the refresh token if needed) automatically every 3 minutes — both while the app is running and via a separate, independent scheduled task as a fallback. That's only a workaround, not a reliable fix: we don't know after how long an unused registration is actually discarded by 3CX, so an occasional manual re-login is still sometimes necessary.


Questions for the community / 3CX AI team​


  1. Is there a way to give a client created via Dynamic Client Registration the same "Persistent" status that official connectors (e.g. claude.ai) seem to get — via a specific scope, registration parameter, or admin setting?
  2. If not: how long does an unused refresh token / client registration remain valid on the 3CX side before it's discarded?
  3. Is there a supported way for an internal server-to-server integration like ours to get a genuinely permanent, non-interactive credential for MCP access (e.g. an OAuth client with a client secret created manually in the admin area, with no expiry) instead of relying on a flow designed for interactive user logins that has to be kept alive and occasionally redone manually?

Happy to provide more detail — logs, timestamps of the last successful login, the client ID involved — if that helps with diagnosis.


Environment: Version 20.0 Update 10 (Build 1621 Alpha - AI 1.6.57) self-hosted







3cxMCP.pngUnbenannt.png
 
Solution
Hi there, some pointers for you...

DCR is essentially the WRONG way to go - it's not appropriate for service-to-service interactions. The appropriate flow to use is the "client_credentials" flow.

Use this flow for Service-to-service integration, implemented as follows:
  • Create a service principal:
    • Admin > Integrations > API > Add ; enable 3CX Configuration API Access; select the Department and Role for this service principal - it will determine the level of access that will be available to your application
    • Note that this is a "service" and NOT a "user" principal - user-centric functions (think along the lines of "give me a list of my voicemails") are not available, because your app is not a "user"
  • use the...
Hi

I'll try to look into this, and get back to you.
 
Hi there, some pointers for you...

DCR is essentially the WRONG way to go - it's not appropriate for service-to-service interactions. The appropriate flow to use is the "client_credentials" flow.

Use this flow for Service-to-service integration, implemented as follows:
  • Create a service principal:
    • Admin > Integrations > API > Add ; enable 3CX Configuration API Access; select the Department and Role for this service principal - it will determine the level of access that will be available to your application
    • Note that this is a "service" and NOT a "user" principal - user-centric functions (think along the lines of "give me a list of my voicemails") are not available, because your app is not a "user"
  • use the regular OAuth client_credentials flow, and request scope "mcp"
  • the resulting access token will now be able to access the "/mcp" endpoint
This will give you a "persistent" session.
 
  • Like
Reactions: KyriacosS_3CX
Solution
Hi Kevin,

Thanks again for the earlier guidance on switching from Dynamic Client Registration to the client_credentials flow with scope mcp — that fully resolved the "no Persistent client status" / invalid_grant issues we were hitting. The service principal now gets a token from /connect/token and calls the /mcp endpoint successfully, no browser redirect needed.


However, we've hit a follow-up problem: under the new service-principal connection, the MCP server's tools/list only returns these 8 tools:


list_peers, get_server_time, get_edit_url, find_extension, control_participant, find_by_email, list_crm_contacts, list_phonebook


None of these can set or query a queue agent's login/logout status (the equivalent of an agent toggling "logged in to queue X" in the 3CX client/console). Under our previous setup (Dynamic Client Registration + Authorization Code/PKCE, with an interactive user login), tools for exactly this purpose were available and worked correctly. After migrating to client_credentials, they disappeared from the tool list entirely — we tried assigning a different Department/Role to the service principal, but the tool list didn't change.


Our reading of your earlier reply is that this might be by design: you mentioned that "this is a 'service' and NOT a 'user' principal — user-centric functions ... are not available, because your app is not a 'user'." Setting an agent's own queue login status looks like exactly that kind of user-centric action.


Could you confirm:


  1. Is queue agent login/logout status intentionally excluded from the MCP tool set for service principals (client_credentials), regardless of the assigned Role?
  2. If so, is there a supported way for a service-to-service integration to read/set an agent's queue status — for example via the Configuration REST API (XAPI) instead of MCP? We already use XAPI successfully (client_credentials) for reporting and department/queue listing, so if there's an equivalent endpoint for queue membership/agent status there, that would work for us.
  3. If neither MCP nor XAPI can do this for a service principal, is a real user-context OAuth flow (Authorization Code, non-DCR, e.g. a statically registered app + real user login) the only supported path for this specific action, and if so, how would we register such an app without hitting the same DCR persistence problems as before?

Thanks a lot for the help so far — the client_credentials migration was a big improvement everywhere else.