Connected apps (OAuth connections)
List and revoke the OAuth/MCP applications connected to your account, such as Claude's remote MCP connector.
Uptimeify lets you connect third-party apps (like Claude Desktop / Claude.ai) via MCP OAuth. These two endpoints let the signed-in user list and revoke their own connections. They power the Settings → Connected apps page in the dashboard.
Both endpoints are session-authenticated (browser cookie), not token-based: they are not part of the wsm_/wsma_ API-token surface, and every operation is strictly scoped to the caller's own connections.
Scopes
A connection carries scopes, and each one covers exactly one area of your monitoring data. Fourteen scopes exist in total: seven read scopes plus their collective alias mcp:read, and six write scopes that let the connection change data in that area instead of just viewing it.
Read scopes
| Scope | Covers | Tools it unlocks |
|---|---|---|
mcp:monitors:read | Your monitors and their current state | list_monitors, monitor_status |
mcp:incidents:read | Incidents across your monitors | list_incidents |
mcp:checks:read | Check history and uptime figures | check_history, uptime_summary |
mcp:alerts:read | Notification channels, escalation configuration, alert history | list_alert_channels, alert_history |
mcp:statuspages:read | Status pages and maintenance windows | list_status_pages, list_maintenance_windows |
mcp:organization:read | Organization profile, customers and users | get_organization, list_users, list_customers |
mcp:billing:read | Billing and SMS usage | billing_summary |
mcp:read | Collective alias, covers the three operational areas above | the five tools of those three areas |
mcp:read is the scope a client requests when it asks for read access without naming an area, and it is what connections made before granular scopes existed carry. It is frozen to the three operational areas that existed when it was introduced (monitors, incidents, check history) and does not grow when a new area is added: the four newer read areas -- alerts, status pages, organization, billing -- must be requested by name, and only then does the consent screen offer them. Those connections are unchanged.
Write scopes
| Scope | Covers |
|---|---|
mcp:monitors:write | Create, change and delete monitors, including deleting a monitor and its history |
mcp:incidents:write | Create, change and delete incidents, including posting incident updates that subscribers receive |
mcp:maintenance:write | Create, change and delete maintenance windows; alerts are suppressed for the monitors a window covers |
mcp:statuspages:write | Create, change and delete status pages, including their design and custom domains; subscriber addresses stay out of reach |
mcp:alerts:write | Create, change and delete alert channels; deleting a channel stops alerts from reaching it |
mcp:organization:write | Create, change and delete customers (with their watched domains and IP addresses), tags, custom fields and scheduled reports, plus change or deactivate an existing member -- never create or delete one; bulk customer maintenance, the organization's own master data, billing, SMTP settings and API tokens stay out of reach |
All six back real tools today: mcp:monitors:write unlocks six tools (pause, resume, rename, change the check interval, create and delete a monitor), mcp:incidents:write unlocks four (acknowledge, resolve, post an update, delete a manual incident), mcp:maintenance:write unlocks three (create, change and delete a maintenance window), mcp:statuspages:write unlocks eight (create, change and delete a status page, change its design, and add, verify, activate and delete a custom domain), mcp:alerts:write unlocks three (create, change and delete a notification channel; only email and sms channels can be created this way, and none of the three compares state before writing), and mcp:organization:write unlocks nineteen -- five for tags, three for custom fields, three for scheduled reports, one for a member, and seven for customers together with their watched domains and IP addresses. See Authenticated tools (write) for the full list and what each one does. Three things that area deliberately does not offer, whatever the scope name suggests: there is no tool that creates a member and none that deletes one, only one that changes or deactivates an existing member; there is no bulk customer maintenance and no way to send a report by hand; and the organization's own master data cannot be changed at all. Two more are worth knowing before granting it: delete_custom_field does not delete a field, it retires it from the forms and the customer table while the definition and every captured value stay in the database, and delete_tag strips the tag from every maintenance window that used it, which can leave a window with no scope at all. update_user and update_customer are the only two tools in the area that compare a record's state before writing, and only when the connection also holds mcp:organization:read. The consent screen offers all six write areas as separate checkboxes, grouped apart from the read areas so ticking one is a deliberate, separate choice.
Whether a write scope actually does anything also depends on the deployment, separately from which scopes exist. Write tools are registered only when the deployment has switched them on; where they have not been, a connection holding every scope in this table still cannot create, change or delete anything. Ask whoever runs your Uptimeify instance rather than assuming from the scope catalogue alone.
There is deliberately no mcp:billing:write and no scope for credentials: nothing here cancels a subscription, changes a plan, or mints its own API token.
Checking a write scope on the consent screen also checks its read twin of the same name (mcp:monitors:write checks mcp:monitors:read, mcp:incidents:write checks mcp:incidents:read): the write tools compare a record's current state before writing, to avoid repeating a write a model already made, and that comparison needs read access to the same data. mcp:maintenance:write is the one write scope with no twin, by design -- maintenance windows are read under mcp:statuspages:read and stay there.
All 14 scopes -- the seven read areas, the mcp:read alias, and the six write areas -- are published in the OAuth discovery documents (/.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource), so a client can discover them rather than having to know them. A client that asks for no MCP scope at all is not turned away: mcp:read is added to the request, so the consent screen still offers the three operational read areas it covers, and the user can clear any of them. A request that already names an MCP scope is left exactly as it is, and is never widened.
A token sees only the tools whose scope it was granted. A connection holding mcp:incidents:read alone lists list_incidents in tools/list and no other account-bound tool: the rest are not hidden-but-callable, they are absent, and calling one anyway is refused. A token with no MCP scope at all sees no account-bound tools. Until 1 December 2026 there is one exception: connections created before the scopes were published carry only identity scopes, and until that date such a token is treated as if it held mcp:read so it keeps working. The exception applies only to a token with no MCP scope whatsoever, never to one holding a single area, and it ends on that date without further notice: after it, an identity-only token sees no account-bound tools. Re-authorizing a connection at any time replaces it with a real, narrowable scope. The anonymous check tools on /mcp (DNS, TLS, WHOIS and the rest) need no token and are outside this system entirely.
One tool's answer, not just its presence, depends on a second scope: billing_summary names each customer in its usage breakdown only when mcp:organization:read was granted alongside mcp:billing:read. With billing alone the breakdown carries public ids and usage figures and no names -- the customer list belongs to the organization area and does not come back through the usage figures.
Consent
Every authorization passes through a consent screen. It names the application that is asking, names the account it will be linked to, and offers each read and write area as a separate checkbox, with the write areas grouped apart from the read ones so granting one is a deliberate, separate choice. Clearing a box removes that scope before the authorization code is minted, so the token that comes out is narrower than what the client asked for.
prompt is forced to consent on our side, so an authorization request cannot skip the screen by omitting the parameter or by sending some other value. prompt=none is the one request we do not rewrite: it means "show no interface", and since we no longer issue anything without consent, the answer is the error redirect OpenID Connect asks for rather than a screen. Without a session the code is login_required, with a session it is consent_required.
The screen posts its selection to a session-only endpoint that verifies the pending authorization belongs to the signed-in account and narrows the stored scope to what was ticked. That endpoint is not part of the public API surface; its error codes are listed under error codes.
List connections
GET /api/oauth/connections
Returns the caller's own live OAuth connections, one entry per connected client. "Live" means the grant still has an open refresh window. Returns an empty array when the user has no connections.
Example (cURL)
curl -X GET "$BASE_URL/api/oauth/connections" \
-H "Cookie: $SESSION_COOKIE" \
-H "Accept: application/json"Response
[
{
"client_id": "claude-desktop",
"client_name": "Claude",
"connected_at": "2026-06-01T09:12:00.000Z",
"last_active": "2026-07-20T14:03:00.000Z",
"scope": "read-only"
}
]| Field | Type | Description |
|---|---|---|
client_id | string | The OAuth client identifier. |
client_name | string | Human-readable application name. |
connected_at | string (ISO 8601) | When the connection was first authorized. |
last_active | string (ISO 8601) | Most recent token activity for this client. |
scope | string | "read-only" when the connection holds no write scope (the common case), "read-write" when it holds at least one mcp:*:write scope. This reflects what was granted, not what a tool can currently do: a "read-write" connection can create, edit or delete something only where a tool exists for that scope and the deployment has write tools switched on (see Authenticated tools (write)) -- otherwise it is "read-write" in name only. |
Revoke a connection
DELETE /api/oauth/connections/:clientId
Revokes the caller's own grant for the given client: deletes its access/refresh tokens and consent record immediately. The app loses access right away; reconnecting requires the user to go through OAuth consent again.
Example (cURL)
curl -X DELETE "$BASE_URL/api/oauth/connections/claude-desktop" \
-H "Cookie: $SESSION_COOKIE"Response
{ "revoked": true, "client_id": "claude-desktop" }Common errors
| Status | data.code | Meaning |
|---|---|---|
| 401 | unauthorized | No active session (not signed in). Both endpoints. |
| 400 | missingClientId | DELETE only: the :clientId path parameter is missing. |
| 404 | unknownOauthConnection | DELETE only: the caller has no connection for that client_id (already revoked, expired, or never connected). See error codes. |