OpenUptime
Manage OpenUptime monitoring, incidents, and status pages through the MCP server.
Discover and create workspaces/projects, and scope calls to workspace/project IDs.
List, create, update, pause, resume, run checks on, and delete monitors across HTTP, TCP, DNS, heartbeat, Postgres, MySQL, Redis, and multi-region setups.
Discover regions and alert channels, and attach channels/regions to monitors.
List, inspect, create, update, acknowledge, and post timeline updates to incidents, including public/internal visibility and postmortems.
List, create, and update public status pages, with monitor components, themes, latency display, and branding options.
Read public status-page summaries, incidents, and maintenance windows without credentials.
List maintenance windows for planning; create/remove maintenance and configure channels via the app or REST API.
Sends monitor and incident alerts to Discord channels, with alert channels assignable to monitors through the MCP tools.
Provides MySQL database monitors that check connectivity and health, and can open incidents or send alerts when checks fail.
Sends uptime and incident alerts to ntfy topics as an alert channel.
Sends monitor and incident alerts to PagerDuty for on-call escalation and incident response.
Provides PostgreSQL database monitors that check connectivity and health, and can trigger incidents and alerts on failure.
Provides Redis monitors that check service health and can open incidents or notify alert channels when checks fail.
Sends uptime and incident alerts to Slack channels, with alert channels configurable on monitors via the MCP tools.
Sends monitor and incident alerts to Telegram as an alert channel.
This server has a remotely hosted endpoint. Open its connector listing for connection details, authentication requirements, and setup instructions:

