MCP server

Connect any agent to CashSDK with the hosted MCP server at https://mcp.cashsdk.com/mcp: Streamable HTTP, OAuth 2.1 or a bearer token.

The CashSDK Model Context Protocol server is hosted, so there is nothing to install. It's a thin, stateless proxy over the CashSDK REST API: every tool maps to an API call made with the token you send, so an agent can create apps, manage catalog, build paywalls, wire webhooks and read revenue without ever holding your dashboard session.

URLhttps://mcp.cashsdk.com/mcp
TransportStreamable HTTP (remote)
AuthOAuth 2.1, or Authorization: Bearer csk_mcp_…
CostFree on every plan, including the sandbox

Choose how to authenticate#

OAuth, no token to manage

For clients that take a URL and sign you in: Claude on the web and Claude Desktop. Paste the URL, approve in the browser, done.

MCP token, one header

For clients that send a header: Claude Code, Cursor, Codex, VS Code, Windsurf, Zed, Gemini CLI. Create it in the dashboard.

Get an MCP token#

Dashboard → Settings → MCP → Create token. Copy it immediately; the full value is shown once and stored only as a hash.

  • Workspace-wide by default, so an agent can call list_apps and create_app before any app exists.
  • Narrow it to one app if you'd rather it could only touch that one. The restriction is real. A narrowed token gets 403 on a sibling app in the same workspace.
  • Choose Read only for analytics, diagnostics, and support agents that should inspect state without changing it. Read-only tokens receive 403 for every mutating API call, including calls made through MCP tools.
  • It does not expire. Revoke it in the dashboard when you're done, and any agent using it stops on its next call.

Any CashSDK token grants API access. Never commit one. If a config file is checked into your repo, put a placeholder there and have each developer supply their own.

Or use the setup token#

The integration prompt in your dashboard still contains a short-lived csk_st_… setup token, scoped to one app and to provisioning actions only. It's the zero-friction path for a first-hour onboarding, but it expires in 24 hours and minting a new one revokes the last, so it is the wrong thing to leave in a config file. Use an csk_mcp_… token for anything ongoing.

Client configuration#

Header-based clients need the URL and an Authorization header:

json
{
  "mcpServers": {
    "cashsdk": {
      "url": "https://mcp.cashsdk.com/mcp",
      "headers": { "Authorization": "Bearer csk_mcp_..." }
    }
  }
}

The exact file differs per client. See Claude Code, Cursor and Codex. For Claude on the web or Claude Desktop, add a custom connector and paste https://mcp.cashsdk.com/mcp; you'll be asked to sign in and pick a workspace.

Verify it's connected#

bash
curl -s https://mcp.cashsdk.com/mcp \
  -H "Authorization: Bearer csk_mcp_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | head -c 400

A list of tools comes back. Without a valid credential you get 401 with a WWW-Authenticate header carrying resource_metadata. That pointer is what tells an OAuth client where to authenticate, and what tells a token client its token has been revoked or has expired.

What an agent can't do#

Some of the API is refused for every MCP token, at every role, regardless of what the person who created it can do in the dashboard. An agent reads store listings, webhook payloads and READMEs, any of which can try to steer it, so the boundary is drawn in code rather than left to a prompt:

RefusedWhy
Billing, partner payouts, revenue-history importMoves real money, or what you're billed
Team members, invitations, SSO, SCIMDecides who can get in
Deleting a workspace, closing an accountIrreversible
Uploading store credentials (.p8, service-account JSON)A human step; the raw file shouldn't pass through a model
Rotating the ingest tokenSilently breaks store notifications until a human repastes the URL
Bulk data exportBulk PII egress
Creating another MCP tokenOtherwise a narrow token issues itself a wide one

Within what's left, a token can never exceed the member who created it, and every call passes the same AccessService and role checks a dashboard session does. The token's own read/write permission is enforced in addition to those checks.

Every change an agent makes lands in your workspace audit log with actorType: "agent" (or agent_setup for the onboarding setup token), alongside the member whose credential it used, so "was that change mine or my agent's?" has an answer. Reads are not logged, on MCP or anywhere else.

Rate limits#

EndpointLimit
POST /mcp600 requests/min per IP
POST /oauth/register20/hour per IP
POST /oauth/token120/min per IP

