Skip to content

Black Friday:

60% off

Cliedesk Pro

Every plan, every site count. Ends Cyber Monday.

00 days 00 hrs 00 min 00 sec
Claim 60% off

Developers

MCP (Cliedesk Pro)

This guide covers a feature of Cliedesk Pro. The free plugin is a complete help desk; see what Pro adds.

§6.7, §16. Tests: tests/phpunit/pro/mcp/, cliedesk-pro/app/__tests__/Mcp.test.tsx.

Like the Public API, every MCP endpoint exists only while Cliedesk Pro runs with a valid licence. Otherwise WordPress answers 404 rest_no_route. With MCP switched off (pro_mcp.enabled), every MCP route is 404.

Transport

All three endpoints speak MCP Streamable HTTP, protocol 2025-11-25 (also 2025-06-18 and 2025-03-26):

  • POST with Content-Type: application/json; the answer is always JSON (no SSE). GET and DELETE answer 405.
  • Stateless: no Mcp-Session-Id. Every request is authenticated on its own.
  • JSON-RPC 2.0, batches of at most 10 messages. Notifications get no answer; a body of only notifications answers 202 with no body.
  • initialize answers the client’s version when supported, else the newest. Other requests may send MCP-Protocol-Version; an unsupported value answers 400 with error.data.supported.
  • Methods: initialize, ping, tools/list, tools/call. Capabilities: tools (listChanged: false) only.
  • An Origin header must be the site (same scheme, host and port) or an origin in pro_api.oauth_allowed_origins (DNS-rebinding protection), else 403 FORBIDDEN_ORIGIN.
  • Tool results have structuredContent (the Public API representation: snake_case, prefixed ids such as conv_…) and a text block with the same JSON. Errors are results with isError: true and structuredContent.error.code (the Public API error codes). An unknown tool is JSON-RPC error -32602.

Team server: POST /wp-json/cliedesk-api/v1/mcp

  • Credentials: an OAuth 2.1 access token (cdk_oat_…, the person who consented) or an API key, in Authorization: Bearer. Scopes mcp:read (read tools) and mcp:write (write tools). The owner needs the capability cliedesk_use_mcp (Admin, Supervisor and Agent by default). Without a credential: 401 with WWW-Authenticate: Bearer resource_metadata="…/oauth/protected-resource".
  • Tools (CliedeskPro\Modules\Mcp\Tools) are Public API endpoints run through ApiServer::dispatch, so the person’s capabilities, product scope, record rules, PII masking and money limits apply as on the API. Default set: me, search, conversations_list, conversation_get, conversation_messages, conversation_reply, conversation_note_add, conversation_status_set, conversation_priority_set, conversation_assign, conversation_tag, contact_search, contact_get, contact_conversations, contact_records (record sources such as woo_order), contact_update, article_search, article_get, article_create_draft, article_update_draft (drafts only), saved_reply_search, saved_reply_render, macro_run, report_metrics, report_overview, report_series, approval_get, job_get.
  • Add-on Actions flagged mcp with an api_scope become tools named like the Action (. → _), off until an admin switches them on. Settings, keys, roles, approval decisions, erasure, licence and vault never become tools.
  • tools/list shows only what the credential can use: switched on, the owner may run the Action, mcp:write and read-only off for write tools. Write tools in read-only mode answer READ_ONLY; without mcp:write INSUFFICIENT_SCOPE.
  • Approvals (§7.4, MCP column): tools whose Action is customer_visible, destructive or touches_money create an approval through the cliedesk_action_gate filter instead of running. The result is {"status": "approval_pending", "approval_id": "appr_…"}; the Action runs once, as the person, when someone with Answer approvals approves. Governance can set a tool to auto; money tools always ask. Test keys (cdk_test_) run writes as dry runs and create no approval.
  • Steps (Actions a tool call starts on the side, such as macro steps): a macro_run (or a note with macro steps) whose steps would need approval becomes one approval for the whole macro. Inside a tool call, any other Action that needs approval is refused (cliedesk_mcp_approval_required). Steps need approval when they are customer_visible, destructive or touches_money, and also csat.send, conversation.cc.add, conversation.requester.set and every connector.* Action. Tool overrides never apply to steps.
  • article_update_draft refuses a scheduled (future) article or a scheduled update draft: it would go live without review.
  • Every tool result except me, report_*, approval_get and job_get carries "untrusted": true at the top, and every object in it (messages, conversations, contacts, search hits) carries "untrusted": true: their text can be written by customers.
  • Limits: the credential’s Public API buckets plus per client (oauth:{client} or key:{id}) 120 tool calls and 20 writes per minute (pro_mcp.client_calls_per_min, client_writes_per_min, overrides in pro_mcp.clients). A suspended client answers 403 CLIENT_SUSPENDED.

