Imported from yashodhank/whmcs-mcp-server (
AGENTS.md). Install upstream withnpx skills add yashodhank/whmcs-mcp-server. Copyright stays with the author.
Agent & contributor guide — WHMCS MCP Server
Concise orientation for AI agents and humans working in this repo. The full historical build specification lives in AGENT.md; operational runbooks live under docs/.
Read docs/OPERATIONS-HANDOFF.md for the authoritative product boundary, ownership model, repository placement, deployment limits, and the mandatory rule to update handoff documentation with every substantive change.
What this server is
- Transport: MCP over stdio (Cursor, Claude Desktop, Kilo, etc.). Logs go to stderr only; never write to stdout except JSON-RPC.
- Backend: WHMCS External API via
WhmcsClient(src/whmcs/). - Surface: 81 catalog tools (legacy WHMCS actions, list/reporting, aggregators, capability probes, controlled write-flow, agent-native write UX, planning,
ops_ask,mcp_doctor) plus 9 resource endpoints/templates. Production WHMCS baseline is 8.13.7.
Architecture (current)
MCP host → src/index.ts
├─ config / security / rateLimiter
├─ tools/* (zod schemas, outputSchema + structuredContent)
├─ governance/* (opt-in: consumer → canonical → project)
├─ catalog/* (typed operation metadata, validation, discovery)
├─ write/* (intent store, validation, execution gate, audit)
├─ planning/* (deterministic, non-executable PlanIR compiler)
├─ resources/* + playbook + compat-9x
└─ whmcs/WhmcsClient (compatibility facade)
├─ request/* (encode, transport, decode, classify, retry/repair)
└─ readCoordinator + cachePolicy (bounded safe-read acceleration)
Governance (Phase B, opt-in): Set MCP_GOVERNANCE_ENABLED=true and configure MCP_CONSUMER_REGISTRY (SHA-256 of bearer tokens only — never commit raw tokens). When off (default), legacy tool output paths remain for backward compatibility. See docs/design/governance.md.
Controlled writes (Phase F–G+): Mutations that bypass simple MCP_MODE=full use the write-flow tools (draft_write_intent → validate_write_intent → approve_write_intent → execute_write_intent). Production execution is deny-by-default unless explicitly allowlisted (MCP_PROD_WRITE_AUTHORIZED, caps, audit path). See docs/design/controlled-writes-phase-f.md (implemented; sealed by default) and docs/superpowers/specs/2026-05-19-whmcs-prod-write-RUNBOOK.md.
Tool families (where to edit)
| Family | Module | Examples |
|---|---|---|
| Legacy CRUD | clients.ts, billing.ts, orders.ts, services.ts, domains.ts, support.ts |
search_clients, get_invoice, suspend_service |
| Governed lists | listTools.ts, reportingListTools.ts |
list_client_invoices, list_invoices, list_services |
| Aggregators | aggregators.ts |
get_account_360, get_billing_snapshot |
| Capability / probes | capabilityShellTools.ts |
get_capability_matrix, get_stats, list_users (unverified) |
| Ticket read | ticketThreadTool.ts |
get_ticket_thread |
| Write flow | writeFlow.ts |
draft_write_intent, execute_write_intent |
| Write UX / posture | writeFlow.ts |
get_write_posture, prepare_domain_order |
Register new tools in the matching module, then wire registration from src/index.ts. Prefer zod input/output schemas and return structuredContent when outputSchema is declared (see tests/tools/outputSchemaCompliance.test.ts).
Resources (read-only URIs)
| URI | Purpose |
|---|---|
whmcs://clients/{clientid}/summary |
Client identity + counts |
whmcs://clients/{clientid}/log |
Recent client activity |
whmcs://invoices/{invoiceid}/history |
Invoice + transactions |
whmcs://tickets/{ticketid}/thread |
Ticket thread |
whmcs://system/activity |
Global activity (admin) |
whmcs://docs/ops-playbook |
Agent behavioral playbook |
whmcs://docs/compat-9x |
WHMCS 8.13 / 9.x compatibility notes |
whmcs://capabilities/v2 |
Versioned, filtered capability discovery |
Resources do not use auth_token query params; scope is process + MCP_ACCESS_MODE / client allowlist.
Configuration essentials
Copy .env.example. Required: WHMCS_API_URL, WHMCS_IDENTIFIER, WHMCS_SECRET.
WHMCS_API_URLmust be the base origin (https://host) — the client appends/includes/api.php. Setting the full endpoint doubles the path and WHMCS returns"An admin user is required"on every call. If you see that error, do NOT start with credentials/admins/roles/IP — run the URL-shape check in docs/runbooks/api-connectivity-troubleshooting.md §1 first (2-minute fix).WHMCS API 403 is one of: (1) edge/WAF/proxy or a stuck keep-alive socket (curl / a fresh process from the same IP works) — fix server-side, or reconnect the MCP for fresh sockets; the IP auto-heal can't; (2) IP not in
APIAllowedIPs(the only case auto-heal fixes); (3) permission/role ACL. The client surfaces a classified hint; see the runbook's "403 Forbidden — three distinct causes".
| Variable | Notes |
|---|---|
MCP_ENV |
Layers .env.<profile>; WHMCS_API_URL must be HTTPS unless WHMCS_ALLOW_HTTP=true (local stack only). |
MCP_MODE |
read_only (default), simulate, full — legacy direct mutators. |
MCP_ACCESS_MODE |
admin or scoped client + MCP_ALLOWED_CLIENT_IDS. |
MCP_GOVERNANCE_ENABLED |
Opt-in projection boundary. |
MCP_CONSUMER_REGISTRY |
JSON array with token_sha256 — see docs/reference/consumer-registry.example.md. |
MCP_CLIENT_CUSTOM_FIELD_LABELS |
id:label pairs for stable custom-field names in client output. |
MCP_PROD_WRITE_* / MCP_WRITE_* |
Production write authorizer, caps, audit/idempotency paths. MCP_PROD_WRITE_AUTHORIZED_FILE is the live owner-only JSON allowlist; edit it to change approved actions/scopes without restarting the MCP. |
MCP_DEFAULT_CONSUMER_AUTH_TOKEN |
Raw bearer token auto-injected for trusted stdio when auth_token is omitted. Never applied for HTTP. Local escape hatch only (ADR-0002.4). See docs/runbooks/grokbot-stdio-access.md. |
MCP_DEFAULT_APPROVER_CONSUMER_AUTH_TOKEN |
Raw bearer token auto-injected for approve_write_intent on trusted stdio. Must resolve to a DISTINCT consumer from the executor default. _FILE variant supported. See docs/runbooks/grokbot-stdio-access.md. |
MCP_STAFF_CONSUMER_IDS / MCP_STAFF_OIDC_SUBS |
Staff ops_ask allow-lists (consumer ids ∪ OIDC sub). Empty ⇒ nobody is staff. |
MCP_WHMCS_OIDC_ISSUER |
WHMCS origin rejected as an MCP Bearer issuer (defaults to WHMCS_API_URL origin). |
MCP_EFFECT_LEDGER_PATH |
JSONL {at,consumer_id,job,clientid,effect} — no payloads or tokens. |
WHMCS_HEAL_EXTRA_IPS |
Comma-separated extra IPs (e.g. Grok Bot egress) always included in IP allowlist heal. |
Auth layers (do not confuse)
Before proposing “WHMCS OAuth for MCP,” read docs/runbooks/auth-layers-whmcs-vs-mcp.md. Admin ops use API identifier/secret + MCP consumer tokens; WHMCS OpenID is client-area/SSO; MCP OAuth 2.1 RS is HTTP-roadmap only.
Scripts & verification
| Script | Purpose |
|---|---|
npm run build |
Produce dist/index.js (required before MCP hosts connect). |
npm run ci:node |
Local parity with GitHub build-test (lint/format/tests/catalog). |
npm test |
Vitest unit/integration suite. |
npm run mcp:test:production-program |
L0–L6 production test program. |
scripts/mcp-governed-smoke.mjs |
Governed read smoke. |
scripts/mcp-capability-probe.mjs |
Capability probe report. |
scripts/mcp-exposure-audit.mjs |
Exposure audit harness. |
scripts/whmcs-ip-updater/ |
Optional API IP allowlist updater (ops). |
Local dual-WHMCS stack: docs/runbooks/local-whmcs-testing.md. Operator troubleshooting: docs/runbooks/ai-agent-local.md.
Pre-push CI parity (matches GitHub build-test / related jobs): docs/runbooks/local-ci-parity-before-push.md.
Safety rules for agents editing this repo
- No secrets in git — credentials, registry tokens,
.env.local, prod seeds. - Preserve stdio contract — no
console.logon stdout; useLogger→ stderr. - Minimal diffs — match existing patterns in the tool module you touch.
- Tests — add/adjust Vitest for behavior changes; run
npm run ci:nodebefore PR (lint--max-warnings 0, format, tests, catalog contracts). - WHMCS 9 — invoice immutability and credit/debit notes: read docs/reference/whmcs9-credit-debit-notes.md before billing/write changes.
- Do not commit
.cursor/hooks/state/or other IDE-local paths. - Keep the handoff current — every code, governance, deployment, approval,
client-delivery, or review-finding change must update the relevant handoff
and audit record in the same work item. If a fact is unknown, mark it
PENDINGwith the exact owner or evidence needed; do not guess.
Documentation map
| Doc | When to read |
|---|---|
| README.md | Install, MCP config, tool catalog summary |
| docs/README.md | Full doc-map index (design / runbooks / reference / archive) |
| docs/design/governance.md | Consumer contracts & projection |
| docs/design/capability-catalog.md | Catalog metadata, evidence, discovery, and pack migration |
| docs/runbooks/capability-probe.md | Promoting verified capabilities |
| docs/design/controlled-writes-phase-i.md | Production write GO/NO-GO |
| docs/runbooks/production-test-program.md | Reliability / RCA test program |
| docs/reference/cursor-skills.md | Recommended Cursor skills |
| examples/README.md | structuredContent integration patterns |
| docs/runbooks/simple-writes.md | Default write model (governance off, destructive phrase) |
| docs/OPERATIONS-HANDOFF.md | Product boundary, ownership, runtime, release, and handoff checklist |
| docs/runbooks/auth-layers-whmcs-vs-mcp.md | WHMCS Admin API vs OpenID/OAuth vs MCP auth — read before "use OAuth for MCP" |
| docs/runbooks/grokbot-stdio-access.md | Grok Bot / Business WhatsApp stdio access setup |
Cursor / rules
- Repo-wide coding standards: .cursorrules
- WHMCS-specific Cursor rule: .cursor/rules/whmcs-mcp-server.mdc