mcpField
O
OneUptime

OneUptime

Remote
oneuptime.comCloud & Infra7.8kUpdated today

About OneUptime

OneUptime’s MCP server lets AI agents manage observability and incident-response data in OneUptime. It offers CRUD operations across operational models, read-only telemetry queries, and dedicated response workflows.

Key features

  1. 01Manage incidents, alerts, and monitors
  2. 02CRUD for operational records
  3. 03Query telemetry resources
  4. 04Acknowledge and resolve incidents
  5. 05Public status page tools

Use cases

  1. 01Triage and resolve incidents
  2. 02Review logs and exceptions
  3. 03Update customer status pages

MCP support

Exposes OneUptime data and actions to MCP-compatible clients through a stateless Streamable HTTP endpoint. Authentication supports OAuth 2.1 sign-in or per-request API keys.

Configuration

Remote servers need no local install. Pick your client, then copy the config or install in one click.

Endpointhttps://oneuptime.com/mcp
Copy install command
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.

All endpoints
Streamable HTTPhttps://oneuptime.com/mcpAuth required

Tools

Details

From the project README

OneUptime MCP Server

A Model Context Protocol (MCP) server that exposes OneUptime to AI agents. It lets MCP-compatible clients (Claude, VS Code with Copilot, Cursor, and others) manage incidents, alerts, monitors, status pages, on-call, and telemetry through ~190 tools.

How it works

  • Transport: Streamable HTTP at /mcp. The server is stateless — no session IDs are issued or required, so it is safe behind load balancers and multi-replica deployments.
  • Hosted endpoint: https://oneuptime.com/mcp
  • Self-hosted endpoint: https://<your-host>/mcp (served by the App container behind Nginx)
  • Auth: sign in with OneUptime (OAuth 2.1, per the MCP authorization specification), or a per-request API key via the x-api-key header or Authorization: Bearer <key> (scheme is case-insensitive). There is no environment-variable API key — every request carries its own credential.

Connecting a client

By signing in

Give the client the URL and nothing else. The first call to a tool that needs an identity is answered 401 with a WWW-Authenticate challenge; the client discovers the authorization server from it, opens the consent screen in the user's browser, and gets tokens for the project the user picks.

claude mcp add --transport http oneuptime https://oneuptime.com/mcp
{ "servers": { "oneuptime": { "type": "http", "url": "https://oneuptime.com/mcp" } } }

The rest of this section configures the same clients with an API key instead, for agents that run unattended.

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "oneuptime": {
      "transport": "streamable-http",
      "url": "https://oneuptime.com/mcp",
      "headers": {
        "x-api-key": "your-api-key-here"
      }
    }
  }
}
Claude Code
claude mcp add --transport http oneuptime https://oneuptime.com/mcp \
  --header "x-api-key: your-api-key-here"
VS Code (GitHub Copilot)

.vscode/mcp.json or the user MCP configuration:

{
  "servers": {
    "oneuptime": {
      "type": "http",
      "url": "https://oneuptime.com/mcp",
      "headers": {
        "x-api-key": "${input:oneuptime-api-key}"
      }
    }
  },
  "inputs": [
    {
      "type": "promptString",
      "id": "oneuptime-api-key",
      "description": "OneUptime API Key",
      "password": true
    }
  ]
}
Cursor

.cursor/mcp.json:

{
  "mcpServers": {
    "oneuptime": {
      "url": "https://oneuptime.com/mcp",
      "headers": {
        "x-api-key": "your-api-key-here"
      }
    }
  }
}

For self-hosted instances, replace oneuptime.com with your OneUptime host in any of the above.

Authentication

API key

Create a project API key in OneUptime under Project Settings → Advanced → API Keys and grant it the least privilege the agent needs (read-only keys work for all get_/list_/count_ tools). The project is inferred from the key — create tools never need a projectId argument.

Warning — never give an AI agent a master key. A OneUptime master API key is also accepted on this header and grants instance-wide admin access. Always use a project-scoped API key with least privilege for AI agents.

Public status page tools and oneuptime_help / oneuptime_list_resources work without any credential.

OAuth sign-in