OpenUptime
Open-source uptime monitoring and status pages. Runs on Cloudflare Workers with Postgres, or in one Docker container.
Hosted version · Docs · Reference · MIT license
Features
Monitoring
HTTP / HTTPS with keyword matching and slow-response alerts
TCP, DNS and WebSocket
Heartbeat (push) monitors for cron jobs and background workers
PostgreSQL, MySQL and Redis
Domain expiry
EVM and Solana RPC node health
MCP server checks
Multi-region checks, with your own probes
Monitor dependencies, so a downstream outage doesn't page you twice
Incidents and status pages
Incidents with acknowledgement, assignment and postmortems
Maintenance windows, one-off or recurring
Public status pages
Email and RSS subscriptions for status page visitors
Status badges and embeds for your site or README
Alerts
Slack, Discord, Microsoft Teams, Telegram, Lark / Feishu and ntfy
PagerDuty, webhooks and email
Push notifications to the iOS app
Repeat reminders and escalation
Teams and automation
Workspaces, projects and roles
GitHub sign-in and two-factor authentication
REST API with API keys
MCP server so your AI agent can manage monitors, incidents and status pages
JSON import / export
Part | Stack |
| Hono, better-auth, Cloudflare Worker (cron + queue consumer) |
| Astro (static pages, SSR for status pages) + React islands |
| Storage interface ( |
| Postgres implementation of |
Related MCP server: DevHelm MCP Server
Deploy to Cloudflare
The site is two Workers on one domain:
Worker | Serves | Also does |
|
| minute cron, queue consumer that runs the checks |
| everything else on | status pages (SSR); reaches the API through a service binding |
Keeping the API under /api/* of the same domain means session cookies stay same-origin. You need no separate API hostname.
Before you start
A Cloudflare account and a domain whose DNS is on Cloudflare (the zone).
A Postgres database reachable from the internet (Neon, Supabase, RDS, your own). Workers connect through Hyperdrive.
Node.js 22+ and pnpm (
corepack enableprovides the pinned version).Workers Paid plan for the Queue (default). On the Free plan, run in inline mode instead: see Reference.
1. Get the code and sign in
git clone https://github.com/becoolme/openuptime.git && cd openuptime
pnpm install
cd apps/api && npx wrangler loginAll npx wrangler … commands below run in apps/api unless noted.
2. Create the Queue and Hyperdrive
npx wrangler queues create openuptime-checks
npx wrangler hyperdrive create openuptime-prod --connection-string="postgres://user:pass@host:5432/db"The second command prints an id. In apps/api/wrangler.jsonc uncomment the hyperdrive line and paste it:
"hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<id printed above>" }],The commented placement line is optional (it runs the Worker next to your database host); leave it commented unless you
want that.
3. Create the schema
From the repository root:
DATABASE_URL="postgres://user:pass@host:5432/db" pnpm db:migrateIt only applies what is new, so run it again after every upgrade. It never issues CREATE SCHEMA, so a role without
database-level CREATE works too.
4. Point the config at your domain
Edit two files. In both, replace status.example.com with your own domain.
apps/api/wrangler.jsonc, where zone_name is the zone (the apex domain) even when you serve from a subdomain.
Uncomment routes and set:
"routes": [{ "pattern": "status.example.com/api/*", "zone_name": "example.com" }],
"vars": {
"BETTER_AUTH_URL": "https://status.example.com", // public origin: cookies, OAuth, email links
"WEB_ORIGIN": "https://status.example.com", // same value
"EMAIL_FROM": "alerts@example.com" // sender address; optional, see below
}Email is optional: without it invitations and alerts are written to the Worker log. To send it, onboard your domain under Email Sending in the Cloudflare dashboard first (see Reference).
apps/web/wrangler.jsonc:
"routes": [{ "pattern": "status.example.com", "custom_domain": true }],
"vars": { "PRODUCT_URL": "https://status.example.com" } // target of the "Powered by" link on status pagesThe custom domain creates its DNS record and certificate for you; the hostname must not already have a DNS record pointing elsewhere.
No domain on Cloudflare? Leave routes out of both files and set BETTER_AUTH_URL and WEB_ORIGIN to the web
Worker's https://openuptime-web.<your-subdomain>.workers.dev address. The web Worker then forwards /api/* to the API
Worker through the service binding, so cookies stay same-origin.
5. Set the secrets
npx wrangler secret put BETTER_AUTH_SECRET # openssl rand -hex 32
npx wrangler secret put CRON_SECRET # any long random string; guards /internal/*If wrangler asks to create the Worker first, answer yes. Optional: GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET add
"Sign in with GitHub".
6. Deploy
pnpm exec wrangler deploy # in apps/api
cd ../web && pnpm build && pnpm exec wrangler deployDeploy the API first: the web Worker binds to it by name.
7. Check it
curl https://status.example.com/api/health # {"ok":true}Open the domain and sign up. Once your own account exists you can set "DISABLE_SIGNUP": "true" in the API vars and
deploy again to close registration (invited people can still join).
Upgrade later: pull, pnpm install, pnpm db:migrate, then deploy the API and the web Worker, in that order.
Self-host with Docker
One container runs the API, the web app and the check scheduler; Postgres comes with the compose file. Either run the published image or build it from source; the settings are the same.
Option A: run the published image
Tagged releases are published to ghcr.io/becoolme/openuptime for linux/amd64 and linux/arm64. You need no clone and
no build:
mkdir openuptime && cd openuptime
curl -fsSLO https://raw.githubusercontent.com/becoolme/openuptime/main/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/becoolme/openuptime/main/.env.docker.example -o .envEdit .env: set POSTGRES_PASSWORD and BETTER_AUTH_SECRET (openssl rand -hex 32), and uncomment OPENUPTIME_IMAGE.
Pin a version (ghcr.io/becoolme/openuptime:0.1.0) or follow the newest release (:latest). Then:
docker compose pull && docker compose up -d # http://localhost:8080Upgrade: change the tag if you pinned one, then run the same two commands again. Migrations run on start.
Option B: build from source
git clone https://github.com/becoolme/openuptime.git && cd openuptime
cp .env.docker.example .env # set POSTGRES_PASSWORD and BETTER_AUTH_SECRET (openssl rand -hex 32)
docker compose up -d --build # http://localhost:8080Upgrade: git pull, then docker compose up -d --build.
Either way
The schema is migrated on start and the data lives in the pgdata volume. Set PUBLIC_URL when the app is not served
from http://localhost:8080. Email is optional; see Reference.
Once your own account exists, set DISABLE_SIGNUP=true in .env and run docker compose up -d to close registration
(invited people can still join).
Develop
pnpm install
cp .env.example apps/api/.dev.vars # edit DATABASE_URL and secrets
DATABASE_URL=postgres://user:pass@localhost:5432/openuptime_dev pnpm db:migrate # same URL as in .dev.vars
pnpm dev:api # http://localhost:8787 (checks run inline every 15s)
pnpm dev:web # http://localhost:4321 (proxies /api to the API)
pnpm typecheckMCP server
Agents (Claude, Cursor, Codex and any MCP client) can manage monitors, incidents and status pages over Streamable HTTP at
/api/mcp, authorizing with OAuth or an API key:
claude mcp add --transport http openuptime https://openuptime.app/api/mcp # or https://<your-host>/api/mcpClient setup, scopes and the tool list are in the MCP docs.
An agent skill that teaches the common workflows ships in skills/openuptime:
npx skills add becoolme/openuptime.
The hosted server is listed
in the MCP Registry as app.openuptime/mcp; server.json is its entry.
Tests, how checks run, the MCP server, alert channels and the other details are in docs/reference.md.
Open source vs hosted
The monitoring itself is the same code in both. The hosted service at openuptime.app adds
plans, billing and a few features that live only in that build; it plugs into this repo through one interface
(Edition, see docs/editions.md), so nothing in the core is locked or throttled.
Self-hosted (this repo, MIT) | Hosted (openuptime.app) | |
Monitors, incidents, status pages, alert channels, API, MCP | All of it | All of it |
Limits | None: no plans, quotas or metering | Free plan, paid plans from $5/month (pricing); monitors, checks, emails and history length depend on the plan |
Running it | You: Postgres, the Worker or container, a mail provider, backups, upgrades | We do; nothing to install |
SSL certificate monitoring (expiry alerts, | Not included | Lite and above |
Custom domain for a status page | Not included | Every paid plan (Lite and above), plus early-access workspaces |
Where your data lives | Your database | Ours (Postgres on managed hosting) |
Pick self-hosting if you want to own the data and the infrastructure, or have no limits to worry about. Pick hosted if you would rather not run anything. Both receive the same core updates.
Contributing & security
See CONTRIBUTING.md. Report vulnerabilities privately as described in SECURITY.md, not in public issues.
License
Available Tools
26 toolsacknowledge_incidentAInspect
Assign an existing incident to the authenticated caller and return the incident record. Use this when taking ownership of an investigation; it does not resolve the incident or post a subscriber update. Use post_incident_update to communicate status, and list_incidents to discover the incident UUID.
Inputs: id (required), project, workspace.
create_incidentAInspect
Open a manual incident in the selected project and return its record and UUID. Use this for an event not already represented by an automatic incident; use post_incident_update for an existing incident. A monitorId limits it to pages containing that monitor; otherwise it applies to project status pages. The optional body becomes the first investigating update, public unless visibility is internal. Creation assigns the caller; it does not send subscriber update emails.
Inputs: title (required), body, project, severity, +3 more.
create_monitorAInspect
Create and start a monitor in the selected project; returns its record and UUID (heartbeat monitors include a ping token). Use list_regions and list_channels to discover optional region/channel ids. Heartbeats wait for pings; other types schedule outgoing checks. Auto-enabled alert channels are added, and failures can open incidents and notify channels. Hosted plans may reject capacity, frequency or region choices; private network targets are refused by default.
Inputs: name (required), tags, type, method, +18 more.
create_projectAInspect
Create a project inside the selected workspace and return its record and id. Use this to separate monitors within an existing workspace; use create_workspace for a separate team. Requires access to all projects in that workspace. The new project is immediately usable through the project argument.
Inputs: name (required), project, workspace.
create_status_pageAInspect
Publish a status page at /status/ and return its record and UUID. Use list_monitors to select components and an unused slug (a conflict returns an error); omitted monitorIds creates an empty page. The page and selected monitors' public status become readable without authentication. Use update_status_page to edit an existing page; branding options remain subject to the hosted plan.
Inputs: slug (required), title (required), theme, project, +5 more.
create_workspaceAInspect
Create a workspace owned by the signed-in user, including its first project. Use create_project instead to organize an existing workspace. Requires an OAuth grant for all workspaces; a workspace-scoped API key cannot create one. Returns the new workspace record and id; use list_workspaces to discover its project.
Inputs: name (required), project, workspace.
delete_monitorADestructiveIdempotentInspect
Permanently remove a monitor and its check history; returns an empty success response. Use pause_monitor instead when you may need it again. Requires workspace owner/admin access in addition to write scope. The monitor cannot be recovered through this tool; deletion does not create an incident-resolution update.
Inputs: id (required), project, workspace.
get_incidentARead-onlyIdempotentInspect
Investigate one incident by its UUID from list_incidents. Returns its write-up, update timeline (including internal updates), related monitor/checks, assignee and notification deliveries. Use list_incidents to discover ids; use update_incident to edit the write-up and post_incident_update to change status. This is private team information, unlike list_public_status_page_incidents.
Inputs: id (required), project, workspace.
get_monitorARead-onlyIdempotentInspect
Read one monitor's configuration, recent check history and uptime statistics by its UUID from list_monitors. Use this to investigate a specific monitor; list_monitors is the summary view and run_check performs a new check. Returns the monitor plus history; secret HTTP headers are masked for callers without management access.
Inputs: id (required), project, workspace.
get_public_status_pageARead-onlyIdempotentInspect
Read the published health summary for a status-page slug without credentials. Returns overall/component status, 90-day uptime and active public incidents; use list_public_status_page_incidents for incident history or list_public_status_page_maintenance for downtime schedules. Only published information is returned; a missing page or one with MCP access disabled returns an error.
Inputs: slug (required).
list_channelsARead-onlyIdempotentInspect
Discover alert-channel UUIDs and delivery types (email, webhook, Slack and others) in the selected project. Use the ids with create_monitor/update_monitor.channelIds to route alerts. Returns channel records, not a delivery test. Channel creation and secret configuration are managed through the app or REST API.
Inputs: project, workspace.
list_incidentsARead-onlyIdempotentInspect
Find automatic and manually opened incidents visible in the selected project, with open incidents first. Returns incident summaries and UUIDs; use get_incident for the timeline, failed checks and investigation details. To change status or resolve an incident, use post_incident_update rather than update_incident.
Inputs: project, workspace.
list_maintenanceARead-onlyIdempotentInspect
Read maintenance windows in the selected project, including schedule and monitor associations. Use this authenticated list for planning; list_public_status_page_maintenance only shows windows for a published page slug. This tool does not schedule downtime; use the app or REST API to create or remove windows.
Inputs: project, workspace.
list_monitorsARead-onlyIdempotentInspect
Read monitor summaries for the selected project, including ids, current status, uptime and latency. Use this to find a monitor before changing it or to scan for outages; use get_monitor for recent check history. Secret HTTP header values are masked unless the caller may manage the workspace.
Inputs: project, workspace.
list_public_status_page_incidentsARead-onlyIdempotentInspect
Read recent public incidents and their public updates for a published status-page slug, newest first. Use get_public_status_page for current health, or authenticated get_incident for internal investigation details. No credentials are needed; internal updates are excluded and a missing page or one with MCP access disabled returns an error.
Inputs: slug (required).
list_public_status_page_maintenanceARead-onlyIdempotentInspect
Read scheduled and ongoing public maintenance windows for a published status-page slug without credentials. Use this to explain announced downtime; authenticated list_maintenance is the project-wide management view. Returns public window records; a missing page or one with MCP access disabled returns an error.
Inputs: slug (required).
list_regionsARead-onlyIdempotentInspect
Discover configured check locations and the maximum regions per monitor on this deployment. Use the returned ids with create_monitor/update_monitor.regions or run_check.region; do not guess ids. auto is always available. Explicit remote regions support HTTP/TCP only; hosted plans may restrict how many are used.
Inputs: project, workspace.
list_status_pagesARead-onlyIdempotentInspect
Read status-page records and UUIDs in the selected project for management. Use these ids with update_status_page; use get_public_status_page with a slug to read the published component/outage summary instead. This private list does not include pages outside the selected project.
Inputs: project, workspace.
list_workspacesARead-onlyIdempotentInspect
Discover the workspace and project ids this connection may use before calling private tools. Returns accessible workspaces with their projects; it does not list other users' workspaces. Pass workspace/project ids to private tools to select a scope, or omit them to use this connection's defaults.
Inputs: project, workspace.
pause_monitorAInspect
Stop scheduled checks and alerts for one monitor, preserving its configuration and history; returns the paused monitor. Use this for a pause-only change, or update_monitor to combine a pause with configuration edits. For planned downtime that should still run checks, schedule maintenance through the app or REST API instead. Use resume_monitor to restart checking.
Inputs: id (required), project, workspace.
post_incident_updateAInspect
Append an incident timeline update and change its status; returns the new update record. Use this to communicate progress or resolve an incident, rather than update_incident (write-up only). Public updates appear on status pages and are emailed to subscribers; internal updates remain team-only and send no subscriber email. resolved closes the incident and must be public. Repeating a call creates another update and may send another email.
Inputs: id (required), body (required), status (required), project, +2 more.
resume_monitorAInspect
Restart checking a paused monitor and return its record with pending status. Use this for a resume-only change; use update_monitor for combined configuration edits. Its next check becomes due immediately and may create incidents or send alerts. Hosted active-monitor limits are checked again; existing history is retained.
Inputs: id (required), project, workspace.
run_checkAInspect
Check a monitor immediately. Without region, records the result through the normal incident/alert workflow and returns {ok:true}; it can notify channels. With region from list_regions, returns {ok:true,region,result} for an unrecorded spot check without changing monitor history/status. Use get_monitor to read existing checks. Heartbeats have no outgoing spot check; hosted check credits apply and probe/network errors are returned.
Inputs: id (required), region, project, workspace.
update_incidentAInspect
Edit an incident's root cause or Markdown postmortem and return the updated record. Use post_incident_update instead to change status or notify subscribers. Omitted fields stay unchanged; null or blank text clears a write-up field. Write-ups remain private unless publishPostmortem is true; a published postmortem appears on public status pages after resolution, and false hides it again.
Inputs: id (required), project, rootCause, workspace, +2 more.
update_monitorAInspect
Patch an existing monitor and return its updated record. Read get_monitor first, then send id and at least one changed field; omitted fields stay unchanged and type cannot change. Lists and headers replace their previous values, while documented nulls clear optional settings. Prefer pause_monitor/resume_monitor for a pause-only change; use this for configuration changes or a combined edit. Resuming sets status to pending; heartbeat interval/grace changes recalculate its deadline. New settings affect later checks and alerts; hosted plan limits and target restrictions still apply.
Inputs: id (required), name, tags, method, +19 more.
update_status_pageAIdempotentInspect
Patch an existing status page by its UUID from list_status_pages; returns {ok:true}. Use this to edit presentation or selected components; use get_public_status_page to read the public result. Omitted fields stay unchanged; monitorIds replaces the complete component list and [] clears it. Changes affect the published page; an empty externalUrl removes its header link. Hosted branding restrictions still apply.
Inputs: id (required), theme, title, project, +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 26 tools
Most tools have clearly separated purposes, especially monitor lifecycle, incident lifecycle, and public vs private status-page reads. A few boundaries could still be confused, such as update_incident versus post_incident_update, or list_incidents versus list_public_status_page_incidents, but descriptions explicitly clarify them.
Names are consistently snake_case and generally follow a verb_noun pattern: list_monitors, get_monitor, create_monitor, update_monitor, pause_monitor, resume_monitor, delete_monitor. Public and private variants are named predictably, with no mixed casing or chaotic verb styles.
The domain is broad—workspaces, projects, monitors, incidents, status pages, maintenance, channels, and regions—so many operations are justified. However, 26 tools is heavy and includes several public/private read variants, making the surface borderline overgrown.
Core monitor and incident workflows are well covered, but several resources are only partially managed: maintenance windows and alert channels are list-only, and projects/workspaces/status pages lack full CRUD. These gaps are notable because agents cannot schedule maintenance or configure channels through this MCP server.
Maintenance
Related MCP Connectors
Self-hostable uptime monitoring: create checks, read incidents, manage status pages.
MCP server for Uptrack uptime monitoring. Manage monitors and incidents from AI agents.
Free uptime monitoring: HTTP/TCP/TLS/DNS + MCP server checks, cron heartbeats, status pages, alerts.
Uptime monitoring and public status page: HTTP monitors, down/up alerts and incidents.
Related MCP Servers
AlicenseNot gradedqualityCmaintenanceMCP server for Uptrack uptime monitoring. Manage monitors and incidents from AI agents like Claude, ChatGPT, and Cursor.13 npmMIT
DevHelm MCP Serverofficial
AlicenseCqualityAmaintenanceMCP server for uptime monitoring, incidents, alerting, and dependency status.12944 PyPI1MIT
uptimepageofficial
AlicenseNot gradedqualityBmaintenanceMCP server for Uptimepage uptime monitoring. An LLM client can read your monitors and incidents, run a check on demand, and post incident updates. Writes need an OAuth login and a scoped token, and each one is logged.54AGPL 3.0- AlicenseNot gradedqualityDmaintenanceOfficial Hyperping MCP server for uptime, API, cron and server monitoring. 26 tools covering monitors, outages and timelines, uptime, response time, MTTR and MTTA, on-call schedules and escalation policies, over a remote Streamable HTTP endpoint with Bearer token auth and no install.1MIT