MCP server
Connect Claude, Cursor and other MCP clients to Unhandled over OAuth and let them query and act on your telemetry.
unhandled runs a Model Context Protocol server. Connect an AI assistant to it and the assistant can read your issues, traces, logs, metrics, monitors and alerts, and, if you grant it, change some of them. You sign in through OAuth in the browser, so there is no API key to copy into a config file.
Connect a client
Every client below uses the same server URL, /mcp on your Unhandled domain. Replace https://unhandled.example.com with yours.
Sign in to unhandled
Open Unhandled in your default browser and sign in. The client sends you to a consent page that only signed-in users can open.
Add the server to your client
claude mcp add --transport http unhandled https://unhandled.example.com/mcpThen run
/mcpinside Claude Code and pickunhandledto sign in.Add the server to
~/.cursor/mcp.json, or to.cursor/mcp.jsonin a project:{ "mcpServers": { "unhandled": { "url": "https://unhandled.example.com/mcp" } } }Add the server to
.vscode/mcp.jsonin your workspace:{ "servers": { "unhandled": { "type": "http", "url": "https://unhandled.example.com/mcp" } } }Open Settings > Connectors, choose Add custom connector, and paste
https://unhandled.example.com/mcpas the URL.Any client that supports remote MCP servers with OAuth works with the same URL. The client's first request gets
401with a pointer to the protected resource metadata, and the client registers itself from there.Approve access
The client opens Unhandled's consent page. Pick the organization this connection may use. If the client asks for write access, you can choose Read only instead of Read and write. Then click Allow access.
Ask a question
Try "which issues regressed in production since yesterday?" or "why did the checkout monitor go down?".
/mcpMCP requestsThe server speaks the Streamable HTTP transport in stateless mode. Each JSON-RPC message is its own POST /mcp, answered with a JSON response. The server offers tools only, with no resources or prompts.
authorizationstringrequiredBearer <access token>. A missing, expired or revoked token returns401with awww-authenticateheader that points at the protected resource metadata.content-typestringrequiredapplication/json. A body that is not valid JSON returns400with the JSON-RPC parse error-32700.
GET /mcp and DELETE /mcp return 405 with an allow: POST header, since the server keeps no sessions.
A request with an Origin header must come from the Unhandled app URL, a loopback address, or an origin listed in the MCP_ALLOWED_ORIGINS environment variable (comma-separated). Any other origin gets 403. Requests without an Origin header, which is how most MCP clients connect, are not affected.
Limits
| Limit | Value | Over the limit |
|---|---|---|
| Requests per access token | 120 a minute | 429 with a Retry-After header |
| Tool calls per organization | 600 a minute, across all connections that reach it; only calls that pass every check count | The call returns an error result: "Too many calls right now; retry after N s" |
| Tool calls per member in an organization | 200 a minute, across all of that member's connections | The call returns an error result: "Too many calls right now; retry after N s" |
create_organization per user | 5 an hour, shared with organizations created in the app | The call returns an error result: "Too many calls right now; retry after N s" |
Organizations a user administers, for create_organization and the app | 10, set with ORGANIZATIONS_PER_USER (MCP_ORGANIZATIONS_PER_USER still works as a fallback) | The call returns an error result that names the limit |
create_invitation per user | 20 an hour, shared with invitations sent from the app; at most 3 a day to one address and 100 a day from one organization | The call returns an error result: "Too many calls right now; retry after N s" |
| Live connections per user and app | 5, set with MCP_CONNECTIONS_PER_APP | A new consent revokes the oldest connection |
test_monitor and test_notification_channel per user | 10 a minute each, shared by all your connections | The call returns an error result: "Too many calls right now; retry after N s" |
| Status page subscriber emails per organization | 10 an hour across all connections, set with MCP_SUBSCRIBER_NOTIFICATIONS_PER_HOUR | The call returns an error result: "Too many calls right now; retry after N s" |
accept_invitation per user | 10 every 15 minutes, shared with the browser | The call returns an error result: "Too many calls right now; retry after N s" |
submit_doc_feedback per user | 30 an hour, shared with the browser | The call returns an error result: "Too many calls right now; retry after N s" |
| Requests per IP address | 600 a minute | 429 with a Retry-After header |
| Tool calls running at once, per access token | 4, plus 4 waiting | The call returns an error result: "Too many calls right now; retry after 2 s" |
| Time per tool call | 25 seconds | The query is cancelled and the call returns "Query timed out; narrow the range or add filters" |
When a tool fails for a reason the caller cannot fix, the result says the tool failed unexpectedly and the server logs the details. It never returns the database error. Calling a tool that does not exist returns the JSON-RPC error -32602.
OAuth endpoints
Unhandled is its own OAuth 2.1 authorization server. MCP clients discover and call these endpoints on their own. You only need them when you write a client yourself.
/.well-known/oauth-protected-resource/mcpProtected resource metadataRFC 9728 metadata for the /mcp resource. /.well-known/oauth-protected-resource returns the same document.
/.well-known/oauth-authorization-serverAuthorization server metadataRFC 8414 metadata: the endpoints below, the supported scopes, and S256 as the only PKCE method.
/oauth/registerRegister a clientRFC 7591 dynamic client registration. Send 1 to 10 redirect_uris and an optional client_name. Each redirect URI must use https, a loopback http address or an app scheme. One IP address can register 10 clients an hour.
/oauth/authorizeConsent pageShows the consent page to a signed-in user. The request needs response_type=code, a code_challenge and code_challenge_method=S256. The user's decision posts back to POST /oauth/authorize.
/oauth/tokenExchange or refresh a tokenAccepts the authorization_code grant with the PKCE code_verifier, and the refresh_token grant. Each client_id can call it 60 times a minute and each IP address 120 times a minute. Over the limit it answers 429 with a Retry-After header.
/oauth/revokeRevoke a tokenRFC 7009 revocation. Send the access or refresh token as token, and optionally your client_id.
Clients are public: they get no client secret and must use PKCE.
| Credential | Lifetime |
|---|---|
| Authorization code | 10 minutes |
| Access token | 1 hour |
| Refresh token | 30 days, replaced on every refresh |
A refresh token works once. If a client sends any refresh token the grant has already rotated away from, Unhandled revokes the whole grant and the client has to ask for consent again. An authorization code also works once; redeeming it a second time revokes the tokens the first exchange issued.
Scopes and access
A connection belongs to you, not to one organization. Every app registers itself, so the consent page marks it Unverified app, notes that the app chose its own name, and shows the address it sends you back to and the day it registered. On the consent page you pick two things:
- What it can do. Check scopes one by one, or start from the Read only, Triage or Full preset. Only read scopes start ticked, even when the client asks for more; you tick each write scope yourself. You can drop scopes the client asked for, but you cannot add any. Triage is every read scope plus
issues:writeandalerts:write. It leaves outstatus:write, which posts on your public status page and emails subscribers. - Where. Either All organizations, including ones I join later, or only the organizations you tick. The page starts with only the organization you are working in ticked (your first one if you have not opened one yet). With no organization, nothing is ticked, so reaching the ones you create or join later is a choice you make.
| Scope | Grants |
|---|---|
org:read / org:write | whoami, get_ingest_domain, get_organization and get_retention_settings / rename, re-slug and delete the organization, set its avatar and change data retention |
members:read / members:write | Members, invitations and teams / invite, change roles, remove members, manage teams and leave the organization |
projects:read | list_apps, list_environments, get_project, list_services |
projects:write | Create, change and delete projects and services, and change exception scrubbing |
keys:write | Issue, reveal, rotate and revoke DSNs, deploy keys, heartbeat URLs and webhook signing secrets: setup_service, rotate_service_key, revoke_service_key, create_deploy_key, revoke_deploy_key and get_heartbeat_url, which issue, show or revoke secrets. Revealing or rotating a webhook channel's signing secret needs channels:write too |
telemetry:read | Traces, logs, metrics, exceptions, occurrences, performance tools and the service map, including the names and emails of the end users your apps track |
issues:read / issues:write | Read issues / triage, assign, merge, comment on and link them, edit ownership rules and auto-resolve, and create Linear or GitHub tickets with any text |
alerts:read / alerts:write | Read and preview alerts and channels / create, change, pause, resume and delete alerts, respond to incidents, manage exception rules and mute exception notifications per channel kind |
channels:write | Add, change and delete the Slack, Discord and webhook channels alerts are sent to, and send test messages to any URL, not only saved channels |
uptime:read | Monitors, checks and outages |
uptime:write | Create, change, retarget and delete monitors. The server sends HTTP, TCP and DNS requests, with the headers you set, to any public host |
status:read / status:write | Status pages and incidents / report and update incidents, create, change and delete the status page, and list and remove its subscribers |
billing:read | get_billing and get_usage_report |
dashboards:read / dashboards:write | Read / create, change and delete dashboards and widgets |
deployments:read / deployments:write | Deployments, running versions, deploy keys and source maps / delete source maps |
integrations:read / integrations:write | GitHub and Linear connections and their targets / map projects to targets and disconnect |
feedback:read / feedback:write | Read feedback threads / send, reply to and triage them and rate docs pages |
account:read / account:write | Your profile, notification preferences, inbox and received invitations / change them |
organizations:create | create_organization |
invitations:accept | accept_invitation: join organizations you are invited to, at the invited role. Never ticked by default and only in the Full preset |
The consent page only offers scopes that some tool uses. Clients that still request the old scopes get the scopes of the tools those covered. mcp:read becomes org:read, projects:read, telemetry:read, issues:read, alerts:read, uptime:read, status:read, dashboards:read and deployments:read. mcp:write becomes issues:write, alerts:write, status:write and dashboards:write, so it no longer reaches setup_service. A client that requests no scope is offered every scope, with Read only ticked.
Every call has to pass three checks. A call runs only when all three allow it:
- The connection was granted the tool's scope.
- The organization's MCP policy allows that scope. Admins set it in Settings, MCP: MCP access on or off, and optionally a list of the most an app may do there. Changes apply to the next call. The
account:*scopes are yours, so a policy's list of scopes does not cover them, but turning MCP off for an organization also stops the inbox and notification preference tools there. - Your role allows the action. Each tool uses the same permission check as the page it mirrors, so a member can triage issues, preview alerts and create dashboards, while creating alerts, projects or services needs an admin.
A refused call returns an error result that names the reason, for example Organization "acme" does not allow the issues:write scope over MCP. While an organization is suspended, every tool that changes something returns an error there.
Tools that act inside an organization take an organization argument (its slug). It is required only when the connection reaches more than one organization; whoami lists them. whoami and list_apps cover every organization the connection reaches. Leave an organization and the connection stops reaching it on the next call. An admin can also cut a connection off from their organization; editing the connection or leaving and rejoining does not undo that.
A connection that covers only the organizations you ticked never grows by itself. create_organization adds the organization it creates. accept_invitation does not. After joining, a connection for all organizations reaches the new one, and any other needs you to add it under Connected apps.
Changes made through MCP appear under your user, for example in an issue's activity. They notify people the same way the app does, so assignees get the usual emails.
Calling tools
Most tools accept these optional arguments:
projectstringProject slug. Required when the organization has more than one project.
environmentstringdefaultproductionproduction,stagingordevelopment.servicestringTelemetry name of one service.
rangestringdefault24h15m,1h,6h,24h,7dor30d.fromstringISO timestamp that starts a custom window. With
to, the window can span up to 90 days.tostringISO timestamp that ends a custom window.
cursorstringThe
nextCursorof the previous page. List tools return up to 50 items per page. A cursor that the server cannot read returns the JSON-RPC error-32602.
Every response repeats the project, environment, service and window it used, so the assistant knows exactly what it looked at. Results come back as JSON in a single text block. When the caller can fix the problem, such as an unknown project or service, the error names the valid choices.
A result is at most 256 KiB. A list page that would pass the limit returns fewer items, truncated: true and a nextCursor for the rest. Other results that are too large have their long strings cut to 2,048 characters, then 256, and carry a truncationNotice. If the result still does not fit, the tool asks the caller to narrow the request.
Human approval for sensitive actions
Each organization has the setting Require human approval for sensitive agent actions under Settings, MCP. It is on by default, only admins can change it, and every change appears in the organization's MCP Activity list.
While it is on, a sensitive call does not run, even with confirm: true. It returns a result like this instead:
{
"status": "approval_required",
"approvalId": "6f0c…",
"approvalUrl": "https://unhandled.net/mcp/approvals/6f0c…",
"expiresAt": "2026-10-24T15:15:00.000Z",
"action": { "tool": "create_invitation", "organization": "acme", "description": "grants [email protected] admin access" },
"next": "Nothing ran. Ask the user to open … then call create_invitation again with exactly the same arguments plus approvalId."
}The person who connected the app, or anyone in the organization with at least their role, opens the link while signed in. The page shows the tool, the app, the requester and the exact arguments, with secret values hidden: channel and monitor URLs show only their origin, and custom header values show as (hidden). Approving needs a sign-in from the last 15 minutes or the account password; denying does not. The agent then repeats the call with the same arguments plus approvalId. The approval is bound to the connection, the user, the organization, the tool and a keyed hash of the full arguments, hidden values included, expires after two hours (on a self-hosted server, MCP_APPROVAL_TTL_MINUTES sets another length), and runs once. It is used up only when the call succeeds: a call that fails leaves it ready for a retry, and parallel calls with one approval run the action once. A call with any other argument, from another connection, or after it was used, denied or expired is refused. Stored arguments are redacted and encrypted with the app key. Admins see every approval under Settings, MCP, Approvals until an hour after it expires; the hourly mcp.prune job then deletes it.
These calls are sensitive:
create_invitationwith roleadmin,update_memberpromoting to admin,remove_member;update_monitormoving a monitor that sends custom headers to another origin, or leaving it with no channel;create_notification_channel,update_notification_channelwith a new URL,delete_notification_channel,reveal_notification_channel_secret,rotate_notification_channel_secret;- silencing alerting:
pause_monitor,delete_monitor,pause_alert,snooze_alert,delete_alert,update_alertleaving an alert with no destination or changing the condition of a firing alert,create_exception_rulewithmuteKind; delete_organization,delete_project,delete_service,delete_team,delete_status_page,disconnect_integration,remove_ingest_domain;- issuing or revoking credentials:
setup_service,create_deploy_key,get_heartbeat_url,rotate_service_key,revoke_service_key,revoke_deploy_key; update_retention_settingslowering any category;- every call that publishes text outside the organization:
create_status_pagewithpublic: true,update_status_pagepublishing a page or changing the text of a public one,create_status_incidentorupdate_status_incidentwriting to a public incident on a public page or withnotifySubscribers: true,create_monitororupdate_monitorchanging a monitor shown on a public page, andlink_issuewith your ownteam,titleorbody; accept_invitationandcreate_organization. These belong to no organization, so they wait for approval unless every organization you belong to turned the setting off.
When the setting is off, these calls need confirm: true as before.
Untrusted text in results
Much of what a result carries was written by someone other than Unhandled or you: exception messages, log lines, span attributes, AI conversations and analytics events reported by your apps and their users, plus names, comments and descriptions written by members. Anyone with a public DSN can put text there, so an assistant must never follow it as an instruction.
A result is always one JSON text block. When it holds such text, the result's _meta lists those fields under unhandled.net/untrustedFields. Each entry is a path into the JSON, with [] for every item of a list, such as items[].message. A path that ends at an object, such as items[].attributes, covers everything inside it. Only text the server formats itself, such as timestamps, cursors and truncation notices, is left off the list. The server's instructions and every tool description repeat that this text is data, never instructions.
{
"content": [{ "type": "text", "text": "{\"project\":\"default\",\"items\":[{\"id\":\"1f0…\",\"name\":\"api-health\"}],\"nextCursor\":null}" }],
"_meta": { "unhandled.net/untrustedFields": ["items[].id", "items[].name", "project"] }
}Values keep exactly what was stored, so an agent can pass them back unchanged. Characters that hide or reorder text for a person reading along arrive as \u escapes inside the JSON instead of raw: bidirectional controls, zero-width spaces, word joiners, line and paragraph separators, byte order marks, C1 controls and Unicode tag characters. Decoding the JSON gives back the original value. Zero-width joiners stay raw, since emoji and many scripts need them.
Safe retries
The tools that create something accept an optional requestKey of 1 to 200 characters: create_organization, create_project, create_alert, create_dashboard, add_widget, add_issue_comment, create_status_incident, update_status_incident, add_ingest_domain, create_invitation, create_team, create_feedback_thread, reply_feedback_thread and submit_doc_feedback. Repeat a call with the same key within 24 hours and the server returns the first result instead of acting twice. Reusing a key for a different call returns an error. setup_service, rotate_service_key and create_deploy_key take no key, because a replay would have to store the secret they issued, so each call issues a new one. A replay goes through every check again first, so a call your connection may no longer make is refused rather than answered from the earlier result. Secrets in a result, such as a heartbeat URL from create_monitor, are never stored; a replay returns a note to fetch them with get_heartbeat_url.
Every tool in tools/list carries the MCP annotations readOnlyHint, destructiveHint, idempotentHint and openWorldHint, so clients can decide which calls to confirm with you. Tools that delete, revoke, disconnect or stop something, such as delete_project, revoke_service_key or pause_alert, are marked destructive and run only when the call passes confirm: true. Some tools need confirm: true only for certain arguments, and say so in the error when it is missing: rotate_service_key with grace none, update_member demoting an admin, update_team or update_project removing entries from a list, bulk_update_issues on more than 25 issues, update_issue_settings lowering autoResolveDays, update_retention_settings lowering any category, update_exception_settings turning scrubbing off or weakening it, rotate_notification_channel_secret, and create_status_incident or update_status_incident writing to a public incident on a public page or with notifySubscribers true. create_invitation with role admin and update_member promoting to admin need it, and both email the organization's other admins. Calls that silence or reroute notifications need it too: update_alert leaving an alert with no destination or changing the condition of a firing alert, create_exception_rule with muteKind, update_monitor closing an ongoing outage or leaving a monitor with no channel, and create_notification_channel or update_notification_channel with a URL no channel of the organization uses yet. So do calls that change what anyone can read: create_status_page or update_status_page publishing a page or changing the slug, title, description or logo of a public one, create_monitor or update_monitor changing a monitor shown on a public page, link_issue with your own team, title or body, and add_issue_comment when members of the issue's project cannot see some projects you can. test_monitor, create_monitor and update_monitor need it for a host none of the organization's monitors checks yet, and test_notification_channel for a URL no saved channel uses. For 10 minutes after a connection receives a secret, such as a key from setup_service or a signing secret, those calls to a new destination, and every call that publishes text outside the organization, are refused even with confirm: true. pause_monitor and accept_invitation always need it.
update_monitor never carries saved custom header values to another origin. Changing the URL of a monitor with saved headers requires customHeaders in the same call: pass them again, or [] to drop them. test_monitor reports the outcome, status code, timings, error type, response header names and response size, never the response body or header values. Joining an organization with accept_invitation never extends the connection that accepted it, even one approved for all organizations; reconnect the app to work there. delete_project also needs the project's exact name as confirmation, as the app asks you to type it. link_issue is marked open world, since it can create a ticket in Linear or GitHub.
Trace and log searches use the query grammar of the Traces and Logs pages, for example duration>=500ms status:error http.route^/api service:billing-api. Issue tools accept an issue ID, a pasted issue URL or a canonical fingerprint.
Tools
The server registers over 200 tools, listed below by area. tools/list shows only the tools your connection's scopes allow.
Workspace
| Tool | Access | What it does |
|---|---|---|
whoami | read | Current user, granted scopes, and every organization the connection reaches with your role, the scopes it allows over MCP, and its projects and services |
list_apps | read | Projects with their services in every organization the connection reaches |
create_organization | write | Create an organization with you as admin, a default team and a default project. The connection reaches it right away |
create_project | write | Create a project. Needs an organization admin |
list_environments | read | A project's environments with their request counts in the window |
setup_service | write | Create a service, or reuse the one with the same name, and return a fresh DSN with install steps for the AdonisJS agent, OTLP settings for any OpenTelemetry SDK and a link to the setup for other stacks |
Projects, services and keys
These tools need an organization admin, except list_services, which any member who can see the project may call.
| Tool | Access | What it does |
|---|---|---|
get_project | read | Name, slug, team access, what deleting the project would remove, and its exception settings |
update_project | write | Rename a project, change its slug or the teams that can see it. Fields you leave out stay as they are |
delete_project | write | Delete a project and everything in it |
update_exception_settings | write | Turn secret scrubbing on or off and set the fields to always or never scrub |
create_sample_project | write | Open the Sample project with simulated data, creating it the first time |
list_services | read | Services with the last four characters of their keys, the rules watching them and the ingest endpoint |
update_service | write | Change a service's display name |
delete_service | write | Delete a service, revoke its keys and pause its alerts |
rotate_service_key | write | Issue a new DSN; the old key keeps working for the grace period |
revoke_service_key | write | Stop the previous key, or every key of a service |
get_service_map | read | Services, databases and external hosts with the calls between them, and per-service series on request |
get_ingest_domain | read | The organization's custom ingest domain, its state and DNS records |
add_ingest_domain | write | Add a custom ingest domain and return the DNS records to create |
check_ingest_domain | write | Check the ingest domain's DNS now |
remove_ingest_domain | write | Remove the custom ingest domain |
Issues and exceptions
| Tool | Access | What it does |
|---|---|---|
list_issues | read | Issues with status, priority, assignees, teams, stats, trend and archive progress, plus per-status counts and the For review total. Filters by status, view (app tab, saved view or triage shortcut), priority, assignee, service, text and token query |
list_issue_views | read | The built-in issue tabs and the saved views you can see, with their query, status and sort |
list_issue_filter_values | read | Values of an issue search field in the window, to build queries |
list_issue_assignees | read | People with access to the project and the organization teams an issue can be assigned to |
get_issue | read | One issue with counts, services, stack location, first and latest release, regression context, archive progress, suggested owners, linked tickets and its app URL; the latest occurrence, tag distribution, comments and activity on request |
list_similar_issues | read | Up to 8 issues that look like the same failure, as merge candidates |
get_issue_activity | read | An issue's history, newest first, with actor and time |
get_issue_settings | read | Auto-assign and auto-resolve settings and the ordered ownership rules |
update_issue | write | Resolve (now, in the next release or in a release), archive or reopen an issue, set priority, assignees and teams, mark it reviewed and add a comment |
bulk_update_issues | write | The same changes on up to 100 issues at once, each change in one transaction |
add_issue_comment | write | Comment on an issue |
link_issue | write | Create a Linear or GitHub ticket (title, body and Linear options) or attach an existing one. Returns the existing link if the issue already has one for that provider, unless another is true. A GitHub repository or Linear team other than the project's mapped one needs an organization admin |
search_external_issues | read | Search the project's mapped repository or Linear team for tickets to attach. Needs integrations:read |
unlink_issue | write | Remove a linked ticket from an issue; the ticket itself is untouched |
merge_issues | write | Merge up to 50 issues into a target issue; undo with unmerge_issue |
unmerge_issue | write | Give a merged issue back the grouping keys it brought in, and reopen it |
create_issue_view | write | Save a search as a personal or shared issue tab |
delete_issue_view | write | Delete a saved issue tab |
update_issue_settings | write | Change auto-assign and auto-resolve; omitted fields stay. Organization admins only |
create_ownership_rule | write | Append an ownership rule matching a service, path or route to a person or team. Organization admins only |
delete_ownership_rule | write | Delete an ownership rule. Organization admins only |
list_exceptions | read | Exception groups with occurrences, users, services, entry points, handled, trend, and the issue that groups them with its status. Hides groups whose issue is resolved or archived unless status asks for them |
get_exception | read | One exception group and one occurrence (latest or by id) with its cause chain, frames, tags, extra and release deployment |
list_occurrences | read | Occurrences of an issue or of a fingerprint, newest first |
get_occurrence | read | Inspect an issue occurrence (best, latest, by id, older or newer) with its cause chain, related exceptions in the trace and, on request, the hour of logs and spans before the throw |
list_issue_users | read | End users an issue affected, with occurrence counts |
Traces and logs
| Tool | Access | What it does |
|---|---|---|
get_overview | read | A project's overview: health cards with deltas against the previous period or a compare window, trends, traffic and the attention tables. Top exceptions skip resolved and archived issues unless exceptionStatus asks for them |
get_project_status | read | The overview status strip for one environment (alerts, uptime, incidents, new and regressed issues) and the setup checklist |
list_traces | read | Traces newest or slowest first with duration, status, span and error counts; can hide background work |
get_trace_stats | read | Trace counts per root status and the per-bucket chart, optionally grouped by a field |
tail_traces | read | New traces since a cursor, like live mode |
get_trace | read | The spans of one trace in start order with timings, status and category, 200 per page. Attributes only with includeAttributes or attributeKeys, and long values are cut to 2,048 characters. includeLogsAndExceptions adds the trace's logs and exceptions |
get_span | read | One span with every attribute, event and link, and on request its duration rank and the instance metrics around it |
list_search_fields | read | Searchable fields of spans or logs with their common values |
list_logs | read | Log records filtered by level, service, window and trace ID |
search_logs | read | Full-text search over log messages |
get_log_volume | read | Log counts per bucket and level, with totals per level |
list_log_patterns | read | Log messages clustered into up to 30 templates |
get_log_context | read | A log's full body, the other logs of its trace and the logs around it from the same service |
tail_logs | read | New log records since a cursor, like live mode |
Every tool that takes a time window also accepts services (several service names), interval (1m to 1d) and compare (previous, 1d or 1w).
Performance
| Tool | Access | What it does |
|---|---|---|
list_endpoints | read | HTTP endpoints with request count, average and p95 duration, and error rate |
get_endpoint_stats | read | One endpoint's latency percentiles, error rate, throughput and time series |
list_db_queries | read | Normalized statements with executions, durations, errors and executions slower than 100 ms |
get_db_query_detail | read | One statement's percentiles and its 20 most recent executions |
list_jobs | read | Background jobs with processed count, error rate and processing time |
get_job_detail | read | One job's percentiles and its 20 most recent executions |
list_cache_stats | read | Cache keys with operations, hits, misses, hit rate and latency |
get_cache_key_detail | read | One cache key's hits, misses, percentiles and hit and miss series |
list_external_calls | read | Outgoing HTTP calls by domain with latency, error rate and 4xx and 5xx counts |
get_external_call_detail | read | One domain's URL patterns and its 20 most recent requests |
get_performance_dashboard | read | Any built-in dashboard (requests, queries, external calls, jobs, cache, emails, commands) as its page shows it: summary, series, queue flow and rows, with the page's sorts and filters and compare deltas |
get_performance_detail | read | One operation of a built-in dashboard: summary, series, samples by status and order, breakdown, callers and time breakdown |
get_latency_heatmap | read | The latency heatmap of a request, query or external call, narrowed by attribute values |
compare_latency_outliers | read | What the executions in a heatmap box share compared with the rest of the window |
get_system_metrics | read | The system metrics panels and series of one instance |
Metrics
| Tool | Access | What it does |
|---|---|---|
list_instances | read | Instances that reported runtime metrics in the window, with runtime and a live flag for the last 15 minutes |
list_metrics | read | The metrics page catalog: gauge, sum, histogram and summary metrics seen in the 90 days before the window end, with unit, description, services, last value and trend. Search matches name or description; type keeps one kind. conflict marks a name reported with several types or units, overflowed one that hit the per-metric series limit |
get_metric | read | A metric series aggregated with avg, sum, min, max, count, rate, p50, p75, p90, p95 or p99, kept or excluded by attribute values and grouped by one attribute, up to 10 groups, as the metric explorer charts it. Counters and cumulative histograms report the increase per bucket, with counter resets handled |
get_metric_attributes | read | A metric's attribute keys, including service.name and service.instance.id, with up to 50 values each |
Deployments
| Tool | Access | What it does |
|---|---|---|
list_deployments | read | Deployments newest first, filtered by service, source (detected, api, cli), version, commit SHA prefix and environment, with the 5xx impact and new issue counts on request |
get_deployment | read | One deployment's timeline, CI links, previous deployment and nearby versions, with the before and after impact and its issues on request |
get_running_versions | read | The versions each service reported in the last 15 minutes |
list_deploy_keys | read | Deploy keys with their last four characters and last use. Needs an organization admin |
create_deploy_key | write | Create a deploy key and return its token once. Needs an organization admin |
revoke_deploy_key | write | Revoke a deploy key. Needs an organization admin |
list_source_maps | read | Source maps by service and release with size and quota. Needs an organization admin |
delete_source_maps | write | Delete the source maps of one release. Needs an organization admin |
Uptime and status pages
| Tool | Access | What it does |
|---|---|---|
list_monitors | read | Uptime monitors with state, 24-hour uptime and median response time |
get_monitor | read | One monitor over 24h, 7d or 30d with its 10 latest outages and 10 latest isolated failed checks |
get_check | read | One check with its HTTP response, health report, neighbouring checks, outage and trace ID |
list_outages | read | Ongoing and recent outages with their incidents. maxAgeDays defaults to 7, at most 90 |
get_outage | read | One outage with its failed checks grouped by reason |
list_status_incidents | read | Incidents and maintenance newest first. Closed ones only with includeClosed |
get_status_incident | read | One incident's updates, affected monitors and covered outages |
create_status_incident | write | Declare an incident from outages or monitors, or schedule maintenance |
update_status_incident | write | Post an update, change status with a required message, resolve, cancel or reschedule maintenance, edit title, visibility and monitors |
create_monitor | write | Create an HTTP, TCP, DNS or heartbeat monitor, checked every minute. Private and local targets are refused. Needs a project manager |
update_monitor | write | Change only the fields you pass. Changing the target or a check setting closes an ongoing outage and restarts the monitor. Needs a project manager |
pause_monitor | write | Stop checks. An ongoing outage closes without a recovery notification. Needs a project manager |
resume_monitor | write | Resume a paused monitor, checked again within a minute. Needs a project manager |
delete_monitor | write | Delete a monitor with its outages and check history. Needs a project manager |
get_heartbeat_url | write | Return a heartbeat monitor's secret ping URL |
get_status_page | read | The environment's status page: settings, public URL, listable monitors and subscriber counts, with what the public page shows on request |
create_status_page | write | Create the environment's status page, private unless public: true. Needs a project manager |
update_status_page | write | Change only the fields you pass, publish the page or take it offline. Needs a project manager |
delete_status_page | write | Delete the status page with its incidents, subscribers and custom domain. Monitors are kept. Needs a project manager |
list_status_subscribers | read | The page's email subscribers, newest first, with the monitors they follow. Needs status:write |
remove_status_subscriber | write | Remove a subscriber without telling them. Needs a project manager |
Alerts
| Tool | Access | What it does |
|---|---|---|
list_alerts | read | Endpoint alerts with condition, destinations, status and last value |
get_alert | read | One alert's evaluations in the window, its incidents and its latest incident |
list_notification_channels | read | Slack, Discord and webhook channels with their IDs. URLs and secrets are never returned |
preview_alert | write | Replay an alert condition on recent data and suggest a threshold. Saves nothing |
create_alert | write | Create an endpoint alert, paused until you pass enabled: true |
update_alert | write | Change only the fields you pass |
pause_alert | write | Pause an alert. A firing alert resolves |
resume_alert | write | Resume a paused alert, within the active-alert limit |
delete_alert | write | Delete an alert and its incident history. A firing alert sends its resolved notification first. Needs a project manager |
snooze_alert / unsnooze_alert | write | Hold an alert's notifications for 1h, 4h, until tomorrow morning or until the firing incident resolved, or end the snooze. Any project member |
get_incident | read | Who acknowledged an alert incident or monitor outage, its assignee, its comments and the members it can be assigned to |
acknowledge_incident | write | Acknowledge an alert incident or monitor outage as you, which stops its reminders. Any project member |
assign_incident | write | Assign an alert incident or monitor outage to a member, or unassign it. Sends no notification. Any project member |
add_incident_comment | write | Comment on an alert incident or monitor outage. Sends no notification |
get_notification_channel | read | One channel's settings, health and 100 latest deliveries, and what would be left with no destination without it |
create_notification_channel | write | Add a Slack, Discord or webhook channel. The URL is stored encrypted and never returned. Needs an organization admin |
update_notification_channel | write | Change a channel's name, URL or defaults. A new URL re-enables a disabled channel. Needs an organization admin |
delete_notification_channel | write | Delete a channel. Alerts, monitors and exception rules stop posting to it. Needs an organization admin |
test_notification_channel | write | Post a test message to a saved channel or to a URL before you save it, and report whether it arrived. Needs an organization admin |
reveal_notification_channel_secret / rotate_notification_channel_secret | write | Show a webhook channel's signing secret, or replace it and return the new one. Needs an organization admin |
list_exception_rules | read | The project's exception notification rules, the fallback channels and how new exceptions are batched into digests |
create_exception_rule / delete_exception_rule | write | Post a service's or environment's new exceptions to a channel, or mute a channel kind, and delete a rule. Needs a project manager |
Analytics and end users
| Tool | Access | What it does |
|---|---|---|
list_analytics_sites | read | Sites that sent web analytics in the window |
get_analytics_overview | read | Totals, series against the previous period, top lists and event properties, with the page, entry, exit, referrer, UTM and event filters |
list_analytics_pages | read | Pages by route or URL with pageviews and visitors |
list_analytics_events | read | Custom events with counts and visitors |
list_analytics_sessions | read | Visits, a page at a time, or the visits that dropped off at a funnel step |
get_analytics_session | read | One visit's journey and the services it touched |
get_analytics_funnel | read | A 2 to 8 step funnel with reach and drop-off per step |
list_tracked_users | read | End users your application identified, with requests and errors |
get_tracked_user | read | One end user's profile, series and recent requests |
The analytics tools need the analytics:read scope; the end-user tools need telemetry:read.
AI agents and MCP monitoring
| Tool | Access | What it does |
|---|---|---|
get_ai_overview | read | AI calls, tokens, cost, errors and latency with series and top conversations |
list_ai_models | read | Calls, tokens, cost and latency per model |
list_ai_tools | read | Tool calls of your agents with errors and latency |
list_ai_scorers | read | Evaluation scorer results |
list_ai_conversations | read | The 100 most recent conversations |
get_ai_conversation | read | One conversation's steps, tokens, cost, evaluations and trace ids |
get_mcp_monitoring_overview | read | Calls, clients, users, tools and methods of your own MCP server |
get_mcp_monitoring_tool | read | One tool of your own MCP server with its recent calls |
These need the ai:read scope.
Dashboards
| Tool | Access | What it does |
|---|---|---|
list_dashboards | read | Custom dashboards with widget counts, variables, creator and whether you can edit them |
get_dashboard | read | One dashboard's variables and widgets with every query, formulas, display and layout |
get_dashboard_data | read | Every widget of a dashboard run for the window, with dashboard variables selected by name |
preview_widget | read | Run a widget definition without saving it |
create_dashboard | write | Create a dashboard, optionally with its first widget in one step |
update_dashboard | write | Rename a dashboard or change its description, icon or variables |
duplicate_dashboard | write | Copy any dashboard you can see, widgets included, as your own |
delete_dashboard | write | Delete a dashboard; restore_dashboard brings it back |
restore_dashboard | write | Bring back a deleted dashboard with its widgets |
add_widget | write | Add a chart, stat, table, sparkline, pie or bar_gauge widget with up to six queries and four formulas |
update_widget | write | Change a widget's queries, formulas, display or layout |
save_dashboard_layout | write | Move and resize several widgets in one save |
remove_widget | write | Remove a widget |
As in the app, anyone who can see a project may create and duplicate dashboards, while editing, deleting and restoring one needs its creator or an organization admin.
Integrations
| Tool | Access | What it does |
|---|---|---|
list_integrations | read | GitHub and Linear connections; admins also see each project's repository or team |
list_integration_targets | read | The GitHub repositories or Linear teams a connection can file tickets to. Needs an organization admin |
set_project_integration_target | write | Choose the repository or team a project files tickets to. Needs an organization admin |
clear_project_integration_target | write | Stop a project filing tickets. Needs an organization admin |
disconnect_integration | write | Disconnect GitHub or Linear. Needs an organization admin |
Connecting GitHub or Linear stays in the app, since it needs you to approve it with the provider.
Billing
| Tool | Access | What it does |
|---|---|---|
get_billing | read | The plan, trial state, the plans on sale and the data ingested this billing period against the plan's included bytes |
get_usage_report | read | Ingest usage for one of the last 25 billing periods by signal, project, environment and service, with the projection and overage for the current one |
These need the billing:read scope.
Organization, members and teams
| Tool | Access | What it does |
|---|---|---|
get_organization | read | Name, slug, avatar, suspension, your role and the counts of projects, live services and members |
update_organization | write | Rename the organization or change its slug. Old slugs keep redirecting in the browser |
set_organization_avatar / remove_organization_avatar | write | Upload a base64 image under about 700 KB, or delete the avatar |
get_retention_settings / update_retention_settings | read / write | How many days each kind of data is kept, and changing it. Omitted categories stay as they are; lowering any category needs confirm: true, since older data is then deleted |
leave_organization | write | Leave the organization. The only admin cannot leave |
delete_organization | write | Erase the organization and all its data. Pass its slug as confirmation. Cannot be undone |
list_members / list_invitations | read | Members with their roles, and open invitations including expired ones |
update_member / remove_member | write | Change a member's role or remove them, by email. The last admin stays |
create_invitation / revoke_invitation | write | Email an invitation, which also resends one, or revoke the open invitation to an address |
list_teams | read | Teams with their members' emails and project slugs |
create_team / update_team / delete_team | write | Manage teams. update_team replaces only the lists you pass |
Changing the organization, its members and its teams needs an organization admin, as in the app.
Account and inbox
| Tool | Access | What it does |
|---|---|---|
get_account / update_account | read / write | Your name, timezone, theme, avatar and verification state; change the name, timezone or theme |
set_account_avatar / remove_account_avatar | write | Upload a base64 image under about 700 KB, or delete your avatar |
get_notification_preferences / update_notification_preferences | read / write | Which emails you get and which inbox categories you muted, per organization |
list_inbox | read | Your 50 newest notifications with the unseen count, filtered by unread or category |
mark_inbox_seen / mark_inbox_read | write | Clear the unseen badge, or mark one notification or all of them read |
open_notification | write | Mark a notification read and say whether its target is live, moved or deleted |
list_received_invitations / accept_invitation | read / write | Invitations sent to your verified email, and joining one with invitations:accept and confirm: true. The connection that accepts does not reach the new organization; reconnect the app to work there |
No tool changes your email address, password or passkeys, or deletes your account. Do those in the app.
Feedback
| Tool | Access | What it does |
|---|---|---|
list_feedback_threads / get_feedback_thread | read | Your feedback threads, or every thread for organization admins, and one thread's messages |
create_feedback_thread / reply_feedback_thread | write | Send an idea, bug or help request, or reply. An admin's reply on someone else's thread emails its author |
update_feedback_thread | write | Set a thread's status. Needs an organization admin |
submit_doc_feedback | write | Rate a docs page helpful or not |
Revoking access
Open Settings, choose Profile under Account, then the Connected apps tab. It lists every app you allowed, with its organizations, scopes and when it was last used.
- Edit changes the scopes and organizations. The change applies to the app's next call.
- Revoke stops its token right away. You can also post the token to
POST /oauth/revoke.
Organization admins see every app that reaches their organization in Settings, MCP. Revoke there cuts that app off from the organization only; it keeps working in the member's other organizations. Reconnecting the same app does not bring it back: it stays under Revoked apps until an admin chooses Allow again. The Activity list on the same page shows the latest changes apps made in the organization: the tool, the app, the member, what it acted on and the names of the fields it set, never their values. Tokens also stop working when they expire.
An app can never change its own access: editing connections and the organization MCP policy is only possible in the browser.
FAQ
The connection was granted only read scopes, for example with the Read only preset. Edit it in Connected apps, or connect again and tick the write scopes you want.
Dashboards yes, alerts no: each tool allows what the app allows that member. Members can also triage, comment on and link issues.
The one in the organization argument. When the connection reaches only one organization you can leave it out.
create_organization allows 5 new organizations an hour per user, and each one is recorded in an audit log. Plans put no limit on how many organizations you own.