MCP technical details
For developers and app reviewers: server URL, OAuth, scopes, confirmations, limits and errors.
For developers building or reviewing an MCP client. To connect Claude or ChatGPT, see Use Wafeq with Claude or ChatGPT.
| Setting | Value |
|---|---|
| Server URL | https://mcp.wafeq.com/mcp |
| Transport | Streamable HTTP, stateless, JSON responses |
| Authentication | OAuth 2.1 (API keys don't work here) |
| Scopes | mcp.read (always granted), mcp.write |
| Tools | See the tool reference |
Authentication
Wafeq follows the MCP authorization spec.
| What | URL |
|---|---|
| Protected resource metadata | https://mcp.wafeq.com/.well-known/oauth-protected-resource/mcp |
| Authorization server metadata | https://app.wafeq.com/.well-known/oauth-authorization-server/oauth2/mcp |
| Issuer | https://app.wafeq.com/oauth2/mcp |
Take the authorize, token, registration and revocation endpoints from the authorization server metadata, with their trailing slashes.
- Register with a Client ID Metadata Document (an HTTPS URL as
client_id) or dynamic client registration (RFC 7591). - Authenticate with
token_endpoint_auth_methodnone(the default) orprivate_key_jwt, signed with ES256 or RS256 keys fromjwks_uriorjwks. Wafeq issues no client secrets. - PKCE
S256is required. resource=https://mcp.wafeq.com/mcpis required on the authorization request and code exchange. On a refresh it's optional, but must match.isscomes back on the redirect (RFC 9207).- Redirect URIs match exactly. Loopback
httpURIs may differ only in port. - Scopes: no scope requested means both. Without
mcp.write, write tools are hidden, and calling one returns HTTP403withWWW-Authenticate: Bearer error="insufficient_scope". Authorize again withmcp.writeto get write access.
| Token | Lifetime |
|---|---|
| Authorization code | 10 minutes |
| Access token | 1 hour |
| Refresh token | Rotates on every use. A replaced token is refused, and reusing it after 60 seconds ends the connection. |
| Connection | 90 days from approval, then the user connects again |
A connection stops working while the user is deactivated or in none of the shared organizations, and ends when they change their password. Members with the Integrations permission can see each connection on the Integrations page in Wafeq and disconnect it there.
Permissions and confirmations
- Tools follow the user's role and the organization's plan. Call
get_capabilitiesfirst for the shared organizations, then with anorganization_idto see which tools work there. Passorganization_idon every other call. - No tool moves money.
create_paymentonly records a payment. - Thirteen tools can ask before acting, including
send_invoice,report_invoice,void_invoice,merge_contactsanddelete_branch. They return asummary,warningsand aconfirmation_token. Show these to the user, and if they agree, repeat the same call withconfirmation_tokenadded. The token lasts 10 minutes. - Those thirteen and every
delete_*tool can't be undone.report_*andvoid_invoicereport to ZATCA or the FTA when the organization is connected; only a credit note reverses that. - Pass a new UUID as
idempotency_keywherever a tool accepts it, and reuse it when retrying.
Limits and errors
Each Wafeq user gets 120 read and 30 write calls per minute, shared across all their connected apps. Lists return up to 100 rows per page.
A failed call returns isError: true with a text block of JSON: {"code", "retryable", "message"}. Retry only when retryable is true.
| Code | Retry? |
|---|---|
invalid_arguments, invalid_request, not_found | Yes, with fixed arguments |
rate_limited | Yes, after the wait in the message |
permission_denied, plan_upgrade_required, record_locked, not_possible | No |
internal_error | No. After a write, read the record: it may have been saved. |
Requests with an Origin header other than https://app.wafeq.com get 403 Forbidden Origin, so browser-based clients can't connect.
Support
Updated about 1 hour ago