pushover-mcp
by metaember
README.md
# pushover-mcp
A tiny [MCP](https://modelcontextprotocol.io) server that sends push
notifications through [Pushover](https://pushover.net).
It exposes one tool:
- **`send_notification`** — send a `message` with optional `title`, `priority`,
`sound`, `url`, `url_title`, and `device`.
Two parameters are designed to read well to an LLM:
- **`priority`** uses names instead of numbers: `lowest`, `low`, `normal`
(default), `high`, `emergency` (repeats until acknowledged).
- **`sound`** is an allowlist fetched live from Pushover's sounds API **once at
startup** and cached for the process. If that fetch fails (offline, or no
token), it falls back to a baked-in list so the server still starts.
## Setup
1. Get your **user key** from your [Pushover dashboard](https://pushover.net)
and create an application to get an **API token**
at <https://pushover.net/apps/build>.
2. Install dependencies:
```sh
uv sync
```
## Run
The server reads `PUSHOVER_TOKEN` and `PUSHOVER_USER` from the environment.
### With 1Password (recommended)
`.env` holds **secret references** (`op://…`), not the secrets themselves.
Launch through `op run` to resolve them at runtime:
```sh
op run --env-file=.env -- uv run pushover_mcp.py
```
### With plain env vars
```sh
PUSHOVER_TOKEN=... PUSHOVER_USER=... uv run pushover_mcp.py
```
## Use with Claude Code / Claude Desktop
Launching via `op run` keeps secrets out of the MCP config entirely:
```sh
claude mcp add pushover -- \
op run --env-file=/Users/charlesbine/Documents/prog/mcp/pushover/.env -- \
uv run --directory /Users/charlesbine/Documents/prog/mcp/pushover pushover_mcp.py
```
Or as JSON (e.g. `claude_desktop_config.json`):
```json
{
"mcpServers": {
"pushover": {
"command": "op",
"args": [
"run", "--env-file=/Users/charlesbine/Documents/prog/mcp/pushover/.env", "--",
"uv", "run", "--directory", "/Users/charlesbine/Documents/prog/mcp/pushover", "pushover_mcp.py"
]
}
}
}
```
## Tests
```sh
uv run pytest
```
Tests mock the network and use no real credentials, so they run offline.
Run them with plain `uv run pytest` (not via `op run`) so the import-time sound
fetch falls back instead of calling the live API. GitHub Actions runs the suite
on every push and pull request across Python 3.10–3.13 (see
`.github/workflows/ci.yml`).
## Run over HTTP (Docker)
The server speaks stdio by default. Set `MCP_TRANSPORT=streamable-http` to serve
over [Streamable HTTP](https://modelcontextprotocol.io) instead, so any
HTTP-capable MCP client can connect at `http://<host>:8000/mcp`. The Docker image
sets this for you.
```sh
docker build -t pushover-mcp .
docker run --rm -e PUSHOVER_TOKEN -e PUSHOVER_USER -p 8000:8000 pushover-mcp
```
As a Compose service — credentials live in this container's own environment (an
`env_file` or Docker secrets), so they stay isolated to this tool:
```yaml
services:
pushover-mcp:
build: .
environment:
PUSHOVER_TOKEN: ${PUSHOVER_TOKEN}
PUSHOVER_USER: ${PUSHOVER_USER}
restart: unless-stopped
```
The HTTP endpoint is unauthenticated, so don't expose it publicly — keep it on a
private/internal network (and drop the published `ports:` if a co-located client
reaches it over the Compose network).
## License
[MIT](LICENSE) © Charles Bine
TDQS
A3.9/5.0
Scored across 1 tool
Disambiguation5/5
Only one tool exists, so there is no possibility of confusion between tools.
Naming Consistency5/5
With a single tool, naming is trivially consistent.
Tool Count5/5
A single tool is appropriate for a focused server that sends push notifications via Pushover.
Completeness4/5
The tool covers the primary action of sending notifications, but lacks secondary features like delivery status or recipient management, which are minor gaps.
Maintenance
ActivityInactive
ResponsivenessNo issues