gotify-mcp
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., "@gotify-mcpsend a notification saying 'Build complete' with priority 5"
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.
Gotify MCP
MCP server for self-hosted Gotify. Exposes a unified gotify action router and a gotify_help companion tool for sending notifications and managing Gotify messages, applications, clients, and account metadata.
Overview
Two MCP tools are exposed:
Tool | Purpose |
| Unified action router for all Gotify operations |
| Returns markdown documentation for all actions and parameters |
The server supports HTTP (default) and stdio transports. HTTP transport requires bearer authentication via GOTIFY_MCP_TOKEN.
What this repository ships
gotify_mcp/server.py: FastMCP server, action router, and BearerAuth middlewaregotify_mcp/services/gotify.py: Async HTTP client for the Gotify REST APIskills/gotify/SKILL.md: Client-facing skill documentationdocs/gotify-api.json: Bundled upstream Gotify API reference.claude-plugin/plugin.json,.codex-plugin/plugin.json,gemini-extension.json: Client manifestsdocker-compose.yml,Dockerfile,entrypoint.sh: Container deploymentscripts/: Smoke tests and contract checks
Tools
gotify
Single entry point for all Gotify operations. Select the operation with the action parameter.
gotify(action="send_message", app_token="AbCdEf", message="Build finished", priority=5)gotify_help
Returns the full action reference as Markdown. Call this to discover available actions.
gotify_help()Actions
send_message
Send a push notification. Requires an app_token — this is the per-application token, not the client token.
Parameter | Type | Required | Default | Description |
| string | yes | — | Application token from Gotify UI (Settings > Apps) |
| string | yes | — | Notification body. Supports Markdown when |
| string | no | — | Notification title |
| integer | no | app default | Priority 0–10. See Priority Levels below. |
| dict | no | — | Extended metadata. See Extras Structure below. |
Response fields:
Field | Type | Description |
| integer | Assigned message ID |
| integer | Application ID that sent the message |
| string | Message body |
| string | Message title |
| integer | Effective priority |
| string | ISO 8601 timestamp |
| dict | Extras as submitted |
Example:
gotify(action="send_message",
app_token="AbCdEf",
title="Deployment done",
message="## Summary\n- All steps complete\n- Ready for review",
priority=7,
extras={"client::display": {"contentType": "text/markdown"}})list_messages
List messages with pagination and optional filtering.
Parameter | Type | Required | Default | Description |
| integer | no | — | Filter to messages from one application |
| integer | no |
| Cursor offset (message ID) — items before this ID are skipped |
| integer | no |
| Maximum number of messages to return |
| string | no |
| Field to sort by. Valid values: |
| string | no |
|
|
| string | no |
| Case-insensitive substring filter applied to title and message body |
Response fields:
Field | Type | Description |
| array | Array of message objects (same shape as |
| integer | Total messages before pagination |
| integer | Limit used |
| integer | Offset used |
| boolean | Whether more pages exist |
Note: Gotify uses cursor-style pagination internally. The offset parameter maps to the since query parameter (a message ID), not a row count.
Example:
gotify(action="list_messages", limit=20, sort_order="desc")
gotify(action="list_messages", app_id=3, query="error", limit=10)delete_message
Delete a single message by ID. Destructive — requires confirm=True.
Parameter | Type | Required | Default | Description |
| integer | yes | — | ID of the message to delete |
| boolean | yes |
| Must be |
Example:
gotify(action="delete_message", message_id=42, confirm=True)delete_all_messages
Delete all messages across all applications. Destructive — requires confirm=True.
Parameter | Type | Required | Default | Description |
| boolean | yes |
| Must be |
Example:
gotify(action="delete_all_messages", confirm=True)list_applications
List all applications registered on the Gotify server.
Parameter | Type | Required | Default | Description |
| integer | no |
| Number of items to skip |
| integer | no |
| Maximum items to return |
| string | no |
| Case-insensitive substring filter on application name |
Response fields:
Field | Type | Description |
| array | Array of application objects |
| integer | Total applications before pagination |
| integer | Limit used |
| integer | Offset used |
| boolean | Whether more pages exist |
Each application object contains:
Field | Type | Description |
| integer | Application ID |
| string | Application token (use for |
| string | Application name |
| string | Application description |
| integer | Default message priority |
| string | Path to application image |
| boolean | Whether this is an internal application |
Example:
gotify(action="list_applications")
gotify(action="list_applications", query="homelab")create_application
Create a new Gotify application.
Parameter | Type | Required | Default | Description |
| string | yes | — | Application name |
| string | no | — | Application description |
| integer | no | — | Default priority for messages from this app (0–10) |
Returns the created application object.
Example:
gotify(action="create_application",
name="homelab-alerts",
description="Claude Code homelab notifications",
default_priority=5)update_application
Update an existing application. Provide at least one of name, description, or default_priority.
Parameter | Type | Required | Default | Description |
| integer | yes | — | ID of the application to update |
| string | no | — | New application name |
| string | no | — | New description |
| integer | no | — | New default priority (0–10) |
Returns the updated application object.
Example:
gotify(action="update_application", app_id=3, name="homelab-alerts-v2", default_priority=7)delete_application
Delete an application and all its messages. Destructive — requires confirm=True.
Parameter | Type | Required | Default | Description |
| integer | yes | — | ID of the application to delete |
| boolean | yes |
| Must be |
Example:
gotify(action="delete_application", app_id=3, confirm=True)list_clients
List all registered Gotify clients. Requires GOTIFY_CLIENT_TOKEN.
Parameter | Type | Required | Default | Description |
| integer | no |
| Number of items to skip |
| integer | no |
| Maximum items to return |
| string | no |
| Case-insensitive substring filter on client name |
Response has the same pagination shape as list_applications. Each client object contains id, token, and name.
Example:
gotify(action="list_clients")create_client
Create a new Gotify client. Returns the client object including its token.
Parameter | Type | Required | Default | Description |
| string | yes | — | Client name |
Example:
gotify(action="create_client", name="my-phone")delete_client
Delete a Gotify client. Destructive — requires confirm=True.
Parameter | Type | Required | Default | Description |
| integer | yes | — | ID of the client to delete |
| boolean | yes |
| Must be |
Example:
gotify(action="delete_client", client_id=5, confirm=True)health
Check the Gotify server health status. No additional parameters.
Returns a JSON object with health fields from the upstream Gotify /health endpoint. Note: this MCP tool call requires bearer authentication. The raw HTTP /health endpoint on the MCP server is unauthenticated.
Example:
gotify(action="health")version
Get the Gotify server version. No additional parameters. No authentication required on the upstream call.
Example:
gotify(action="version")current_user
Get the current authenticated user's account information. Requires GOTIFY_CLIENT_TOKEN.
No additional parameters. Returns the user object with id, name, and admin fields.
Example:
gotify(action="current_user")Token Types
Gotify uses two separate token types. Using the wrong type will produce a 401 error.
Token | Source | Used for |
App token | Gotify UI: Settings > Apps > Create Application |
|
Client token | Gotify UI: Settings > Clients > Create Client | All management actions: list/delete messages, list/create/delete apps and clients, current_user |
The MCP server reads GOTIFY_CLIENT_TOKEN from the environment and uses it automatically for management actions. You never pass it explicitly to the tool.
The app_token for send_message is always passed explicitly per call — it is not read from the server environment.
Priority Levels
The priority field is an integer from 0 to 10. Gotify clients interpret priority ranges as follows:
Range | Level | Recommended use |
0–3 | Low | Informational, FYI messages |
4–7 | Normal | Task updates, completions, standard alerts |
8–10 | High | Blocked states, errors, urgent alerts |
If priority is omitted from send_message, the application's defaultPriority is used. If the application has no default, Gotify falls back to 0.
Extras Structure
The extras field in send_message is a free-form dict passed to the Gotify API. The most common use is enabling Markdown rendering:
extras={"client::display": {"contentType": "text/markdown"}}Other known namespaces from the upstream Gotify extras specification:
Key | Value type | Description |
| dict | Display hints for Gotify clients |
| string |
|
| dict | Platform-specific notification overrides |
Any key/value pairs are accepted — the server passes them through as-is.
Destructive Operations
Four actions are gated behind a confirmation check:
delete_messagedelete_all_messagesdelete_applicationdelete_client
Without confirm=True, the server returns:
{"error": "Destructive operation. Pass confirm=True to proceed."}To bypass the gate server-wide, set either environment variable:
ALLOW_DESTRUCTIVE=true # skip confirm check
ALLOW_YOLO=true # identical effectThese env vars are intended for automated environments where interactive confirmation is not possible.
Pagination
List actions (list_messages, list_applications, list_clients) share a common pagination interface:
Parameter | Type | Default | Notes |
| integer |
| Items to skip. For |
| integer |
| Maximum items per page |
| string |
|
|
| string |
|
|
| string |
| Substring filter. Matches title and body for messages; name for apps and clients. Case-insensitive. |
All list responses include total, limit, offset, and has_more alongside the items array.
Error Handling
All errors return a JSON object with these fields:
Field | Type | Description |
| string | Short error identifier |
| integer | HTTP status code or 500 for network errors |
| string | Human-readable explanation |
Common errors:
error | errorCode | Cause |
| 401 | Wrong or missing token type for the operation |
| 403 | Token valid but operation not permitted for this user |
| 404 | Message, application, or client ID does not exist |
| 400 |
|
| 500 | Network failure reaching the Gotify server |
| 401 | Neither |
Responses are truncated at 512 KB. Truncated responses include ... [truncated] at the end.
Installation
Claude Code plugin (recommended)
Install as a Claude Code plugin. You will be prompted for:
Gotify Server URL — base URL of your Gotify instance
Gotify App Token — for sending messages (from Gotify UI: Settings > Apps)
Gotify Client Token — for management operations (from Gotify UI: Settings > Clients)
The plugin uses stdio transport with ${userConfig.*} interpolation — no .env file needed.
Docker Compose
cp .env.example .env
chmod 600 .env
# Edit .env with your credentials
docker compose up -dLocal development
uv sync --dev
uv run gotify-mcp-serverConfiguration
Two deployment paths are supported:
Path | Transport | Credentials | Auth |
Plugin (stdio) | stdio |
| None |
Docker (HTTP) | http |
| Bearer token |
See docs/CONFIG.md for the full environment variable reference.
Docker URL rewriting
When running inside Docker, localhost and 127.0.0.1 in GOTIFY_URL are automatically rewritten to host.docker.internal so the container can reach a host-side Gotify server.
Usage examples
Send a plain text notification
gotify(action="send_message",
app_token="AbCdEf",
title="Build finished",
message="All tests passed.",
priority=5)Send a Markdown notification
gotify(action="send_message",
app_token="AbCdEf",
title="Deploy complete",
message="## Status\n- All steps done\n- Ready for review",
priority=7,
extras={"client::display": {"contentType": "text/markdown"}})Page through messages
# First page
gotify(action="list_messages", limit=25, offset=0)
# Next page (use the ID of the last message as offset)
gotify(action="list_messages", limit=25, offset=99)Filter messages by text
gotify(action="list_messages", query="error", limit=20)Filter messages from one application
gotify(action="list_messages", app_id=3, limit=50)Manage applications
# List all applications
gotify(action="list_applications")
# Create
gotify(action="create_application",
name="homelab-alerts",
description="Automated notifications",
default_priority=5)
# Update
gotify(action="update_application", app_id=3, default_priority=7)
# Delete (destructive)
gotify(action="delete_application", app_id=3, confirm=True)Manage clients
# List all clients
gotify(action="list_clients")
# Create
gotify(action="create_client", name="my-phone")
# Delete (destructive)
gotify(action="delete_client", client_id=5, confirm=True)Server info
gotify(action="health")
gotify(action="version")
gotify(action="current_user")HTTP fallback
When MCP tools are unavailable, use direct HTTP calls. App tokens go to /message, client tokens go to management endpoints.
# Send a notification
curl -s -X POST "$GOTIFY_URL/message" \
-H "X-Gotify-Key: $GOTIFY_APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Done","message":"All steps complete","priority":7}'
# List messages
curl -s "$GOTIFY_URL/message" \
-H "X-Gotify-Key: $GOTIFY_CLIENT_TOKEN"
# List applications
curl -s "$GOTIFY_URL/application" \
-H "X-Gotify-Key: $GOTIFY_CLIENT_TOKEN"
# Health (no auth)
curl -s "$GOTIFY_URL/health"Development
Setup
just setupThis copies .env.example to .env (if not already present) and installs all dependencies.
Commands
just dev # Run the server locally (uv run python -m gotify_mcp.server)
just lint # Run ruff check
just fmt # Run ruff format
just typecheck # Run ty check
just test # Run pytest
just build # Build Docker image
just up # Start via docker compose
just down # Stop docker compose
just restart # Restart docker compose
just logs # Follow docker compose logs
just health # curl http://localhost:9158/health
just test-live # Run live integration tests (requires running server)
just gen-token # Generate a random bearer token
just clean # Remove build artifactsVerification
Run before committing:
just lint
just typecheck
just testLive verification (requires a running server and Gotify instance):
just test-liveServer health endpoint
The MCP server exposes an unauthenticated HTTP health endpoint:
GET http://localhost:9158/healthThis proxies through to the Gotify server's /health and returns:
{"status": "ok", "gotify": {...}}Or on failure:
{"status": "error", "reason": "..."}Logs
The server writes rotating logs to logs/gotify_mcp.log (max 5 MB, 3 backups). Log level is controlled by GOTIFY_LOG_LEVEL.
Related plugins
Plugin | Category | Description |
core | Core agents, commands, skills, and setup/health workflows for homelab management. | |
media | Search movies and TV shows, submit requests, and monitor failed requests via Overseerr. | |
infrastructure | Query, monitor, and manage Unraid servers: Docker, VMs, array, parity, and live telemetry. | |
infrastructure | Monitor and manage UniFi devices, clients, firewall rules, and network health. | |
infrastructure | Create, edit, and manage SWAG nginx reverse proxy configurations. | |
infrastructure | Docker management (Flux) and SSH remote operations (Scout) across homelab hosts. | |
infrastructure | Manage Docker environments, containers, images, volumes, networks, and GitOps via Arcane. | |
infrastructure | Receive, index, and search syslog streams from all homelab hosts via SQLite FTS5. | |
dev-tools | Scaffold, review, align, and deploy homelab MCP plugins with agents and canonical templates. |
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.
Latest Blog Posts
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/jmagar/gotify-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server