Setup
Once you have a Personal Access Token (PAT), connecting an AI client to Waafir is a matter of adding each server you want to your client's MCP configuration and supplying the token. This page gives the connection URLs and ready-to-paste configuration for Claude Desktop and Cursor.
Connection URLs
Each Waafir MCP server has its own URL — the server name is part of the path. Point your client at the specific server you want:
| Server | URL |
|---|---|
waafir-redact | https://app.waafir.io/api/mcp/waafir-redact |
waafir-translate | https://app.waafir.io/api/mcp/waafir-translate |
waafir-dataroom | https://app.waafir.io/api/mcp/waafir-dataroom |
waafir-esign | https://app.waafir.io/api/mcp/waafir-esign |
Replace https://app.waafir.io with your Waafir base URL if you are on a
different deployment. There is no bare /api/mcp endpoint — the server name
segment is required, and a request without it returns a 404. Add one
configuration entry per server you intend to use; you do not have to add all
of them. Note waafir-esign is a paid offering
— without the E-Signatures add-on or an active subscription its URL answers
with an ADDON_NOT_PURCHASED error.
Authentication
Every request carries your PAT as a bearer token in the Authorization
header:
Authorization: Bearer waafir_pat_...How you supply that depends on the client, as shown below. Never commit a real token to a shared file or repository — treat it like a password.
Claude Desktop
Add an mcpServers entry per server to your Claude Desktop configuration,
passing the token in the Authorization header. Connecting the three servers
included with every plan looks like this — add waafir-esign the same way if
your organisation holds it:
{
"mcpServers": {
"waafir-dataroom": {
"url": "https://app.waafir.io/api/mcp/waafir-dataroom",
"headers": {
"Authorization": "Bearer YOUR_WAAFIR_PAT"
}
},
"waafir-redact": {
"url": "https://app.waafir.io/api/mcp/waafir-redact",
"headers": {
"Authorization": "Bearer YOUR_WAAFIR_PAT"
}
},
"waafir-translate": {
"url": "https://app.waafir.io/api/mcp/waafir-translate",
"headers": {
"Authorization": "Bearer YOUR_WAAFIR_PAT"
}
}
}
}Replace YOUR_WAAFIR_PAT with the token you copied at issuance. Keep only the
servers you need. Add-ons → Connect generates a copy-ready snippet for
you when you issue a token.
Cursor
Cursor takes the token from an environment variable rather than a literal
header. Add an mcpServers entry per server with the token under env:
{
"mcpServers": {
"waafir-dataroom": {
"url": "https://app.waafir.io/api/mcp/waafir-dataroom",
"env": {
"WAAFIR_PAT": "YOUR_WAAFIR_PAT"
}
}
}
}Add the waafir-redact and waafir-translate entries the same way, changing
only the server name in the URL.
Calling a tool
After connecting, your client lists the server's tools (an MCP tools/list)
and calls them on your behalf. You do not call tools by hand — you ask the AI
client to do something ("list the files in this data room", "translate this
paragraph into French") and it selects and calls the right tool, passing the
arguments documented in each server's reference. See the
waafir-redact,
waafir-translate,
waafir-dataroom, and
waafir-esign references for the tool
contracts.
When something goes wrong
Failures arrive on two different layers, and they do not look alike. Getting this wrong is the single most common integration mistake here: a client that branches only on the HTTP status will silently miss every failure of the second kind.
Layer 1 — the request was refused before any tool ran
These are real HTTP error statuses, with a JSON-RPC-shaped error body. They mean the request never reached a tool at all:
-
404 — Unknown MCP server. The URL's server-name segment is not one of
waafir-redact,waafir-translate,waafir-dataroom, orwaafir-esign— most often a typo or a bare/api/mcpwith no server name. Fix the URL. -
402 — Add-on not purchased. The server is a paid offering (today:
waafir-esign) and your organisation holds neither the add-on nor an active subscription. An org admin can purchase the add-on or a plan from the billing settings. An unentitled organisation cannot even list the server's tools. -
401 — Unauthenticated. The PAT is missing, malformed, revoked, or expired. Check that the
Authorizationheader is present and that the token is still active in Add-ons → Connect; issue a fresh one if it has been revoked or has expired. -
403 — Forbidden. The credential was rejected at the door: a logged-in browser session was used instead of a PAT (sessions are not accepted on this surface), or your organisation enforces an IP allow-list and the request came from an address outside it.
-
429 — Too many requests. You have hit an MCP rate limit. Nothing here is keyed on your IP address or on your organisation — your budget is your token's, so a colleague in the same organisation and a second client on the same network do not spend it. Two limits can produce this status:
- the credential you present, before it is looked up — 60 requests per minute. A malformed, revoked or expired token spends this budget too, which is the point: it bounds a retry loop that never authenticates.
- the token, once resolved — 120 requests per minute, deliberately higher, because a working client's authenticated call volume is larger than its retry volume.
There is also a platform-wide ceiling on unauthenticated traffic, set far above real usage; you are unlikely to be what trips it.
The response carries no
Retry-Afterheader and no distinguishing code — every 429 on this surface looks the same — so back off on a schedule of your own rather than spinning. If one token is not enough headroom, issue a second: both limits are per token.
Layer 2 — a tool ran and refused
This is where most refusals live, and it is not an HTTP error. The HTTP
response is 200 and the JSON-RPC envelope is a success envelope. The
failure is carried inside the tool result, which sets isError: true and whose
text content is:
{ "error": { "code": "CONFLICT", "message": "…" } }Branch on error.code. The codes are:
| Code | Meaning |
|---|---|
INVALID_ARGUMENT | An argument is missing, malformed, or not a valid id — fix it and retry |
FORBIDDEN | The token is valid but not permitted for this call |
NOT_FOUND | No such record, or it is not yours |
CONFLICT | Understood and permitted, but the data room is not in a state where it can be carried out |
TOO_LARGE | The input exceeds a size limit — split it |
QUOTA_EXCEEDED | A metered allowance is spent; somebody must buy or upgrade something |
UPSTREAM_ERROR / UNAVAILABLE | A transient downstream failure — retry later |
INTERNAL | An unexpected failure — do not retry, escalate |
Two of these catch people out:
FORBIDDENfor a scope that is too low. Areadtoken calling a write tool is refused by the tool, so it arrives here asFORBIDDENin the payload — not as an HTTP 403. The same is true of a token restricted to specific data rooms that references one outside its allow-list. Issue a token with the right scope or data-room access.CONFLICT. The call was understood and permitted, but the data room is not in a state where it can be carried out — a folder name already taken, a file whose name a live file has since claimed, or a restore whose container is still deleted or whose upload never completed. ACONFLICTis not an authorization problem and re-issuing the token will not help; the message names the blocking record where there is one, so you can act on it and retry. Thewaafir-dataroomreference lists the conflicts each tool can return.
A clear refusal on either layer is the expected, safe outcome of a call Waafir will not serve — it fails the request rather than silently doing less than you asked.
Personal Access Tokens
Issue, scope, and revoke Personal Access Tokens (PATs) to authenticate an AI client against Waafir's MCP servers. Covers the read / write / admin scopes, restricting a token to specific data rooms, expiry, the one-time reveal, and revocation.
waafir-redact reference
Reference for the waafir-redact MCP server — redact PII from a block of text with redact_text, or analyse a whole document for PII with redact_file and redact_file_status.