Skip to main content
Glama
fridaypatrick

Revolut Business MCP

README.md
# Revolut Business MCP

Read-only Model Context Protocol (MCP) server exposing Revolut Business transaction data to MCP clients over stdio.

## Tools

### `revolut_list_transactions`

List transactions. Single-page passthrough of the Revolut API response; no lossy field mapping.

| Parameter | Type | Notes |
|---|---|---|
| `from` | string (ISO calendar date or RFC3339 datetime) | optional |
| `to` | string (ISO calendar date or RFC3339 datetime) | optional |
| `account` | string (UUID) | optional, filter by account |
| `count` | integer 1–1000 | optional |
| `type` | enum | optional; one of `atm`, `card_payment`, `card_refund`, `card_chargeback`, `card_credit`, `charge`, `charge_refund`, `exchange`, `transfer`, `loan`, `fee`, `refund`, `topup`, `topup_return`, `tax`, `tax_refund` |

### `revolut_get_transaction`

Get a single transaction.

| Parameter | Type | Notes |
|---|---|---|
| `id` | string | required |
| `id_type` | literal `"request_id"` | optional; when set, `id` is treated as a request ID and only resolves transactions created within the last 2 weeks |

## Pagination caveat

`revolut_list_transactions` returns one page only, matching the Revolut API's own behavior. The server does not auto-paginate. Use `from`/`to` to page through results yourself.

## Prerequisites

- Node.js 22+
- A Revolut Business account with API access
- A client certificate registered with Revolut for API authentication, and the corresponding private key

Follow Revolut's official setup guides before configuring this server:

- [Revolut Business API documentation](https://developer.revolut.com/docs/business/business-api)
- [Setting up authentication (client credentials / certificate)](https://developer.revolut.com/docs/business/business-api#business-api-authentication)

## Install / build / test

```bash
npm install
npm run build       # tsc -> dist/
npm run typecheck    # tsc --noEmit
npm test             # tsx --test test/**/*.test.ts
```

## Environment configuration

Copy `.env.example` to `.env` and fill in values. Do not commit `.env` or any private key material.

`.env` is auto-loaded (via Node's `--env-file-if-exists=.env`) only by `npm start` and `npm run dev`. Running `node dist/src/index.js` directly does not load `.env`; supply the required variables externally (e.g. via your process manager or shell), or invoke Node yourself with `--env-file-if-exists=.env`.

| Variable | Description |
|---|---|
| `REVOLUT_ENV` | `sandbox` (default) or `production`. Selects the API base URL. |
| `REVOLUT_CLIENT_ID` | OAuth client ID from your Revolut Business API app. |
| `REVOLUT_JWT_ISS` | JWT `iss` claim value used when signing the client assertion. |
| `REVOLUT_PRIVATE_KEY` | PEM private key matching the certificate registered with Revolut. Supports literal `\n` line breaks (quoted single-line form), which the server normalises. |
| `REVOLUT_REFRESH_TOKEN` | Initial OAuth refresh token obtained via Revolut's authorization flow. |
| `REVOLUT_HTTP_TIMEOUT_MS` | Optional. HTTP request timeout in milliseconds, integer between 100 and 120000. Defaults to 15000. |

### Sandbox vs production

`REVOLUT_ENV=sandbox` targets `https://sandbox-b2b.revolut.com/api/1.0`; `REVOLUT_ENV=production` targets `https://b2b.revolut.com/api/1.0`. Any other value fails config loading at startup.

## Refresh-token behavior

The server exchanges the configured refresh token for a short-lived access token on first use, caches it in memory, and renews it automatically before expiry (60s skew) or on a 401 response. If Revolut rotates the refresh token in its response, the rotated token is adopted only in memory for the current process and is never written to `.env` or any file. On restart, the server always uses the `REVOLUT_REFRESH_TOKEN` value from the environment, regardless of any rotation that happened in a previous run. If the old token was invalidated by rotation, the process fails to authenticate until `REVOLUT_REFRESH_TOKEN` is updated.

Operators who need rotation to survive restarts must build their own secure external persistence (e.g., a secrets manager write-back) and update the environment before the next start. This server does not provide that mechanism.

## Running locally (stdio)

```bash
npm run build
npm start
```

`npm start` runs `node --env-file-if-exists=.env dist/src/index.js`, which auto-loads `.env` if present. For development without a build step, `npm run dev` runs the same via `tsx` against `src/index.ts` with the same `.env` auto-loading.

The server communicates over stdio; it has no HTTP listener. Run it via an MCP client that spawns it as a subprocess. If your MCP client invokes `node dist/src/index.js` directly (bypassing the npm scripts), it will not auto-load `.env`; the client must supply the environment variables itself (see the config example below) or you must add `--env-file-if-exists=.env` to the invocation.

## MCP client configuration example

Generic stdio MCP client config (adapt keys to your client's format):

```json
{
  "mcpServers": {
    "revolut-business": {
      "command": "node",
      "args": ["/absolute/path/to/revolut-business-mcp/dist/src/index.js"],
      "env": {
        "REVOLUT_ENV": "sandbox",
        "REVOLUT_CLIENT_ID": "...",
        "REVOLUT_JWT_ISS": "...",
        "REVOLUT_PRIVATE_KEY": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
        "REVOLUT_REFRESH_TOKEN": "..."
      }
    }
  }
}
```

## Security notes

- Never commit `.env`, private keys, or refresh tokens.
- Treat the refresh token as a long-lived credential; rotate it if leaked.
- The private key must correspond to the certificate registered with Revolut for this API client; keep it out of shell history and logs.
- This server is read-only: it exposes no write, transfer, or payment-initiating tools.

## Non-goals (current)

- No auto-pagination across multiple pages of transactions.
- No caching, persistence, or database layer.
- No write/transfer/payment tools — listing and single-transaction retrieval only.
- No transport other than stdio.
- No automated refresh-token persistence back to environment files.

This README does not claim live verification against the production Revolut API; behavior is based on the implemented code and Revolut's published API documentation.