Skip to main content

Management API MCP

The Management API exposes an MCP (Model Context Protocol) endpoint so AI clients — Cursor, Claude Desktop, and other MCP-compatible tools — can read and write your organisation’s data directly, without a custom integration. It is the same Management API you already use over REST: MCP is an additional transport on the same service, exposing a curated allowlist of tools rather than every REST route.
MCP is additive. Your existing API key integrations, webhooks, and REST calls are completely unaffected — this page only concerns connecting an AI client.

Connect

Add this URL to your MCP client’s server configuration. Cursor, for example, supports static OAuth client credentials for a remote server that issues its own fixed client ID rather than supporting Dynamic Client Registration — which is how this endpoint is set up. RxScale provisions an Auth0 application for your organisation and gives you its client ID; put that in mcp.json’s auth block instead of a bearer token:
Set RXSCALE_MCP_CLIENT_ID in your shell environment rather than writing the client ID literally into the file — Cursor interpolates ${env:...} in the auth block the same way it does in headers. Always set scopes explicitly to the list of permission strings (see Permissions) your RxScale account manager has confirmed are provisioned for your client — request only what your use of the client actually needs.
Do not omit scopes to “get everything.” Cursor’s documented fallback for an omitted scopes field is to discover scopes_supported from the Auth0 tenant’s own /.well-known/oauth-authorization-server metadata — the authorization server’s tenant-wide list, not a list scoped to this MCP resource specifically (RxScale’s Auth0 tenant hosts other APIs’ scopes too). Cursor does not derive per-API permissions from this resource’s RFC 9728 metadata or from Auth0 AS metadata; the only reliable way to get exactly the permissions your client should have is to list them explicitly in scopes.
Dynamic Client Registration is not enabled for this rollout — the client ID above is one RxScale issues to your organisation, not one Cursor registers on the fly. Before sign-in can work at all, two things must exist out-of-band: ask your RxScale account manager for a client ID, and have them register Cursor’s fixed OAuth redirect URL(s) against it in Auth0 — Cursor documents fixed callback URLs per surface, not a single one:
  • Web and Cursor Agents: https://www.cursor.com/agents/mcp/oauth/callback
  • Desktop app: http://localhost:8787/callback
Register both if your organisation’s users sign in from both the web/Agents surface and the desktop app; register only the one you use otherwise. Sign-in fails with a redirect-URI mismatch until the client ID is provisioned and the redirect URL(s) you need are registered. Only once both of those exist does connecting prompt you to sign in through your organisation’s Auth0 login page — there is still no API key or client secret to paste into the config file, but there is out-of-band setup RxScale must do first.
If your client only supports a static header rather than an auth block for OAuth — or you want a non-interactive token for a script — request one yourself with the client credentials grant below and reference it the same way Cursor’s headers field supports environment interpolation:

Authentication

The MCP endpoint accepts the same credentials as the rest of the Management API — see Authentication for the full details — with one important difference: its Bearer tokens are issued for a separate OAuth audience from the REST API. A token issued for one audience is rejected on the other. Requesting a token for the MCP audience uses the same OAuth 2.0 client credentials grant described in Authentication, with audience set to the MCP endpoint’s own URL:
scope is a space-separated list of the same permission strings used on REST (see Permissions) — request only what the calling client needs; the resulting token’s tools are limited to those, exactly like an API key’s permissions.
A machine-to-machine application’s token carries sub = <client_id>@clients, and RxScale must register that sub as a service principal in your organisation before it can call anything — scopes alone are not sufficient. Until then the endpoint answers 401 with {"code": "user_not_found"}. See Getting a Bearer token.
For an interactive AI client (Cursor, Claude Desktop), you generally do not need to run this request yourself. The client discovers the required Auth0 authorization server from the MCP endpoint’s metadata and takes you through sign-in with the RxScale-provided Auth0 application. Use the client credentials grant above only for a custom or headless client that does not implement OAuth discovery — set the resulting access_token as an Authorization: Bearer header (or your client’s equivalent custom-header setting).
API keys (X-API-Key) also work on the MCP endpoint, scoped by the same permissions as on REST — useful for a client that only supports a static credential.

