Skip to main content

MCP server

A Model Context Protocol server over the management API. Point any MCP client at it and an assistant can answer "can we test payments yet", explain what is blocking a provider, and run a product sync — with exactly the permissions the key you give it carries.

https://mcp.paycraft.mobilebytesensei.com/

Transport is Streamable HTTP; authentication is the same pcsk_ bearer token as the REST API.

Connect​

Create a key under Settings → Developer API and grant it only the scopes the assistant needs.

Claude Code​

claude mcp add --transport http paycraft https://mcp.paycraft.mobilebytesensei.com/ \
--header "Authorization: Bearer $PAYCRAFT_KEY"

Claude Desktop​

In claude_desktop_config.json:

{
"mcpServers": {
"paycraft": {
"command": "npx",
"args": [
"-y", "mcp-remote", "https://mcp.paycraft.mobilebytesensei.com/",
"--header", "Authorization: Bearer ${PAYCRAFT_KEY}"
],
"env": { "PAYCRAFT_KEY": "pcsk_your_key_here" }
}
}
}

Any client​

curl -X POST https://mcp.paycraft.mobilebytesensei.com/ \
-H "Authorization: Bearer $PAYCRAFT_KEY" \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

initialize, tools/list, tools/call and ping are implemented. GET returns 405 — this server never initiates messages, so it declines to hold open a stream that would only ever be idle.

Tools​

ToolEffectScope
paycraft_appsList the apps this key reaches — start here with an account keyapps:read
paycraft_create_appCreates an app and returns its publishable keyapps:write
paycraft_attach_providerAttaches a provider credential the account already holdsproviders:write
paycraft_readinessProvider readiness, per mode, with manual stepsreadiness:read
paycraft_tenantPlan, limits, and the key's own scopestenant:read
paycraft_productsList the catalogueproducts:read
paycraft_productOne product with pricingproducts:read
paycraft_providersConnected providersproviders:read
paycraft_sync_reportDrift report — what a sync would doproducts:read
paycraft_sync_runRuns the sync drainproducts:sync
paycraft_create_productAdds a product to the catalogueproducts:write
paycraft_update_productChanges named product fields (merge-safe; trial_per_platform:null clears)products:write
paycraft_set_product_pricingSets a product's per-country prices (upsert; does not reach a store)products:write
paycraft_sync_productSyncs one productproducts:sync
paycraft_retire_productStops sales at the live stores, then deactivates the rowproducts:write
paycraft_sync_eventsPer-provider events for a runproducts:read
paycraft_subscribersSubscription recordssubscribers:read
paycraft_entitlementsCanonical entitlement statesubscribers:read
paycraft_couponsDiscount codescoupons:read
paycraft_paywallPaywall configurationpaywall:read
paycraft_webhooksInbound webhook deliverieswebhooks:read
paycraft_auditAudit trailaudit:read

The two write tools are annotated destructiveHint: true, so clients that surface the distinction will flag them before running.

Onboarding a fresh app, end to end​

One credential for the whole sequence — the account's pcsk_ key. Nothing else is needed and no provider secret ever travels.

1. paycraft_apps → learn which apps this key reaches
2. paycraft_create_app → the new app + its publishable pk_ key
3. paycraft_attach_provider → once per provider (stripe, google_play, app_store, …)
4. paycraft_create_product → once per tier (weekly / monthly / quarterly / annual)
5. paycraft_set_product_pricing → per-country prices for each product
6. paycraft_sync_product → push each to its providers
7. paycraft_readiness → what still needs a human

Every step is idempotent, so an interrupted chain is safe to re-run: step 2 returns the existing app with created: false, step 4 refuses a duplicate SKU unless you pass upsert, and step 5 upserts per locale.

Steps 1–5 never touch a storefront. Only step 6 writes to a live provider. A catalogue that exists in PayCraft and has not been synced is not on sale, which is why every write response says synced: false and names the sync call rather than letting the absence of an error read as "shipped".

Credentials are added once, by a human, in the dashboard​

paycraft_attach_provider takes an account_id, never a key. Provider secrets live encrypted in the account's provider_accounts row and are read only server-side by the sync; the API refuses a body containing secret/api_key/credential outright. So the first app on a new Stripe account still needs someone to paste that credential into the dashboard once — every app after it just attaches, and the secret never enters an API call, a log, or an assistant's context.

Omit account_id to take the account's default connection for that provider. With several and no default, the tool refuses and lists the candidates rather than guessing which account to bill through.

What step 7 cannot do for you​

Both native stores flip test-readiness only after a REAL sandbox purchase, and expose no API to set or check it. paycraft_readiness reports that as an ordered manual_steps list. A chain that reported itself complete without it would be asserting a purchase nobody made.

How it stays safe​

Tools call the REST handlers, not the database. Authentication, scope enforcement, tenant filtering, pagination clamping and the confirm-count gate all live in those handlers. A second implementation would have to stay in step with them forever, and the half that drifted would be the half deciding who reads whose billing data. Connecting an assistant therefore grants nothing its key did not already allow.

Give it a read-only key. Grant only read scopes and the write tools refuse with a clear message. The safest assistant is one that cannot spend money.

Writes still ask twice. paycraft_sync_run requires the count from paycraft_sync_report. An agent cannot bulk-write to live providers on a set nobody looked at.

Everything is attributable. Actions land in the audit trail as actor_type=api_key with the key id — readable through paycraft_audit.

What an assistant cannot do​

Google Play and App Store test mode cannot be enabled by any tool. Neither store exposes an API for it. Those readiness rows carry ordered manual_steps for a person with a device, and turn green only when a real sandbox purchase reaches PayCraft.

A good assistant relays those steps. It should never claim to have completed them — and the server tells it so in the instructions returned at initialize.

Good first questions​

Once connected, these exercise the tools naturally:

  • "Can we take test payments yet? What's blocking anything that isn't ready?"
  • "Show me what a product sync would change before we run it."
  • "Did any webhooks fail in the last day, and why?"
  • "Is [email protected]'s subscription active, and does their entitlement agree?"

The last one is worth understanding: a subscription is what a provider bills, an entitlement is what PayCraft grants. They disagree during grace periods and refunds, and the entitlement is the one your app should trust.