The code is in OAuth/; each file opens with the reasoning behind it. The shape of it:

  • One issuer under /mcp. https://<host>/mcp is both the protected resource (RFC 9728) and the authorization server's issuer (RFC 8414). Every endpoint sits under /mcp/oauth, and every URL is built from HOST / HTTP_PROTOCOL, never from the request.
  • Lazy, at the HTTP layer. OAuth/RequestGate runs before the MCP SDK sees a request. initialize, tools/list and the public tools pass with no credential; a call to a tool that needs an identity is refused 401 (or 403 insufficient_scope for a read-only grant calling a write tool) with a Bearer challenge. It cannot live in a tool handler: a refusal from inside the SDK is a 200, and a client only starts signing its user in on a real 401.
  • Clients identify themselves. A Client ID Metadata Document (OAuth/ClientIdMetadataDocument, fetched through the egress guard with private addresses always blocked) or Dynamic Client Registration (OAuth/RegistrationEndpoint). Nobody registers a client by hand.
  • Authorization code + PKCE (S256 only), resource indicators (RFC 8707), iss in the authorization response (RFC 9207), rotating refresh tokens with reuse detection, revocation (RFC 7009).
  • Opaque tokens, stored as hashes. oumcp_ac_… / oumcp_at_… / oumcp_rt_…; only the SHA-256 is kept (McpOAuthToken). A grant (McpOAuthGrant) is one member letting one client act for them in one project; revoking is deleting the grant, which cascades to its tokens.
  • Only an access token is a credential. x-api-key carries an API key and nothing else; Authorization carries an API key or an access token. Any other oumcp_ secret presented in either header — a refresh token, a code, a client secret, or an access token in x-api-key — is refused 401 invalid_token by OAuth/RequestGate and is never passed on to the API as an API key.
  • Scopes mcp:read and mcp:write (write includes read). The consent screen can narrow what a client asked for, never widen it.
  • The API never sees the client's token. Having accepted an access token, the MCP layer calls the REST API with a 60-second signed delegation token (Common/Server/Utils/Mcp/McpDelegationToken). Common/Server/Middleware/McpDelegationAuthorization turns that into a request authorized as the member — never as a master admin — in the grant's project, with their live permissions, and marked read-only when the grant is. A stolen access token is therefore worth exactly what the MCP tools can do with it.
  • Checked on every use. Common/Server/Utils/Mcp/McpOAuthGrantAccess re-evaluates the grant per request and per token exchange: the member still exists, is not blocked, still belongs to the project, is not on a team that blocks AuthorizeMcpClient, and still satisfies the project's SSO requirement.
  • Consent is the Accounts page /accounts/mcp-authorize; managing connected clients is Settings → MCP Server in the Dashboard.

Two settings: DISABLE_MCP_OAUTH=true switches the whole thing off (the routes answer 404 and an unauthenticated tool call gets the in-band "API key is required" result it always got), and DISABLE_MCP_OAUTH_CLIENT_ID_METADATA_DOCUMENTS=true is for instances that cannot make outbound requests.

Tool catalog

Database resources — full CRUD

Each of these 27 models gets six tools: create_, get_, list_, update_, delete_, count_ (e.g. create_incident, get_incident, list_incidents, update_incident, delete_incident, count_incidents):

Incident, Alert, Incident Alert, Monitor, Status Page, Scheduled Maintenance Event, Team, Monitor Status, On-Call Policy, Incident State, Incident Severity, Alert State, Alert Severity, Incident State Timeline, Alert State Timeline, Incident Public Note, Incident Internal Note, Alert Internal Note, Status Page Announcement, Scheduled Maintenance State, Scheduled Maintenance State Timeline, Label, Monitor Status Event, Security Case, Security Case Note, Security Detection, Security Playbook.

Telemetry resources — read-only

Log, Metric, Span, Exception Instance, Monitor Log, Security Event, Change Event, Kubernetes Cost Allocation, and Threat Intel Indicator get list_ and count_ tools only (e.g. list_logs, count_spans, list_exception_instances). There are no create tools for telemetry — ingestion happens via OpenTelemetry.

Workflow tools

Purpose-built shortcuts for incident/alert response (packages/App/FeatureSet/MCP/Tools/WorkflowTools.ts):

  • acknowledge_incident, resolve_incident
  • acknowledge_alert, resolve_alert
  • add_incident_note (with visibility: "internal" | "public" — public notes post to the status page)
  • add_alert_note
  • oneuptime_whoami — returns the project (ID and name) the credential belongs to; for an OAuth sign-in, also who is signed in, through which client, and whether the connection is read-only
Helper and public tools
  • oneuptime_help, oneuptime_list_resources
  • No credential needed: get_public_status_page_overview, get_public_status_page_incidents, get_public_status_page_scheduled_maintenance, get_public_status_page_announcements
Annotations and results

Every tool has a title and states all three MCP hints, set in Tools/ToolAnnotations.ts, so clients can auto-approve safe calls and confirm the rest:

  • readOnlyHint: true on the tools that change nothing: get_, list_, count_, oneuptime_whoami, the helper tools and the public status page tools.
  • destructiveHint: true on every tool that changes something: create, update and delete tools, acknowledging and resolving, and adding notes. Most writes overwrite or delete a record, change an incident's or alert's state, page someone on call or post to a status page, and the directories allow false only for a write that adds and sends nothing.
  • openWorldHint: true only on the public status page tools, which read any public status page on the instance. Every other tool stays inside the caller's project.

