get_plan
Fetch one plan by UUID — the same kind-tagged row list_plans emits, with its one nested block and its cadence string.
Read one plan in full. The row is the same one list_plans emits, so an
agent that found a plan in the list reads exactly the same fields back, and the row
update_plan returns after a change is comparable field for field.
Reads go through the plan service, so the tenant scope and the token's scope:project: allow-list
both apply. An id the token cannot see answers RESOURCE_NOT_FOUND, indistinguishable from an id
that never existed.
`kind` names the ONE block you will find
Every plan carries a kind — subscription, pass or pass_series — and
the kind decides which single nested object accompanies it: billing, pass
or pass_series. The other two are absent, not null. Read the tag and you
know what you are holding; there is no nullable object to probe.
Every row also carries cadence, the human-readable duration the portal and the bot show — "Per Month", "Per 3 Hours", "For all 10 passes". Use it rather than deriving a duration yourself.
Requires ability
The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.
Runs the same action as
The REST endpoint and this tool share one action, so validation, permissions and events are identical.
Annotations
It reads and never changes anything.
Arguments
plan_id*stringUUID of the plan to fetch.
What it returns
{ "data": { "id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b", "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13", "name": "Premium Monthly", "description": "All-access pass", "price": "29.00", "currency": "USD", "kind": "subscription", "cadence": "Per Month", "active": true, "sales_cap": 10, "sales_cap_sold": 3, "position": 0, "paused_reason": null, "created_at": "2026-05-18T10:05:00+00:00", "billing": { "billing_cycle": "months", "billing_cycle_count": 1, "recurring": true, "trial_days": 7, "trial_cardless": false } }}price is a decimal string; currency is an ISO code. The block changes with the kind:
kind: pass
{
"kind": "pass",
"cadence": "Per 3 Hours",
"pass": {
"timezone": "America/New_York",
"recurrence": "weekly",
"sales_cutoff_minutes": 60,
"sales_cutoff_anchor": "before_start",
"next_window": {
"id": "3d5a8c72-b016-4e94-8fa7-61c209d4e738",
"starts_at": "2026-09-20T13:00:00+00:00",
"ends_at": "2026-09-20T16:00:00+00:00"
}
}
}pass.next_window is the next window still on sale, in UTC, or null when the schedule has nothing
left to sell — which also means the plan is not purchasable right now. For the full schedule call
list_pass_windows.
kind: pass_series
{
"kind": "pass_series",
"cadence": "For all 10 passes",
"pass_series": {
"timezone": "America/New_York",
"window_count": 10,
"starts_at": "2026-09-20T13:00:00+00:00",
"ends_at": "2026-11-29T22:00:00+00:00",
"seat_cap": 50,
"seats_remaining": 13,
"successor_plan_id": null
}
}seat_cap and seats_remaining are null on an uncapped season. successor_plan_id is set once
start_next_season has run; it is the plan current holders are
offered in the presale.
How it fails
RESOURCE_NOT_FOUNDunknown plan_id, a plan on another team's project, one outside the token's
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-subscription-plan:view.
How is this guide?
Last updated on