Client compatibility (OAuth discovery)

An unauthenticated request to the MCP endpoint returns 401 with a WWW-Authenticate header pointing at this resource’s RFC 9728 Protected Resource Metadata document:
Strict RFC 9728 clients (for example VS Code’s MCP support) require the metadata document’s resource field to be the exact canonical URL of the MCP endpoint itself — not the broader Management API root — which is why the MCP audience above is the /mcp URL rather than https://api.rxscale.com/v1/management. This discovery flow only gets a client to the point of finding the authorization server and initiating sign-in; it does not remove the prerequisite described in Connect above — RxScale must still provision your organisation’s client ID and register the exact redirect URL(s) your client uses in Auth0 before that sign-in can succeed.

Browser-based clients and Origin allowlisting

A request that carries an Origin header — which only a browser sends — is checked against this service’s allowlist before authentication runs. An origin that isn’t on the allowlist is rejected outright, with 403 and no attempt to read credentials:
Every non-browser MCP client — Cursor, Claude Desktop, a script using curl or an HTTP library — never sends Origin at all and is completely unaffected by this check; it exists to stop a web page from driving this endpoint through your browser’s cookies via DNS rebinding, an attack that has no relevance to a non-browser caller. It only matters if you are building your own browser-based MCP client — a web app that calls this endpoint directly from JavaScript running in a page. If that’s your case, contact your RxScale account manager with the exact origin (scheme://host[:port], e.g. https://app.example.com) you need allowlisted; it cannot be added by the client itself, and there is no self-service way to register one.

Allowed Tools

tools/list only ever returns the tools your token’s permissions allow — the same EnumAPIKeyPermission scopes checked on REST. Every tool dispatches through the identical handler and serialization path as its REST equivalent, so the two surfaces cannot return different JSON for the same data.
get_questionnaire_submission_statistics requires statistics:read, not questionnaire:read — it wraps a statistics endpoint, so it is gated the same way its REST route is, even though it is grouped with the other questionnaire tools by subject.
health_check still requires some valid credential — an API key, or a Bearer token issued for the MCP audience specifically — even though it needs no permission. A Bearer token issued for the REST audience is rejected here just like on any other tool, because the MCP route validates against MCP_API_AUDIENCE, not the REST API_AUDIENCE (see Authentication above). This differs from the REST GET /health endpoint, which requires no authentication at all: every MCP call, including health_check, first goes through this endpoint’s own authentication, while /health is deliberately left open so infrastructure can probe it unauthenticated.

Not available over MCP

Only the tools listed above exist. There is no generic “call any REST endpoint” tool, and adding a new tool is a deliberate catalog change on RxScale’s side — a tool never appears just because a REST route exists. REST-only Management API operations. These endpoints exist and behave exactly as documented on their own REST reference pages; they are simply not on the MCP allowlist in the current release:
  • Order intake and fulfillment — creating an order, updating one, creating a fulfillment, and cancelling a fulfillment (Order Intake)
  • Prescription signing — rendering a prescription PDF or marking one externally signed
  • Notification subscriptions (webhooks) — the entire /notification-subscriptions/ resource: listing, creating, removing, and test-sending (Webhooks)
  • Waiting room — registering, checking the status of, or cancelling a waiting-room entry (Waiting Room)
  • Listing request decisions — accepting or declining a pending listing request (listing and getting a listing request are on MCP; only the accept/decline actions are REST-only)
  • Wallet pass verification and push notifications (listing templates and passes is on MCP)
  • Patient profile field deletion
  • Patient intent status — GET /patients/{patient_uid}/intent/{intent} (listing and getting a patient by UID or email is on MCP; this narrower lookup is REST-only)
  • Review link create and revoke — POST /review-links and DELETE /review-links/{review_link_uid} (listing review links is on MCP)
  • Doctor blacklisted SKUs — the entire /doctors/{uid}/blacklisted-skus resource
  • Scheduling administration writes — cancelling an appointment, and all appointment-type and doctor-availability-rule/date-override CRUD (only listing appointments and appointment types is on MCP)
Not available via the Management API at all — not on REST, and therefore not on MCP either. These are not missing MCP tools; the underlying capability isn’t exposed by this API for any client today, so there is no REST page to link to:
  • Deleting a product or a questionnaire
  • Questionnaire authoring features (custom CSS, file assets, archiving, duplication) — Admin Tool-only
  • Nested SKU attribute graphs beyond the create/patch shape documented on Products
  • Statistics CSV exports
  • Referral-scan and referral-conversion statistics
Use the Management API REST reference for the first group of operations.

Calling a Tool

The MCP endpoint speaks JSON-RPC 2.0 over a single POST route — no separate handshake is required. tools/call takes the tool name and its arguments, matching the tool’s inputSchema from tools/list:

A successful call

Two different kinds of failure

MCP distinguishes a request the server couldn’t even attempt (a protocol-level JSON-RPC error) from a tool that ran and reported a failure of its own (a domain-level result). This endpoint keeps that distinction rather than collapsing both into the same shape: Protocol-level — a top-level JSON-RPC error, no result at all. An unknown tool name, a missing name, arguments that aren’t an object, an argument key the tool’s inputSchema doesn’t define, or arguments that fail the tool’s own schema validation all fail before the tool runs, as error.code -32602 (Invalid params):
A top-level JSON-RPC method this endpoint doesn’t support at all (as opposed to a tool name inside tools/call) fails the same way with error.code -32601 (Method not found). Domain-level — a normal result, with isError: true. The tool name and arguments were valid and dispatch actually ran — and that is what failed: a permission the token lacks, or a UID that doesn’t exist or belongs to another organisation. This is not a JSON-RPC error; it is a successful RPC call whose payload happens to report failure, shaped like the success example above but with isError: true, a human-readable message in content, and a machine-readable structuredContent.code:
structuredContent.code is permission_denied when the token lacks the tool’s required permission, or not_found when the UID doesn’t exist or belongs to another organisation.
Two JSON-RPC protocol revisions are supported on this same endpoint: a stateless header-routed form (Mcp-Protocol-Version: 2026-07-28) that most current MCP clients use, and the earlier initialize-handshake form (2025-11-25). Both are handled transparently — your MCP client selects the revision it understands, and you do not need to configure this.

Headers for custom and headless clients

An interactive MCP client (Cursor, Claude Desktop) sets these automatically; you only need to know about them if you’re writing your own client against the 2026-07-28 stateless revision rather than using an off-the-shelf one:
Any of these three headers may be sent in the MCP spec’s Base64 sentinel form, =?base64?<base64-of-the-value>?=, instead of a plain value — required when the value cannot safely travel as a raw ASCII HTTP header. The server decodes the sentinel and compares the decoded value against the JSON-RPC body; an undecodable sentinel is rejected the same way a mismatched plain value is.
A 2026-07-28 request missing Mcp-Method (or, for tools/call, missing Mcp-Name) is rejected with 400 and JSON-RPC error code -32020 before dispatch — on that revision, these headers are load-bearing for routing, not optional metadata. The response still carries the request’s own id (a header-routing failure is not a notification) and a data object naming the header and the value it was compared against:
An Mcp-Protocol-Version header naming a version this endpoint doesn’t support is rejected with 400 and JSON-RPC error code -32022, with data.requested and data.supported (the list from Two JSON-RPC protocol revisions above) so the client can retry with a version it supports:

Error Responses

A tool-level failure (permission_denied, not_found) is always 200 with result.isError: true — it never becomes an HTTP error status. Only a protocol-level fault (malformed JSON-RPC, unknown method or tool, invalid arguments, a disallowed Origin, bad credentials) changes the HTTP status away from 200.