claude-notify
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@claude-notifyping me when the database migration finishes"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
claude-notify
A remote MCP server exposing exactly one tool, notify_me, that sends a push
notification to your phone through Pushover.
Write "notify me when the migration finishes" or "ping me if the test suite fails" in a Claude Code prompt, and the session calls the tool when it gets there. Sessions run for hours on several machines; this is how they reach you.
It is a remote server rather than a local one so that adding a machine is one
claude mcp add line with nothing to install, and so the Pushover credentials
live in exactly one place.
Claude Code (any machine)
│ remote MCP over HTTPS, Authorization: Bearer <per-machine token>
▼
Cloudflare Worker ──► auth → rate limit → resolve label → truncate → POST ──► Pushover → iPhone
│
└─ KV: token hashes, rate counters, quota stateThe tool
Param | Type | Required | Notes |
| string | yes | The notification body |
| boolean | no, default | Pushover priority 1 — bypasses quiet hours |
There is deliberately no source or machine parameter. The label in the
title comes from the bearer token, resolved server-side, so a session cannot
mislabel itself and the model has one less argument to get wrong. Notifications
arrive titled [vps-01] Claude Code.
Related MCP server: pushover-mcp
First-time setup
You need a Cloudflare account, a Pushover account, and a Healthchecks.io check.
1. Pushover
Install Pushover on your phone and sign in. Your user key is on the dashboard.
Register an application at https://pushover.net/apps/build to get an API token.
Since 1 May 2026 the monthly allowance is per account, not per application — every app you register shares one pool of 10,000 messages a month.
2. Cloudflare
git clone <this repo> && cd claude-notify
npm install
cp wrangler.toml.example wrangler.toml
wrangler kv namespace create NOTIFY_KVPut your account_id (from wrangler whoami) and the namespace id printed by
that command into wrangler.toml. That file is gitignored.
3. Healthchecks.io
Create a check at https://healthchecks.io with a period of 1 hour and a grace of 20 minutes, and copy its ping URL.
Treat that URL as a credential. Anyone holding it can ping your dead-man's switch and permanently suppress the alert that tells you the Worker died.
4. Secrets and deploy
wrangler secret put PUSHOVER_TOKEN # the application API token
wrangler secret put PUSHOVER_USER # your user key
wrangler secret put HEALTHCHECKS_URL # https://hc-ping.com/<uuid>
wrangler deploySecrets are only ever set this way. They are never reachable by any client and never appear in a file in this repo.
Adding a machine
One token per machine, so a leak costs you one machine rather than all of them.
node scripts/token.mjs add vps-01The token is printed once and cannot be recovered — only its SHA-256 hash is stored. The command prints the registration line to run on that machine:
claude mcp add --transport http --scope user claude-notify \
https://YOUR-WORKER.workers.dev/mcp \
--header "Authorization: Bearer <the token printed by the CLI>"Then check it:
claude mcp list # claude-notify ... ✔ ConnectedManaging machines:
node scripts/token.mjs list # labels and status, never the tokens
node scripts/token.mjs revoke laptop # that machine gets 401 on its next callAdd --local to any of these to work against the wrangler dev KV simulation
instead of production.
Only the hash is stored, so hash the token before writing it — a mistake here produces a token that silently never authenticates.
TOKEN=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
HASH=$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)
wrangler kv key put "token:$HASH" '{"label":"ci-runner","enabled":true}' \
--binding NOTIFY_KV --remote
echo "$TOKEN" # shown once
# Revoke:
wrangler kv key delete "token:$HASH" --binding NOTIFY_KV --remoteUsing it
Just say so in the prompt:
Run the full test suite and notify me if anything fails.
This migration will take a while — ping me when it's done.
The session decides when to call the tool. It reports the real outcome back: on success, how many Pushover messages remain this month; on failure, the actual HTTP status and Pushover's own error text. It never retries and never reports success it did not get, so if the pipe is broken the session says so.
Health monitoring
A system cannot report its own death, so detection comes from outside.
Hourly the Worker reads KV and then pings Healthchecks.io. If the Worker
dies, Healthchecks notices the silence and emails you over a path that touches
neither Cloudflare nor Pushover. If KV is unreachable it pings /fail instead,
so a storage outage is reported rather than papered over.
Daily at 08:00 Europe/Athens it sends a real notification: Pipe OK, N remaining. This is the only thing that exercises the entire chain, including
APNs and your iOS notification settings — which can break silently after an OS
update, in a way no server-side check can detect.
Cloudflare cron triggers are UTC-only, so the daily job is registered at both
05:00 and 06:00 UTC and the Worker checks the wall-clock hour in
DAILY_PING_TZ. One of the two is 08:00 in Athens whether or not daylight
saving is in effect, so exactly one firing per day gets through and the
notification lands at 08:00 local year-round.
Rate limits and quota
The only power this endpoint has is making your phone buzz, so spam is the
threat and rate limiting is the control. Both limits are [vars] in
wrangler.toml:
RATE_LIMIT_PER_TOKEN— default 60/hour per machineRATE_LIMIT_GLOBAL— default 200/hour across all machines, so one compromised machine cannot burn the whole Pushover quota
A breach comes back as a tool error naming the limit and when it resets, so the calling session sees it.
Counters live in KV, which is eventually consistent and last-write-wins. Under a concurrent burst some increments are lost and a few extra messages get through. That is a deliberate trade: this is a spam guard on a doorbell, not an exact quota.
Every Pushover response carries the account's remaining monthly allowance, which
is persisted. When it drops below QUOTA_WARN_THRESHOLD (default 500) a warning
is appended to the next notification — reserved before the message is
truncated, so a long message cannot push the warning off the end.
Pushover caps messages at 1024 characters and titles at 250. Both are truncated, never rejected: a truncated notification beats a silent failure.
Development
npm run typecheck
# Order matters. Local KV is a single SQLite database that only one Wrangler
# process may hold open, and each process carries its own workerd runtime — so
# create the token *before* starting the dev server, never alongside it.
# `token.mjs --local` refuses if it sees a dev server on port 8787.
node scripts/token.mjs add laptop --local
npm run dev # wrangler dev, with .dev.vars for secrets
NOTIFY_URL=http://localhost:8787/mcp \
NOTIFY_TOKEN=<the token printed above> \
./test/smoke.shPoint NOTIFY_URL at https://YOUR-WORKER.workers.dev/mcp instead to smoke-test
the deployed Worker; a --local token will not authenticate against it, so use
one issued without --local.
Budget roughly 550 MB of RAM per wrangler dev (a Node parent plus two
workerd processes). Two Wrangler processes at once need over a gigabyte, which is
enough to livelock a small VM that has no swap.
The smoke test drives the whole path — tools/list, a real tools/call, an
unknown token, and a browser-origin request — and reads its credentials from
the environment rather than from the file.
For local development put secrets in .dev.vars (gitignored):
PUSHOVER_TOKEN=...
PUSHOVER_USER=...
HEALTHCHECKS_URL=...Cron jobs can be triggered by hand against wrangler dev:
curl "http://localhost:8787/cdn-cgi/local/scheduled?cron=0+*+*+*+*" # Healthchecks ping
curl "http://localhost:8787/cdn-cgi/local/scheduled?cron=0+5,6+*+*+*" # daily pipe testProtocol notes
MCP revision 2026-07-28 made the protocol stateless: no initialize
handshake, no sessions, no Mcp-Session-Id, no GET stream. Each request
declares its own protocol version and capabilities in a _meta envelope,
mirrored into MCP-Protocol-Version, Mcp-Method and Mcp-Name headers.
This server is dual-era: it serves both the stateless revision and 2025-era
clients that still open with initialize, on the same /mcp endpoint. Claude
Code's rollout of the stateless revision is still in progress across versions,
so serving only one era would strand clients on the other.
Requests carrying an Origin header are refused with 403. Nothing legitimate
calls this from a browser — Claude Code sends no Origin at all — and this is
the transport spec's required DNS-rebinding protection.
Troubleshooting
✘ Failed to connect in claude mcp list — usually a bad or revoked token.
The server returns 401 with no detail, deliberately; check with
node scripts/token.mjs list and reissue if needed.
Connected, but tool calls return Unauthorized — there was a Claude Code
bug where the configured --header was attached on connect but dropped on tool
calls (#50464, fixed
June 2026). If you see this, upgrade Claude Code first.
Notifications stop arriving on the 1st of a month — the Pushover account quota is exhausted; it resets monthly. The daily pipe test reports the remaining count, which is the warning you get before this happens.
The daily test stops but the hourly check stays green — the Worker and KV are fine, so suspect the chain beyond them: Pushover credentials, or iOS notification settings after an update.
Security
Tokens are stored only as SHA-256 hashes, keyed by the hash. Nothing compares secrets, so there is no timing-attack surface.
Raw tokens are never logged. What reaches the request context is the hash.
Unknown and disabled tokens are indistinguishable to the client: same status, same empty body.
PUSHOVER_TOKEN,PUSHOVER_USERandHEALTHCHECKS_URLare Worker secrets and are never reachable by any client.If a credential leaks, rotate it. Rewriting git history is not sufficient.
.gitignore excludes wrangler.toml (it carries the account id and deployed
URL), .dev.vars, and .env. Every example in this file uses placeholders, and
every machine label is a generic one — vps-01, laptop, ci-runner. Real
labels live in KV, not in the repository.
Non-goals
Deliberately not built, and not to be added: a second transport (Telegram, ntfy); two-way messaging; Claude Code hooks integration; IP allowlisting or Tailscale; scheduled or interval status pings; a local MCP server variant.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityCmaintenanceA simple MCP server that can send notifications on mac devices.Last updated57626MIT
- AlicenseAqualityCmaintenanceA tiny MCP server that sends push notifications through Pushover, supporting message, title, priority, sound, URL, and device parameters.Last updated11MIT
- Alicense-qualityDmaintenanceMCP server for sending notifications to ntfy.sh or self-hosted ntfy instances.Last updated26MIT
- AlicenseBqualityDmaintenanceA lightweight MCP server for sending push notifications via ntfy.sh, supporting customizable titles, priorities, tags, and action buttons.Last updated1177MIT
Related MCP Connectors
Push notifications for AI agents - send instant iPhone notifications from any MCP client.
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
A very simple remote MCP server that greets you, with a custom icon.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/slamprou/claude-notify'
If you have feedback or need assistance with the MCP directory API, please join our Discord server