Documentation

Connect Claude / Cursor via MCP

ReliPay hosts two MCP server surfaces, both reachable from Claude Desktop / Claude Code / Cursor:

  • Per-Application end-user MCP at /api/v1/mcp/<slug> — end-users sign into your app via OAuth 2.1 + PKCE and read their own account data through four tools. Full RFC stack: RFC 8414 + RFC 9728 + RFC 7591. Every MCP client that ships generic OAuth discovery connects without custom code.
  • Operator MCP at /api/v1/tenant/mcp — the workspace operator's view of their own data: applications, end-users, payments, webhooks, security events. Two auth paths: OAuth 2.1 + PKCE with a workspace picker at consent (the same RFC stack as per-Application MCP), or Bearer with an operator personal-access-token (rp_op_…) for headless automation.

Three-minute quickstart

  1. Enable MCP on an Application. Go to the operator panel → Applications → pick one → MCP tab → toggle MCP enabled. Copy the displayed MCP URL — https://api.relipay.dev/api/v1/mcp/your-app.
  2. Add it to your MCP client. Easiest path is Claude Code:
    claude mcp add --transport http your-app https://api.relipay.dev/api/v1/mcp/your-app
  3. Sign in. On first tool call, Claude opens a browser tab pointing at your ReliPay app's login page. The end-user signs in with the credentials they normally use to access the app, approves the consent screen, and the tools become available.

What MCP gives you

An MCP server is a typed-tool surface an AI agent can call. ReliPay's hosted MCP server is per-Application — the same user database, the same auth methods, the same plans + credits + licenses your customers already have. The agent sees a slice scoped to one authenticated end-user.

The four tools are deliberately narrow + read-only — listing balances and entitlements, not modifying them. Writes happen through your normal app surface; MCP is for telling an agent about the user's state.

Per-Application MCP URL

Every Application gets its own MCP endpoint, derived from its slug:

https://api.relipay.dev/api/v1/mcp/your-app

That URL is the only thing you ever hand to a client. It serves both the MCP JSON-RPC endpoint and the OAuth Authorization Server under the same hostname; clients auto-discover everything else.

Connect from Claude Code

The Claude Code CLI registers the server in your global ~/.claude.json and handles the OAuth flow on first use.

claude mcp add --transport http your-app https://api.relipay.dev/api/v1/mcp/your-app

No further config needed — the --transport http flag is the load-bearing part; it tells Claude Code to expect the 401 → OAuth-discovery handshake instead of the stdio process protocol.

Connect from Claude Desktop

Edit your Claude Desktop config file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "your-app": {
      "type": "http",
      "url": "https://api.relipay.dev/api/v1/mcp/your-app",
      "oauth": {
        "authServerMetadataUrl": "https://api.relipay.dev/api/v1/mcp/your-app/.well-known/oauth-authorization-server"
      }
    }
  }
}

Restart Claude Desktop. The OAuth flow opens in your browser; sign in, approve, and the four tools appear in the MCP server's tool list.

The oauth.authServerMetadataUrl field is technically redundant when discovery from the resource works — but pinning it explicitly bypasses the well-known cascade, which helps when your deployment runs the API behind an unusual path or reverse proxy.

Connect from Cursor

Cursor uses the same shape; drop the same block into ~/.cursor/mcp.json and restart Cursor.

Connect a custom Claude connector

In Claude (web/desktop) go to Settings → Connectors → Add custom connector and paste the MCP URL:

https://api.relipay.dev/api/v1/mcp/your-app

Claude reads the protected-resource metadata from the 401 challenge, walks the discovery chain, runs the OAuth flow, and connects.

OAuth flow, step by step

For tooling that doesn't ship a generic OAuth-discovery flow, here's what the supported MCP clients do automatically. All of it is standard OAuth 2.1 + PKCE; no ReliPay-specific quirks.

1. Discover

curl https://api.relipay.dev/api/v1/mcp/your-app/.well-known/oauth-authorization-server

Returns RFC 8414 metadata pointing at the authorize / token / register / introspect endpoints under the same MCP URL.

2. Register dynamically (RFC 7591)

curl -X POST https://api.relipay.dev/api/v1/mcp/your-app/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{
    "client_name": "My Local Tool",
    "redirect_uris": ["http://localhost:55123/callback"]
  }'

You get back { client_id, redirect_uris, token_endpoint_auth_method: "none" }. No client secret — PKCE replaces it.

3. Authorize

Build the authorize URL:

https://api.relipay.dev/api/v1/mcp/your-app/oauth/authorize\n  ?response_type=code\n  &client_id=<from-register>\n  &redirect_uri=http://localhost:55123/callback\n  &code_challenge=<sha256-of-verifier>\n  &code_challenge_method=S256\n  &scope=mcp:account\n  &state=<random>

Open it in the user's browser. They sign into your ReliPay Application, approve the consent screen, and the AS redirects to your redirect_uri with ?code=…&state=….

4. Exchange the code for a token

curl -X POST https://api.relipay.dev/api/v1/mcp/your-app/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=<from-redirect>' \
  -d 'code_verifier=<your-pkce-verifier>' \
  -d 'client_id=<from-register>' \
  -d 'redirect_uri=http://localhost:55123/callback'

