MCP Server
The @affitor/mcp Model Context Protocol server — let AI agents (Claude Desktop, Cursor) track clicks, leads, sales and refunds, generate per-stack integration plans, and self-verify attribution as tool calls.
Last updated Oct 14, 2026
@affitor/mcp is a Model Context Protocol stdio server for Affitor. It exposes Affitor's affiliate-tracking capabilities as MCP tools, so an AI agent — Claude Desktop, Cursor, or any MCP client — can report clicks, leads, sales and refunds, fetch a per-stack integration plan, and prove attribution works, all as native tool calls.
Under the hood it wraps the consolidated server client @affitor/sdk/server (the Affitor class). Authentication is your program API key, supplied via the AFFITOR_API_KEY environment variable.
The @affitor/mcp and @affitor/sdk packages are Beta. The documented happy-path works; report issues on GitHub.
Install as a plugin
In Claude Code and Gemini CLI, the plugin is the quickest way to install. It bundles the MCP server with Affitor's integration guide (a skill in Claude Code, a context file in Gemini CLI). Claude Code asks for your program API key when you enable the plugin; Gemini CLI asks during installation.
/plugin marketplace add Affitor/claude-plugins
/plugin install affitor@affitorRun the Claude Code commands inside a Claude Code session. Claude Code keeps the key in secure storage, and Gemini CLI keeps it in the system keychain. Source: github.com/Affitor/claude-plugins.
The server is also listed in the Official MCP Registry as com.affitor/mcp, so clients that browse the registry can find it there.
Add it to your MCP client
For any other client, or to configure it yourself, pick your client below. Every option runs the same local server with npx -y @affitor/mcp and passes your program API key as AFFITOR_API_KEY. Replace your_program_key with your key.
claude mcp add affitor --env AFFITOR_API_KEY=your_program_key -- npx -y @affitor/mcpWhere each JSON goes:
- Claude Desktop:
claude_desktop_config.json, in~/Library/Application Support/Claude/on macOS or%APPDATA%\Claude\on Windows. - Cursor:
.cursor/mcp.jsonin your project, or~/.cursor/mcp.jsonfor every project. - VS Code:
.vscode/mcp.jsonin your project. VS Code asks for the key once and stores it securely. - Other clients (Windsurf, Cline and most others): the client's MCP config file, in the same
mcpServersshape.
Restart your client (or reload its MCP servers) and the affitor_* tools become available to the agent. To let the agent report sales and refunds, also add "AFFITOR_MCP_WRITE": "1" to env (see below).
Gemini CLI: some Google plans moved from Gemini CLI to Antigravity CLI. If you use Antigravity CLI, follow Google's migration guide.
Environment variables
| Variable | Required | Description |
|---|---|---|
AFFITOR_API_KEY | Yes | Your Affitor program API key (Bearer). Server-side only — never ship it to a browser. |
AFFITOR_API_URL | No | API base override. Defaults to https://api.affitor.com. |
AFFITOR_MCP_WRITE | No | Set to 1 to add the two tools that move money: affitor_track_sale and affitor_track_refund. Off by default, so an agent exploring the tools cannot create a real sale or reverse a commission. |
If AFFITOR_API_KEY is not set, the server prints a clear message to stderr and exits.
The program API key is a server-side secret. The MCP server runs locally and reads it from your client config — it is never exposed to the browser or sent to the agent's model.
Tools
The server registers five tools by default, and seven with AFFITOR_MCP_WRITE=1. Each returns the Affitor API's JSON payload as text content; a failed request (a thrown error or an { ok: false } envelope) returns an MCP error result with the message.
| Tool | Inputs | Description |
|---|---|---|
affitor_readiness | forceRecheck?: boolean | Check this program's integration/onboarding readiness — returns a 5-gate verdict + blocker + next_action. Poll until integration_verified is true. |
affitor_track_click | affiliateUrl?, pageUrl?, referrerUrl?, existingClickId? (all optional strings) | Report a click (usually browser-side; public, no customer needed). |
affitor_track_lead | customerExternalId?: string, clickId?: string, email?: string, testMode?: boolean (one of customerExternalId / clickId required) | Report a lead/signup. Binds the customer to the click so later sales attribute by customerExternalId alone. |
affitor_track_sale | customerExternalId? / clickId? (one required), amount: number (cents), invoiceId: string, currency?, saleType?, isRecurring?, subscriptionId?, subscriptionInterval?, testMode? | Needs AFFITOR_MCP_WRITE=1. Report a sale. Creates a real sale and commission unless testMode is true. Resolves attribution by customerExternalId (bound at lead time). |
affitor_track_refund | invoiceId: string, refundAmountCents?: number, refundReason?: string, testMode?: boolean | Needs AFFITOR_MCP_WRITE=1. Report one refund with its own amount; amounts add up on the sale (omit amount = refund the rest → commission reversed). A retry with the same amount is ignored. |
affitor_get_integration_plan | framework, provider, mode? | Return the deterministic per-stack integration plan — install, checkout-metadata snippet, trackSale snippet + where to inject it, and the verify step. |
affitor_run_verification | (none) | Fire the synthetic click → lead → sale verification chain through the real attribution pipeline (isolated is_test rows). |
Tracking tool inputs
affitor_track_lead — one of customerExternalId / clickId is required:
customerExternalId?: string— your own user id; binds this customer to the click.clickId?: string— Affitor click id (from theaffitor_click_idcookie).email?: string— the lead's email address.testMode?: boolean: record a test lead (flaggedis_test) instead of a real one.
affitor_track_sale — one of customerExternalId / clickId is required:
customerExternalId?: string— your own user id; resolves attribution (noclickIdneeded once bound at lead time).clickId?: string— Affitor click id.amount: number— sale amount in integer cents (e.g.4999= $49.99).invoiceId: string— idempotency key; dedups retries (your invoice / transaction id).currency?: string—USD,EUR, orVND; other codes are not supported. Defaults toUSD. Amounts are not converted between currencies: commissions and platform fees are calculated on the amount as sent, and invoices are issued in USD.saleType?: "payment" | "subscription"— one-off payment or subscription.isRecurring?: boolean— whether this sale recurs (subscription renewal).subscriptionId?: string— provider subscription id, if applicable.subscriptionInterval?: "monthly" | "quarterly" | "annual"— billing interval for a subscription sale.testMode?: boolean: record a test sale (flaggedis_test) that creates no commission. Leave it off for a real sale.
affitor_track_refund:
invoiceId: string— the sale's idempotency key (theinvoiceIdyou passed toaffitor_track_sale).refundAmountCents?: number— integer cents, this refund's own amount (not a running total). Omit (or0) = refund everything not yet refunded → commission reversed; otherwise added to earlier refunds →refundeduntil the total reaches the sale amount.refundReason?: string— optional human-readable refund reason.testMode?: boolean: a dry run that returns the refund that would be sent and calls nothing. The API has no test mode for refunds.
affitor_track_click — all optional:
affiliateUrl?: string— the affiliate/referral URL that was clicked.pageUrl?: string— the landing page URL the click arrived on.referrerUrl?: string— the HTTP referrer URL, if any.existingClickId?: string— reuse an existing Affitor click id instead of minting a new one.
affitor_get_integration_plan
A pure tool: it reads the canonical recipe registry (@affitor/recipes) and returns the deterministic integration plan for a given stack. It never touches the network or the client — so the agent follows a fixed contract instead of guessing one.
| Input | Values | Description |
|---|---|---|
framework | next-app, next-pages, fastify, express, node, unknown | The detected app framework. Determines where trackSale is injected. |
provider | stripe (default), polar, lemonsqueezy, paddle, unknown | The detected payment provider. |
mode | stripe_connect (default), s2s | Payment-tracking mode. stripe_connect = Connect autocaptures the sale (metadata only, no trackSale); s2s = inject trackSale in your webhook. |
The plan it returns includes:
- install — what to add (
npm i @affitor/sdk). - metadata — the checkout-session attribution snippet to plant at checkout creation (always required for Stripe).
- sale — the
trackSalesnippet and exactly where to inject it. Formode: "stripe_connect"this isnull— Stripe Connect records the sale server-side, so the agent injects metadata only and must not also calltrackSale(the double-count guard). - renewals — for Stripe
s2s, a separatecase 'invoice.paid'handler so subscription renewals are not silently missed. - verify — the self-verify step (synthetic chain → readiness gate).
Because the CLI (affitor init / affitor onboard), this MCP tool, and the public integration guides all read the same recipe registry, the integration contract can never drift between surfaces.
affitor_run_verification
The agent's proof step. It fires Affitor's synthetic click → lead → sale chain through the real attribution pipeline, writing isolated is_test rows that never create real commissions. Run it, then poll affitor_readiness until integration_verified: true.
The recommended agent loop:
- Call
affitor_run_verificationto fire the chain. - Call
affitor_readinessand checkintegration_verified. - If not yet verified, read the
blockerand its gate'snext_action, self-correct, and repeat.
affitor_run_verification is rate-limited to 10 runs per program per hour. On a rate_limited result, read retry_after_seconds and wait that long before retrying. A non-2xx (including a 429) returns the parsed error body with the HTTP status merged in, so the agent can read retry_after_seconds and back off rather than crash.
Related
- Agent Integration — how AI agents auto-install tracking from generated
AGENTS.mdinstruction files. - CLI Command Reference —
npx affitor onboard, the one-shot equivalent of the MCP flow. - SDK Reference — the
@affitor/sdkpackage the MCP server wraps. - Track Sale — the full API contract behind
affitor_track_sale.