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
mcp.json’s auth block instead of a bearer token:
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.
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
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.
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 returns401 with a WWW-Authenticate header
pointing at this resource’s RFC 9728 Protected
Resource Metadata document:
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 anOrigin 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:
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.
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-linksandDELETE /review-links/{review_link_uid}(listing review links is on MCP) - Doctor blacklisted SKUs — the entire
/doctors/{uid}/blacklisted-skusresource - 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)
- 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
Calling a Tool
The MCP endpoint speaks JSON-RPC 2.0 over a singlePOST 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-RPCerror, 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):
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 the2026-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.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:
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.