Waafir
Connect AI Tools

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:

ServerURL
waafir-redacthttps://app.waafir.io/api/mcp/waafir-redact
waafir-translatehttps://app.waafir.io/api/mcp/waafir-translate
waafir-dataroomhttps://app.waafir.io/api/mcp/waafir-dataroom
waafir-esignhttps://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, or waafir-esign — most often a typo or a bare /api/mcp with 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 Authorization header 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 resolved120 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-After header 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:

CodeMeaning
INVALID_ARGUMENTAn argument is missing, malformed, or not a valid id — fix it and retry
FORBIDDENThe token is valid but not permitted for this call
NOT_FOUNDNo such record, or it is not yours
CONFLICTUnderstood and permitted, but the data room is not in a state where it can be carried out
TOO_LARGEThe input exceeds a size limit — split it
QUOTA_EXCEEDEDA metered allowance is spent; somebody must buy or upgrade something
UPSTREAM_ERROR / UNAVAILABLEA transient downstream failure — retry later
INTERNALAn unexpected failure — do not retry, escalate

Two of these catch people out:

  • FORBIDDEN for a scope that is too low. A read token calling a write tool is refused by the tool, so it arrives here as FORBIDDEN in 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. A CONFLICT is 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. The waafir-dataroom reference 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.