# Connect your assistant or editor

Add the AffiliateRail MCP server to Claude, ChatGPT, Claude Code, Codex, Cursor or VS Code, then ask it to set up your program.

Run your affiliate program from your assistant instead of the dashboard: who your top partners
are this month, which commissions and applications are waiting, who has gone quiet, how revenue
is trending, why a payout failed. Allow it to write as well and it can decide applications, resolve
risk flags, manage the resources shelf and send the campaigns you built. Or hand it the whole
setup: ask your agent to "set up my affiliate program" and it works through the steps with you,
from your commission rate to the tracking tag in your code.

**Server URL:** `https://mcp.affiliaterail.com/mcp`
**Requires:** an AffiliateRail account. API and MCP access is part of every plan, the free trial included.

**To set up your program:** connect, sign in and press Allow, then say "set up my affiliate program".
Your agent calls `setup_guide` and works through the steps with you ([how it goes](#set-up-your-program-with-an-agent)).

## How the connection is secured

You never paste a key into an assistant. When you press Connect, AffiliateRail opens in your
browser, you sign in the way you always do, and you press Allow. That's the whole flow: the
connection can read your program, set it up and act in the review queues, and the screen says
exactly what it can never touch. Press Deny and the assistant is told so. If you want an
assistant that can only read, create a read-scoped API key under Settings, API keys and use that instead.

What that gives you:

- **Nothing to copy and nothing to lose.** The credential is made on our side and the assistant
  receives a short-lived token, one hour, refreshed on its own. You never see a key, so you
  can't leave one in a chat window.
- **One press covers the working surface.** A connection reads your program and acts in the
  places you already work: program settings, branding, commission rules, groups, partner links
  and coupons, commission and application decisions, partner invites, risk flags, the resources
  shelf and campaign sends. Every change shows you a confirmation card first. The Allow screen
  lists what it can never touch, and a read-scoped API key from Settings is the way to connect an assistant that may
  only read.
- **One connection per assistant.** Each one is listed under **Settings**, **API keys**, **Connected
  agents**, by the app that asked, with the date you allowed it and when it was last used.
  Connecting the same assistant again reuses that one instead of leaving another behind.
- **Disconnecting is one click.** Press Disconnect next to it and that assistant stops working on
  its next request. Every other connection carries on.

If you belong to more than one organization, the Allow screen asks which one you're connecting.
The assistant sees that one and nothing else.

The Allow screen also shows who is asking. **Address checked** means the assistant is known by
its own web address and we fetched its details from there, so the name can't be faked. **This
agent named itself** (marked **Not verified**) means it picked its own name, so anyone could call
themselves "Claude". That's normal for a new connection. The screen also names the address Allow
sends you to. Press Allow only if you pressed Connect a moment ago.

## 1. Connect from Claude

1. Go to [claude.ai](https://claude.ai). Open **Settings**, **Connectors**, **Add custom connector**.
2. Name: `AffiliateRail`. Server URL: `https://mcp.affiliaterail.com/mcp`. Leave the OAuth client
   fields empty; the server registers the connector itself. Click **Add**.
3. Click **Connect**. AffiliateRail opens in a new tab. Sign in if you aren't already and press
   **Allow**. You're sent back to Claude, connected.
4. Under the connector, set the permissions for each tool. Our recommendation: leave the read
   tools on **Always allow** and keep every write tool (`approve_commission`, `send_campaign`,
   `reject_application` and the rest) on **Needs approval**, so you confirm every change before
   it happens.
5. In a new chat, make sure the AffiliateRail toggle is on under the tools menu, then ask.


Claude Desktop uses the same URL.

## 2. Connect from ChatGPT

1. Go to [chatgpt.com](https://chatgpt.com). Open **Settings**, **Apps**, **Advanced settings** and switch
   **Developer mode** on.
2. Click **Create app**. Name: `AffiliateRail`. MCP server URL:
   `https://mcp.affiliaterail.com/mcp`. Authentication: **OAuth**. Tick the acknowledgement and
   click **Create**.
3. ChatGPT opens AffiliateRail: sign in and press **Allow**.
4. In a chat, open the tools menu, enable AffiliateRail, and ask.

ChatGPT asks for confirmation before running a tool that changes data. Keep that on.


## 3. Connect from Claude Code or Codex

In Claude Code, run this in your project, then type `/mcp` to sign in. It opens the same Allow
screen:

```bash
claude mcp add --transport http affiliaterail https://mcp.affiliaterail.com/mcp
```

In Codex, add the server, then log in. The second command opens the Allow screen in your browser:

```bash
codex mcp add affiliaterail --url https://mcp.affiliaterail.com/mcp
codex mcp login affiliaterail
```

## 4. Add to Cursor or VS Code

One click each. Both open the editor, add the server, and send you to the same Allow screen the
first time it's used.

- [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=affiliaterail&config=eyJ1cmwiOiJodHRwczovL21jcC5hZmZpbGlhdGVyYWlsLmNvbS9tY3AifQ==)
- [Add to VS Code](https://vscode.dev/redirect/mcp/install?name=affiliaterail&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.affiliaterail.com%2Fmcp%22%7D)

Any other client that speaks MCP: add `https://mcp.affiliaterail.com/mcp` as a remote (HTTP)
server. If it supports sign-in, that's all it needs.

## Set up your program with an agent

A new account comes with a program, a 20% commission rule and some demo data. From there, open
your agent in the repository for your product and ask it to "set up my affiliate program". It
calls `setup_guide`, which returns the seven steps on your Getting started page, plus the optional
custom domain, with the tool for each one. It works through them with you:

| Step | What the agent does |
| --- | --- |
| Commission rule | Reads it with `rules_summary`, changes it with `update_commission_rule` once you say what to pay |
| Payment processor | Hands you the Stripe link from `payment_connection_status` to open yourself. Paddle is connected in the dashboard |
| Tracking tag | Writes the tag from `get_install_instructions` into your code, then proves it with `check_install` |
| Your own portal | Invites you with `invite_partner`, so you see what partners see |
| Test sale | Tells you how to pay once in Stripe test mode or Paddle sandbox through your own link; it needs a real browser |
| First partner | Invites the person you name |
| Branding | Sets your logo and colours with `update_branding` |
| Custom domain (optional) | Points you to the dashboard: it needs a DNS record only you can add |

It also offers to clear the demo data with `remove_sample_data` before real partners join, and
looks things up with `search_docs` rather than guessing.

## What you can ask

Setting up:

| Ask | Tool behind it |
| --- | --- |
| "Set up my affiliate program" | `setup_guide()` |
| "Is Stripe connected?" | `payment_connection_status()` |
| "Add the tracking tag to my site" | `get_install_instructions()`, then `check_install(url)` |
| "How does attribution work with Paddle?" | `search_docs(query)` |
| "Pay partners 30% on every payment" | `create_commission_rule(...)` or `update_commission_rule(rule_id, ...)` |
| "Pause the old launch rule" | `set_rule_status(rule_id, status)` |
| "Set a 60-day cookie and net 30 payouts" | `update_program_settings(...)` |
| "Brand my portal with my logo" | `update_branding(logo_url, ...)` |
| "Make an Agencies group" | `create_group(name)`, `update_group(group, ...)` |
| "Give @jimi a link to my pricing page" | `create_partner_link(partner_handle, destination_url)` |
| "Credit @jimi for the code JIMI20" | `create_coupon(partner_handle, code)` |
| "Clear out the demo data" | `remove_sample_data()` |

Every tool, with its inputs, is in [the tool reference](https://docs.affiliaterail.com/mcp/tools).

Reading your program:

| Ask | Tool behind it |
| --- | --- |
| "Who are my top partners this quarter?" | `top_partners(period)` |
| "What commissions are waiting for approval over $50?" | `pending_commissions(min_amount)` |
| "Which partners have gone quiet in the last 60 days?" | `idle_partners(days)` |
| "Show me affiliate revenue by month this year" | `revenue_by_period(granularity)` |
| "Tell me everything about @jimi" | `partner_detail(handle_or_email)` |
| "Did last month's payouts go through?" | `payout_status(period)` |
| "What commission rules do I have?" | `rules_summary()` |
| "What referrals came in today?" | `recent_referrals(limit)` |
| "Find the partner whose email starts jane@" | `list_partners(query, status)` |
| "Which customers did @jimi bring in?" | `list_customers(query, status)` |
| "Show rejected commissions this month" | `list_commissions(status, partner_handle)` |
| "Who applied, and is anything held?" | `list_applications()` |
| "Revenue by product this quarter" | `report(dimension, from, to)` |
| "Any open fraud flags?" | `list_risk_flags(status)` |
| "What is on the resources shelf?" | `list_resources()` |
| "Is the newsletter still sending?" | `messaging_status()` |
| "What fields does a commission have?" | `schema_introspect(object)` |

Acting in the review queues:

| Ask | Tool behind it |
| --- | --- |
| "Approve commission com_…" | `approve_commission(id)` |
| "Reject com_… because it was a self-referral" | `reject_commission(id, reason)` |
| "Invite jane@example.com to the Agencies group" | `invite_partner(email, group)` |
| "Approve that application" | `approve_application(application_id)` |
| "Decline it, audience is not a fit" | `reject_application(application_id, reason)` |
| "Close the fraud flag, it was one bulk refund" | `resolve_risk_flag(risk_flag_id, note)` |
| "Add the brand kit link to resources" | `create_resource_link(title, url)` |
| "Unpublish the old one-pager" | `update_resource(resource_id, published)` |
| "Delete the outdated banner" | `delete_resource(resource_id)` |
| "Send the August campaign now" | `send_campaign(campaign_id)` |
| "Pause the welcome sequence" | `pause_sequence(sequence_id)` |

Before any of these applies, the server answers the first call with a confirmation card: ids
resolved to the names you recognise, amounts formatted from the stored values, and a field-level
list of exactly what would change ("Approve com_x93: $42.00 USD to Maria Alvarez, matured 28
Aug"). The assistant shows you the card and repeats the call as confirmed only once you agree;
nothing changes until it does.

That's enforced, not left to the assistant. Each card carries a token, and the confirmed call
has to send it back with the same details. A confirm without it is refused and the card comes
back. The card is also a rehearsal: the change is tried and rolled back, so anything it would be
refused for (your plan's limit, a value the settings page wouldn't take) shows on the card
before you're asked.

Every change made through an assistant is written to the audit log as `mcp`, with the connection
that made it, and shows in the object's history like any other change. What isn't here, on
purpose, whatever you allowed: executing or approving payout batches, payout connections and bank
details, API keys and webhook secrets, billing, who is on your team and their role, and deleting partners or customers.
Those stay in the dashboard. An assistant holding your token can't move money, because
AffiliateRail never holds any: payouts run on your own PayPal or Wise account, and that account
isn't on this surface.

Two resources are also exposed: `program://current` (your program's settings, plan and counts,
and the list of programs if you have more than one) and `catalog://events` (the webhook event
catalogue, the same one as `docs/webhooks.md`).

Amounts come back as integer minor units (cents, pence) with the currency and a formatted string.
The assistant is told to quote the formatted one.

## Finding affiliates with RecruitAffiliates.ai

[RecruitAffiliates.ai](https://docs.affiliaterail.com/finder) is our second product, and it finds
new affiliates. It's on the same connection, so the same agent can search, shortlist and look up
addresses for you. Its tools start with `finder_`:

| Ask | Tool behind it |
| --- | --- |
| "Find YouTubers who review email tools" | `finder_search(type, seed)` |
| "Who are my best new matches?" | `finder_list(view)` |
| "Save the top three" | `finder_save(ids)` |
| "Get me their email" | `finder_reveal(id)` |
| "What did we offer them? Offer 30% instead" | `finder_deal(id, terms)` |

A search costs one search credit and an address costs one email credit. Before either is spent,
the agent shows you a card with the cost and what you have left, and waits for your yes. An
address that isn't found is refunded. Saving is free. The agent can offer new terms on a deal, but
it can't mark them agreed or make anyone a partner, and no `finder_` tool drafts or sends a message.
Those stay with you, in RecruitAffiliates.ai.

Every `finder_` tool takes an optional `brand`: a domain, a brand name or a brand id. Leave it out
and the tool uses your oldest brand. On a Grow account, name another brand to work on it. Every
card and every answer names the brand it is about, and a row from a different brand than the one
you named is refused. `finder_list` also shows what a save read off each website: the pages
read, the social profiles and newsletter it found, and any traffic countries and keywords.

## The skill: better answers, connected or not

The AffiliateRail skill ([download and install it here](https://docs.affiliaterail.com/mcp/skill)) teaches Claude how to run an affiliate program: commission
design, program terms, recruiting, fraud, reading the numbers, and the tax-form and payout
mechanics. It has two modes and picks one itself: without a connection it answers as a competent
advisor; with the MCP tools present it composes them into live answers about your program, under
one hard rule: it never states a number about your program that didn't come from a tool call.
You don't need the skill to use the MCP server, or the server to use the skill.

## More than one program

A connection belongs to the organization you chose on the Allow screen, so it covers every program
on that organization. Tools default to your first program; say which one you mean ("in the Acme
Partners program") and the assistant passes its `program_id`, which it reads from
`program://current`.

## Disconnecting

Open **Settings**, **API keys**, **Connected agents** and press **Disconnect** next to the assistant.
That one connection stops working on its next request and no other is touched. Clients that tell
the server when you remove a connector there end it here too; if you're not sure yours does,
press Disconnect as well.

## Other ways to connect

Use these only if signing in doesn't work for your client.

**Send the key yourself.** Any client that can set a header (Claude Code, Cursor, `mcp-remote`)
can skip the browser entirely: make a key under **Settings**, **API keys**, pick the scopes you want,
and send `Authorization: Bearer rail_live_…`. Same scopes, same revocation, and it's the fastest
route from a terminal.

![Settings, API keys, new key dialog with the scope picker](/mcp/api-key.png)

**Paste a key into the browser.** If the Allow screen can't sign you in, for instance in an
embedded browser that won't keep a session, open `https://mcp.affiliaterail.com/oauth/authorize/key`
with the same connection parameters and paste a key there instead. It reaches the same place. Use
it when the front door won't open, not as a habit.

![The pasted-key page at /oauth/authorize/key, the fallback when a browser cannot keep a session](/mcp/authorize.png)

## For developers

- Endpoint: `POST https://mcp.affiliaterail.com/mcp`, streamable HTTP, stateless, JSON responses.
- Discovery: `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`.
- OAuth 2.1, public clients, PKCE S256 required, `authorization_code` and `refresh_token` grants.
  Access tokens last one hour, refresh tokens thirty days; both are bound to the credential behind
  the connection and die with it.
- Client registration, either way: a Client ID Metadata Document (send an `https` URL as
  `client_id`; the document must name itself by that URL and list its redirect URIs, and the
  Allow screen shows its hostname), or dynamic registration at `/oauth/register`. Redirects are
  https, or loopback (`localhost`, `127.0.0.1`, `[::1]`); a loopback redirect registered without a
  port accepts any port.
- Every redirect back to the client carries `iss` (RFC 9207).
- `POST /oauth/revoke` (RFC 7009) ends a connection: revoking its access or refresh token revokes
  the credential behind it. Always answers 200.
- `/oauth/authorize` sends the browser to the merchant dashboard to ask the question and takes the
  answer back. Every endpoint in the metadata stays on `mcp.affiliaterail.com`, so a client never
  sees that trip and never has to follow an issuer across origins.
- `resource` (RFC 8707) is honoured: send `https://mcp.affiliaterail.com/mcp` and the tokens you
  get back are bound to it and refused anywhere else. Sending none is fine and binds nothing.
- Scopes: `mcp:read`, `mcp:write`. Allow mints exactly these; a key you made yourself with the
  broader `read` / `write` scopes is accepted too.
- A 401 carries `WWW-Authenticate: Bearer … scope="mcp:read mcp:write", resource_metadata="…"`
  (RFC 9728), with no `error` when no token was sent (RFC 6750), so any MCP client that implements
  the authorization spec finds the flow on its own.
- Write tools take `confirm` and `preview_token`. The unconfirmed call returns the card and a
  token bound to the tool, its arguments, the program and the connection, valid fifteen minutes;
  the confirmed call needs it.