MCP directories require them: the Claude Connectors Directory flags any tool without a title or a readOnlyHint/destructiveHint, and ChatGPT's requires all three hints as booleans. Tests/ToolAnnotationsForDirectories.test.ts fails on a tool that lacks one, or that breaks the rules above. On the server itself, MCP_ALLOW_DESTRUCTIVE=false removes the delete tools only, and MCP_READ_ONLY=true removes every tool that is not read-only (Tests/WritePolicy.test.ts). Tool results include structuredContent alongside the JSON text. Errors come back as in-band tool results (isError: true) with statusCode, details, and a suggestion — not as protocol errors.

Query, sort, select, and pagination

Queries

Query fields accept a direct value or an operator object:

{
  "query": {
    "title": { "_type": "Search", "value": "database" },
    "createdAt": { "_type": "GreaterThan", "value": "2026-07-01T00:00:00.000Z" }
  }
}

Operators: EqualTo, NotEqual, IsNull, NotNull, EqualToOrNull, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual, InBetween, Search, Includes.

Sort
{ "sort": { "createdAt": "DESC" } }

Values are "ASC" or "DESC".

Select

get_ and list_ tools take an optional select array of field names. By default all readable fields are returned except heavy ones (JSON / VeryLongText / HTML columns), which must be requested explicitly.

Pagination

limit defaults to 10 (max 100); skip offsets into the result set. List responses return the full requested page with honest pagination metadata:

{
  "returnedCount": 10,
  "totalCount": 42,
  "skip": 0,
  "limit": 10,
  "hasMore": true,
  "data": ["..."]
}

Example workflow

A typical incident-response loop an agent can run:

  1. oneuptime_whoami — confirm which project the credential belongs to.
  2. list_incidents with {"sort": {"createdAt": "DESC"}, "limit": 5} — find the active incident.
  3. acknowledge_incident — take ownership.
  4. list_logs with a time-range filter ({"time": {"_type": "GreaterThan", "value": "..."}}) and list_exception_instances — investigate.
  5. add_incident_note with "visibility": "public" — post a status update for customers.
  6. resolve_incident — close it out.

HTTP endpoints

EndpointMethodBehavior
/mcpPOSTJSON-RPC (tool calls and all MCP operations)
/mcpGETWithout an SSE Accept header: friendly JSON discovery payload. With one: 405 (no standalone SSE stream in stateless mode).
/mcpDELETENo-op (stateless — nothing to terminate)
/mcp/toolsGETREST listing of available tools
/mcp/healthGETHealth check, including the protocol versions this build speaks
/mcp/.well-known/oauth-protected-resourceGETProtected resource metadata (also at /.well-known/oauth-protected-resource[/mcp])
/.well-known/oauth-authorization-server/mcpGETAuthorization server metadata (also at /mcp/.well-known/oauth-authorization-server and the origin's root)
/mcp/oauth/authorizeGET, POSTAuthorization endpoint: checks the client's request and redirects to the consent screen
/mcp/oauth/tokenPOSTCode exchange and refresh
/mcp/oauth/registerPOSTDynamic Client Registration
/mcp/oauth/revokePOSTToken revocation
/mcp/oauth/consent/{details,approve,deny}POSTThe consent screen's own calls (session cookie, same origin only)

Protocol compatibility

The server negotiates rather than rejects, so a client does not have to match the MCP SDK bundled in the App container exactly.

Protocol version. The MCP-Protocol-Version request header is negotiated down to the highest version both sides support. A header sent twice is read as its first value — Node collapses repeated headers into one comma-joined string, and a version never contains a comma:

  • a version the server supports is used as-is;
  • a version newer than anything the server knows about (for example a client on a newer revision of the spec) is negotiated down to the server's latest — the same answer initialize gives;
  • a version older than everything the server supports, or one that is not a YYYY-MM-DD version at all, has no common ground. The request is answered with 400 and a JSON-RPC error that names the requested version and lists the supported ones, instead of failing silently at the transport layer.

An unusable header on an initialize request is dropped rather than rejected, because that request negotiates the version in its body. A header that is present but blank is dropped too: an empty string is not the same as an absent header to the SDK, which would otherwise reject it like any other unknown version.

GET /mcp and GET /mcp/health both list the supported versions, so a failing handshake can be diagnosed without reading container logs.

Response format. A POST is answered with whatever the client's Accept header allows: text/event-stream when the client asks for it by name or via the text/* range (what spec-compliant MCP clients do), and a plain application/json body otherwise — including for Accept: application/json, an application/* or */* wildcard, or no Accept header at all. Both are valid replies to a POST under the MCP spec. A client that accepts neither gets a 406 naming the media types the endpoint can produce.

Diagnostics. Negotiation logs describe the client: they are built from a snapshot taken before the headers are rewritten, so they report what was actually sent rather than the values this server normalised them to. Every field in them — header values and the JSON-RPC method alike — is stripped of control characters and length-capped, so a caller cannot forge log lines or flood the log through them. The API key or access token is never logged.

Self-hosting

The MCP server ships as part of the App container and is served at /mcp behind Nginx — no separate deployment is needed. Its tools call the OneUptime API at the App's internal address - SERVER_APP_HOSTNAME and APP_PORT, the address Nginx proxies /api to (inherited from the App service's environment) - never through the public HOST, which the App container cannot always reach (with HOST=localhost it is the container itself). API keys are never configured on the server; clients supply them per request.