You get back { access_token, refresh_token, token_type: "Bearer", expires_in, scope }. The access token is JWT-signed (you don't need to parse it; the MCP endpoint validates it on every call).

5. Call tools

curl -X POST https://api.relipay.dev/api/v1/mcp/your-app \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

6. Refresh on expiry

Repeat step 4 with grant_type=refresh_token and your refresh_token. The old refresh token is rotated out atomically; replay is rejected.

Tools reference

All four tools are zero-argument; they always operate on the user authenticated by the access token. None require parameters from the agent.

  • get_profile

    Email, role, verification status, and the metadata your app stored on the user.

    Returns: { id, email, emailVerified, role, metadata, createdAt }

  • get_subscription

    The user's current subscription (ACTIVE or PAST_DUE) and the linked Plan, or null.

    Returns: { status, provider, currentPeriodEnd, cancelAt, plan: { slug, name, interval, amount, currency } } | null

  • get_credits

    Prepaid credit balance for the user (unit-less; the app defines what a credit means).

    Returns: { balance: number }

  • list_licenses

    Issued licenses for the user (PERPETUAL / TIMED / SEATS). License keys are NEVER returned.

    Returns: { licenses: Array<{ id, kind, status, seatsAllowed, expiresAt, createdAt }> }

Tools never return license keys, password hashes, provider credentials, or any other Application's data. The session is scoped to (applicationId, endUserId) — a token issued for app A can't read app B.

Security model

  • PKCE mandatory. code_challenge_method=S256 is the only accepted value; clients without PKCE fail at /authorize.
  • Public clients only. Dynamic registration returns token_endpoint_auth_method: "none"; PKCE is the replacement for a client secret. No secret to leak.
  • Redirect URI allowlist. https://, http://localhost, and custom schemes (e.g. claude://) are accepted. ftp://, file://, and bare HTTP to a non-localhost host are rejected at registration time.
  • Audience-bound tokens. Each token is signed with aud = <mcp-url>; replaying a token issued for app A against app B's MCP endpoint fails verification.
  • Per-Application kill switch. The operator can bump an Application's tokenGeneration from the panel to invalidate every issued MCP token instantly. Clients see 401 and re-run the flow.
  • Read-only surface. The four tools never mutate. Writes happen through your normal app surface, where you control authorization end-to-end.

Operator MCP (workspace view)

Per-Application MCP exposes the end-user's data. The operator MCP at https://api.relipay.dev/api/v1/tenant/mcp exposes the operator's workspace — applications, end-users, payments, webhook health, security events.

Two auth paths, pick whichever fits the client:

  • OAuth 2.1 + PKCE (recommended for Claude Desktop, Code, Cursor, custom connectors). Operator clicks Connect → browser opens → signs in with panel email + password → picks a workspace at consent → tokens minted. No PAT to paste; full RFC 8414 / 9728 / 7591 discovery.
  • PAT-Bearer (for headless automation / non-browser clients). Mint a rp_op_… token in panel → Account → API tokens and paste it into the client's headers.Authorization field. The PAT is bound to one workspace at mint time.

OAuth mcp.json snippet

{
  "mcpServers": {
    "relipay-operator": {
      "type": "http",
      "url": "https://api.relipay.dev/api/v1/tenant/mcp",
      "oauth": {
        "authServerMetadataUrl": "https://api.relipay.dev/api/v1/tenant/mcp/.well-known/oauth-authorization-server"
      }
    }
  }
}

PAT-Bearer mcp.json snippet

{
  "mcpServers": {
    "relipay-operator": {
      "type": "http",
      "url": "https://api.relipay.dev/api/v1/tenant/mcp",
      "headers": {
        "Authorization": "Bearer rp_op_<paste-your-token-here>"
      }
    }
  }
}

Tools the operator can call

  • get_workspace_overview — counts, MRR per currency.
  • list_applications / list_members.
  • recent_payments / recent_subscriptions (status filter).
  • recent_security_events (actorType filter — operator / end_user / system).
  • recent_webhook_events (provider, onlyFailed) / recent_failed_webhook_deliveries.
  • application_health — per-app payment success rate (30d) + outbound webhook success rate (24h), sorted by failure count.

Read-only. Membership is re-checked on every request; removing the operator from the workspace invalidates the PAT immediately. lastUsedAt on each PAT advances on every successful call.

OAuth endpoints

  • https://api.relipay.dev/api/v1/tenant/mcp/.well-known/oauth-authorization-server — RFC 8414 metadata
  • https://api.relipay.dev/api/v1/tenant/mcp/.well-known/oauth-protected-resource — RFC 9728
  • POST /oauth/register (RFC 7591), GET/POST /oauth/authorize (login + workspace picker + consent), POST /oauth/token (auth-code + refresh), POST /oauth/introspect (RFC 7662)

Scope: mcp:operator:read (the only scope today). Access token: 1h. Refresh token: 30d, hash-only, rotated on redeem.

Self-hosting

The MCP server ships in apps/api — there's no separate process to run. Once your API is reachable on a public URL, set PUBLIC_WEBHOOK_BASE_URL to that origin (the same env var that anchors webhook routes), and the MCP issuer URL is derived automatically. Enable MCP on the Application from the panel and you're done — no extra ports, no extra container, no extra deploy.

Troubleshooting

404 on the MCP URL or any /.well-known/oauth-* path
MCP isn't enabled on the Application. In the operator panel: Applications → pick app → MCP → toggle MCP enabled.
401 with no WWW-Authenticate header
The MCP endpoint always replies 401 + WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource" on unauthenticated calls. If your client doesn't honour the hint, paste the discovery URL into oauth.authServerMetadataUrl in your mcp.json.
invalid_request on /authorize
You're missing PKCE (code_challenge_method=S256) or response_type isn't code. Both are mandatory.
Unknown client_id or unregistered redirect_uri
Re-run dynamic registration with the exact redirect_uri you intend to use. The AS compares character-for-character.
tools/list returns []
The token is valid but for a different audience. Re-do the flow against the correct Application's MCP URL.
Sudden 401 mid-session
The operator likely rotated tokenGeneration (per-app kill switch). Re-run the flow.

Further reading