MCP server
Relvo exposes a Model Context Protocol server, so an AI agent — Claude Code, your own SDK-based agent, anything that speaks MCP — can look up invoices and work your operations task queue directly, without you writing an API client for it.
The boundary is deliberate and worth stating first:
- Financial records are read-only. No tool issues, edits, voids or sends an invoice, a credit note, or any other fiscal document, and none of them moves money.
- The task queue is writable. An agent can create tasks and move them through their state machine — assign, start, complete, cancel — in the same queue your team works in the Relvo dashboard.
- Proposals are decided by people. Where an agent has proposed an action on a task, there is no tool to accept or reject it. An agent proposes; a human decides.
Connect with an API token
Sección titulada «Connect with an API token»claude mcp add --transport http relvo \ https://app.relvoerp.com/api/mcp/ \ --header "Authorization: Bearer rk_live_xxxxxxxxxxxxxxxxxxxx"| URL | https://app.relvoerp.com/api/mcp/ — with the trailing slash |
| Transport | Streamable HTTP |
| Auth | API token in Authorization: Bearer <your Relvo API token> |
| Organization | Carried by the token. There is no organization parameter or header on this surface |
Configure the trailing slash. The bare path /api/mcp answers a 307 redirect to /api/mcp/; most clients follow it, but some drop the Authorization header when they do, which then looks like an auth failure rather than a URL mistake.
Get an API token
Sección titulada «Get an API token»Mint an API token in the Relvo dashboard under Developer Zone (OWNER or ADMIN members only), exactly as described in Authentication. The plaintext token is shown once, at creation.
Issue the narrowest scope that does the job. full_access is issuable and would hand a model every machine endpoint Relvo has — it is the wrong credential for an MCP client, always.
A token carries exactly one scope. operations:write implies operations:read; invoices:read implies nothing else. An agent that must both read invoices and work the queue therefore needs two connections, one per token — which is also what keeps each one’s blast radius legible.
Connect with OAuth
Sección titulada «Connect with OAuth»Relvo also supports OAuth 2.1 for remote MCP clients that cannot accept a static API token. Point the client to the MCP URL below; it discovers the authorization server and takes the user through the Relvo consent flow.
| MCP URL | https://app.relvoerp.com/api/mcp/ |
| Protected-resource discovery | https://app.relvoerp.com/.well-known/oauth-protected-resource |
| Authorization-server metadata | https://app.relvoerp.com/.well-known/oauth-authorization-server |
| Issuer | https://app.relvoerp.com |
| OAuth scopes | invoices:read, operations:read, operations:write; add offline_access for persistent access |
The OAuth client must be registered with Relvo before connecting. Its client_id
and redirect URI are validated exactly, so configure the redirect URI supplied by
your MCP client without changing its spelling, path, or trailing slash. Consent is
per user, organization, and scope; OAuth never grants full_access. Each client
also has a server-enforced scope ceiling. A ChatGPT client registered for
operations:read cannot obtain invoice or write access even if a client UI asks
for it.
What the agent can do
Sección titulada «What the agent can do»invoices:read
Sección titulada «invoices:read»| Tool | Answers |
|---|---|
relvo_invoices_search |
find invoices by text and by lifecycle / fiscal / payment / delivery status and issue-date range |
relvo_invoice_get |
one invoice in full |
relvo_invoice_check_open_readiness |
why a draft cannot be opened yet — findings, missing FX rates |
relvo_invoice_payment_status |
what has been paid against one invoice |
operations:read
Sección titulada «operations:read»| Tool | Answers |
|---|---|
relvo_task_search |
find tasks by text, status, kind, priority, assignee, due date |
relvo_task_get |
one task, including its action proposals |
operations:write — also grants the two read tools above
Sección titulada «operations:write — also grants the two read tools above»| Tool | Effect | Destructive |
|---|---|---|
relvo_task_create |
opens a new task, optionally carrying action proposals | no |
relvo_task_assign |
gives a task to a member, by email | no |
relvo_task_start |
OPEN → IN_PROGRESS | no |
relvo_task_complete |
OPEN / IN_PROGRESS → COMPLETED | yes |
relvo_task_cancel |
→ CANCELLED | yes |
Assignment is by email address and never by user id. No tool on this server returns a user, organization or membership id — resolving the email server-side, against the caller’s own organization, is the only shape that cannot be used to probe for user ids belonging to another tenant.
Retries are replays, not duplicates
Sección titulada «Retries are replays, not duplicates»MCP has no Idempotency-Key header, so Relvo derives one for you from the tool name, the organization and the validated arguments — the same guarantee as Idempotency on the REST API, without the bookkeeping. An agent that retries relvo_task_create with identical arguments gets the same task back, not a second task.
When you genuinely mean “again” — the same daily task, a second time — pass a different request_marker on the write tool. Without it, a repeat is a replay, which is the safe default.
Client compatibility
Sección titulada «Client compatibility»The same MCP endpoint supports two credential types: a static API token for header-capable clients, and OAuth 2.1 for remote connectors. Do not copy an API token into a client that supports OAuth; use the consent flow instead.
| Client | Works | How |
|---|---|---|
| Claude Code | ✅ | the claude mcp add command above |
| Your own agent, any MCP SDK | ✅ | Streamable HTTP plus the Authorization header |
mcp-remote and similar proxies |
✅ | pass the header through; useful for stdio-only hosts |
| Claude remote connectors (claude.ai, Desktop, and mobile) | ✅ | OAuth 2.1 discovery and consent |
| ChatGPT custom MCP app (web) | ✅ | OAuth discovery, PKCE, and offline_access provide persistent read-only access when the registered client permits it |
| ChatGPT mobile | ❌ | ChatGPT custom MCP apps are currently web-only |
OAuth access tokens are short-lived. Request offline_access only for a client
registered to allow it; Relvo then issues rotating refresh tokens. It is a
persistence capability, not a data permission, and the consent screen still
names the one Relvo scope the client may use.
When something fails
Sección titulada «When something fails»Tool failures come back as tool errors — an error flag plus a {code, message, retryable} body — rather than protocol errors, so the agent can read the message and act on it.
| Code | Cause |
|---|---|
mcp.unauthenticated |
no valid API token or OAuth access token on the request — including a browser session reaching the endpoint, which is rejected on purpose |
mcp.forbidden |
the token’s scope does not cover that tool. The tool never ran |
mcp.invalid_arguments |
the arguments failed validation |
mcp.not_found |
the id does not exist in your organization. A record belonging to another tenant is indistinguishable from a missing one, deliberately |
mcp.conflict |
a state guard or a concurrent edit — for example completing a task someone else already cancelled. retryable tells you which: reload with relvo_task_get and decide |
mcp.unavailable |
a genuine server-side problem. This is the only one worth retrying blindly |
A 307 followed by a 401 is not an auth problem — it is the missing trailing slash, and a client that dropped the header on the redirect.