Set well above what a working agent does (a busy setup session bursts dozens of tool calls a minute) so you should never see one. They exist because these endpoints are unauthenticated by construction and would otherwise be free database load.

Tools#

Tools are grouped by what they touch. Each maps directly onto a REST endpoint, so results are the same JSON your backend would receive.

Workspace

| Tool | Description | | --- | --- | | list_apps | Every app in the workspace. Start here with no app id. | | create_app | Create an app from a bundle id or Android package name. | | get_app | Fetch an app's configuration. | | update_app_settings | Change app-level settings. |

Setup & diagnostics

| Tool | Description | | --- | --- | | get_setup_checklist | The live go-live checklist and what's outstanding. | | get_setup_diagnostics | Store-side problems, each with its fix. | | get_ios_integration_snippets | Ready-to-paste iOS integration code. | | get_android_integration_snippets | The same for Android. |

Catalog

| Tool | Description | | --- | --- | | get_catalog | List products and entitlements. | | create_product | Create a product (subscription or one-time). | | create_entitlement | Create an entitlement. | | grant_entitlement | Grant an entitlement to a customer. | | sync_catalog_from_app_store | Pull catalog data from the App Store or Google Play. | | push_catalog_to_app_store | Push your CashSDK catalog to the store. |

Paywalls, placements & experiments

| Tool | Description | | --- | --- | | list_templates | List available paywall templates. | | list_paywalls | List existing paywalls. | | get_paywall | One paywall's config, published and draft. | | create_paywall | Create a paywall from scratch. | | create_paywall_from_template | Create a paywall from a template. | | generate_paywall | Generate a paywall from a natural-language brief (draft only). | | publish_paywall | Publish the draft so devices receive it. | | list_placements | List placements. | | create_placement | Create a placement. | | list_campaigns | List campaigns. | | create_campaign | Create a campaign, or an A/B split with a holdout. | | get_experiment_results | Per-variant conversion, revenue and significance. |

Customers, revenue & keys

| Tool | Description | | --- | --- | | get_customer | Fetch a customer and their entitlements. | | list_transactions | List transactions. | | tail_recent_events | The most recent events. | | get_revenue_overview | Revenue, active subscriptions, trials and churn. | | list_api_keys | Key ids and masked values, never a raw secret. | | create_api_key | Create a new API key. | | rotate_api_key | Rotate an existing API key. |

Store notifications & webhooks

| Tool | Description | | --- | --- | | get_store_notification_urls | The ASSN (Apple) / RTDN (Play) URL to paste into the console. | | request_apple_test_notification | Ask the store to send a test notification. | | list_webhook_endpoints | Endpoints registered for an app. | | register_webhook_endpoint | Register a webhook endpoint URL. | | send_test_webhook | Send a test event to a webhook endpoint. |

Marketplace

| Tool | Description | | --- | --- | | list_marketplace_apps | Every connector this workspace can connect. | | list_marketplace_connections | What's connected, with lifecycle status. | | get_marketplace_status | One connection in full. | | connect_marketplace_app | Connect a billing backend or integration. | | start_marketplace_oauth | Begin a “Connect with X” OAuth flow. | | map_marketplace_catalog | Map a provider's plans to CashSDK products. | | validate_marketplace_connection | Check credentials, secret and mappings. | | activate_marketplace_connection | Start events flowing into the ledger. | | pause_marketplace_connection | Pause without disconnecting. | | disconnect_marketplace_app | Disconnect and wipe stored credentials. |

OAuth details#

For anyone implementing against it directly:

Endpoint
Protected-resource metadata/.well-known/oauth-protected-resource (RFC 9728)
Authorization-server metadata/.well-known/oauth-authorization-server (RFC 8414)
Dynamic client registrationPOST /oauth/register (RFC 7591)
AuthorizationGET /oauth/authorize
TokenPOST /oauth/token
RevocationPOST /oauth/revoke (RFC 7009)

PKCE is required and only S256 is accepted. Access tokens live one hour; refresh tokens live 30 days and rotate on every use. Redirect URIs are matched exactly against what the client registered, with a loopback exception for native clients (RFC 8252 §7.3).

Per-client setup#

Next steps#