Public knowledge: POST /wp-json/cliedesk-api/v1/mcp/public

Off by default (pro_mcp.public_enabled; off answers 404). No credential. Tools help_search {query, limit} and help_article_get {id} over published articles whose effective visibility is public (an article in an internal or signed-in category is not public). 30 calls per minute per IP and 600 for the site (public_ip_per_min, public_site_per_min); over the limit: HTTP 429 with Retry-After. Answers are cached 5 minutes.

Customer server: POST /wp-json/cliedesk-api/v1/mcp/customer/{brand_slug}

Off by default, switched per brand (pro_mcp.customer_enabled, layers workspace and brand; off answers 404).

  • Sign-in: each brand has its own issuer …/mcp/customer/{brand_slug} with …/protected-resource, …/metadata (also …/.well-known/oauth-authorization-server below the issuer and the RFC 8414 path-inserted form) and …/authorize. Token, registration and revocation are the shared /oauth/* endpoints. The authorize endpoint sends the browser to a consent page on the site (/?cliedesk_mcp_consent={brand_slug}&…); the customer signs in with their WordPress account. Scopes customer:read, customer:write; resource must be the brand’s customer URL.
  • The grant is bound to the customer’s contact and the brand (cliedesk_pro_mcp_customer_grants). Only such tokens work here, only for their brand; team tokens and API keys answer 401. Customer tokens never open the team server or the Public API.
  • Contact link: a WordPress account’s email is not proven. The account’s contact is used only when its address is verified there, Cliedesk made the contact for this account (user meta cliedesk_pro_mcp_contact), or the contact does not hold the account’s address. A contact linked only by an unverified address (Free links on sign-up and sign-in) is refused with access_denied; the team can verify the address. With no linked contact, a contact that holds the address unverified is not used: the account gets a new contact without the address.
  • Tools: my_conversations_list, my_conversation_get, request_create (a conversation on channel and source API, with normal triage, routing, SLA and escalation; an optional summary from the assistant of what it tried becomes a team note marked as the assistant’s), message_add, my_orders_list and order_status (the woo_order record source, by the account and its verified emails), help_search. Every lookup is by the token’s contact; another customer’s id answers NOT_FOUND. 60 calls per minute per contact.

MCP client (AI tools from other MCP servers)

Servers and McpClient: admins connect servers (Settings → Developer → MCP servers for AI). Auth none, bearer, basic or OAuth (access token with optional refresh token, token URL and client id; refreshed once on 401). Secrets are in the vault (pro_mcp.srv.{uid}.token|password|refresh|signing). Changing the URL or the token URL removes every saved secret that is not sent again in the same change, so secrets never go to a new address. Optional signing header Cliedesk-Signature: t={unix},v1={hex HMAC-SHA256(secret, t + "." + body)} and X-Cliedesk-Conversation-Id. Requests go through SafeHttp (SSRF guard, HTTPS, no redirects), timeout 30 s (at most 60 s), answers up to 256 KiB, JSON or SSE.

Import calls initialize, notifications/initialized and tools/list (with Mcp-Session-Id when the server sets one). Tools are stored in cliedesk_pro_mcp_tools switched off, autonomy off, kind write, approval on, no exposure; the server’s annotations are kept as hints only. Switching a tool on approves its definition hash; a later import with another hash switches it off (changed). The daily job cliedesk_pro_mcp_refresh imports again. After 5 failures in a row a server’s tools are hidden from the AI for 15 minutes. The AI agent calling these tools through the AI gateway comes with the AI gateway (M5) and the AI tool registry.

Governance, log and CLI

Settings of pro_mcp (versioned and audited): enabled (on), read_only (on), public_enabled (off), customer_enabled (off), limits, tools (per-tool enabled and autonomy), clients (per-client calls, writes, suspended), log_days (30). OAuth registration and the client limit stay pro_api.oauth_registration and pro_api.oauth_client_limit; POST cliedesk/v1/mcp-governance/oauth sets them and purges unused clients.

The call log cliedesk_pro_mcp_calls keeps per request method: surface, client, credential, user or contact, tool, result (ok, error, denied, approval, rate_limited), error code, duration, request id; never arguments, answers or tokens. Purged daily (cliedesk_pro_mcp_purge). Each tool call is also an audit entry mcp.tool_called (via mcp).

wp cliedesk mcp status [--format=json]
wp cliedesk mcp on | off
wp cliedesk mcp read-only on|off
wp cliedesk mcp tools [--enabled] [--format=json]
wp cliedesk mcp refresh-servers