OAuth sign-in needs nothing configured either, but it does depend on HOST and HTTP_PROTOCOL being the address people actually use: the issuer, the token audience and every endpoint in the discovery documents are built from them. A reverse proxy in front of OneUptime has to forward /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server (and everything under them) to the App along with /mcp; the bundled Nginx does.

MCP Registry

OneUptime Cloud's server is listed in the official MCP Registry, which MCP clients and directories read, as com.oneuptime/mcp. server.json is the entry: streamable HTTP at https://oneuptime.com/mcp, signed in to with OAuth, or given a project API key in the optional x-api-key header. Its version is a placeholder, 0.0.0.

Every release publishes it at the release's version. The publish-mcp-registry job in .github/workflows/release.yml runs Scripts/MCP/PublishToMcpRegistry.sh once the GitHub release is published, and skips a version the registry already has, so re-running a release publishes nothing twice. A published version cannot be changed.

Only whoever controls oneuptime.com may publish under com.oneuptime. The job signs in with an Ed25519 private key whose public key is in a TXT record on oneuptime.com, and it fails, publishing nothing, until both are in place. To set them up (Ed25519 needs OpenSSL 3; on macOS, brew install openssl@3 and use its openssl, not the system LibreSSL):

  1. Make a key pair:

    openssl genpkey -algorithm Ed25519 -out mcp-registry-key.pem
    
  2. Add a TXT record on oneuptime.com itself, not on a subdomain such as _mcp.oneuptime.com, with the value this prints:

    echo "v=MCPv1; k=ed25519; p=$(openssl pkey -in mcp-registry-key.pem -pubout -outform DER | tail -c 32 | base64)"
    
  3. In the repository's Settings → Environments, create mcp-registry-publish, limit its deployment branches to release, and give it the secret MCP_REGISTRY_PRIVATE_KEY: the private key in hex, which this prints:

    openssl pkey -in mcp-registry-key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n'
    

Then delete mcp-registry-key.pem, or keep it somewhere safe: whoever has the key can publish, and overwrite, any entry under com.oneuptime. To change the key, replace the TXT record and the secret together; an old record left beside the new one is tried first and fails the sign-in.

To publish before the next release, run the script by hand from the repository root, with mcp-publisher and jq installed: PACKAGE_VERSION=<version> MCP_REGISTRY_PRIVATE_KEY=<hex key> bash Scripts/MCP/PublishToMcpRegistry.sh.

ChatGPT plugin directory

ChatGPTPlugin/ is the package OneUptime uploads to the ChatGPT plugin directory, which ChatGPT and Codex share: the listing, five positive and three negative review test cases, and mcp.json, which points at https://oneuptime.com/mcp and signs in with OAuth for read and write access. npm run build-chatgpt-plugin builds the ZIP. Its README lists what else a submission needs: a verified developer identity, a domain-verification token served at https://oneuptime.com/.well-known/openai-apps-challenge, reviewer credentials for a demo project, and a demo video. Tests/ChatGPTPlugin.test.ts holds the package to the Agent Plugins schemas and OpenAI's limits, and checks that every tool a test case names is one this server has.

Development

The MCP server lives in packages/App/FeatureSet/MCP and is mounted into the App service at startup (packages/App/Index.ts). Tests live in packages/App/FeatureSet/MCP/Tests and run as part of the App test suite:

cd packages/App
npm install
npx jest ./FeatureSet/MCP/Tests --runInBand

New models are picked up automatically: decorate a database model with @EnableMCP (or set enableMCP on an analytics model) and the tool generator creates its tools on the next start.

License

Apache-2.0 - See LICENSE file for details.

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.