Skip to main content

MCP server for Gotify push notifications

Project description

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
gotify Unified action router for all Gotify operations
gotify_help 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 middleware
  • gotify_mcp/services/gotify.py: Async HTTP client for the Gotify REST API
  • skills/gotify/SKILL.md: Client-facing skill documentation
  • docs/gotify-api.json: Bundled upstream Gotify API reference
  • .claude-plugin/plugin.json, .codex-plugin/plugin.json, gemini-extension.json: Client manifests
  • docker-compose.yml, Dockerfile, entrypoint.sh: Container deployment
  • scripts/: 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
app_token string yes Application token from Gotify UI (Settings > Apps)
message string yes Notification body. Supports Markdown when extras sets contentType.
title string no Notification title
priority integer no app default Priority 0–10. See Priority Levels below.
extras dict no Extended metadata. See Extras Structure below.

Response fields:

Field Type Description
id integer Assigned message ID
appid integer Application ID that sent the message
message string Message body
title string Message title
priority integer Effective priority
date string ISO 8601 timestamp
extras 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
app_id integer no Filter to messages from one application
offset integer no 0 Cursor offset (message ID) — items before this ID are skipped
limit integer no 50 Maximum number of messages to return
sort_by string no "id" Field to sort by. Valid values: id, date, priority
sort_order string no "desc" "asc" or "desc"
query string no "" Case-insensitive substring filter applied to title and message body

Response fields:

Field Type Description
items array Array of message objects (same shape as send_message response)
total integer Total messages before pagination
limit integer Limit used
offset integer Offset used
has_more 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
message_id integer yes ID of the message to delete
confirm boolean yes False Must be True to proceed

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
confirm boolean yes False Must be True to proceed

Example:

gotify(action="delete_all_messages", confirm=True)

list_applications

List all applications registered on the Gotify server.

Parameter Type Required Default Description
offset integer no 0 Number of items to skip
limit integer no 50 Maximum items to return
query string no "" Case-insensitive substring filter on application name

Response fields:

Field Type Description
items array Array of application objects
total integer Total applications before pagination
limit integer Limit used
offset integer Offset used
has_more boolean Whether more pages exist

Each application object contains:

Field Type Description
id integer Application ID
token string Application token (use for send_message)
name string Application name
description string Application description
defaultPriority integer Default message priority
image string Path to application image
internal 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
name string yes Application name
description string no Application description
default_priority 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
app_id integer yes ID of the application to update
name string no New application name
description string no New description
default_priority 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
app_id integer yes ID of the application to delete
confirm boolean yes False Must be True to proceed

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
offset integer no 0 Number of items to skip
limit integer no 50 Maximum items to return
query 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
name 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
client_id integer yes ID of the client to delete
confirm boolean yes False Must be True to proceed

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 send_message only — passed per call as app_token
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
client::display dict Display hints for Gotify clients
client::display.contentType string "text/plain" (default) or "text/markdown"
client::notification 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_message
  • delete_all_messages
  • delete_application
  • delete_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 effect

These 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
offset integer 0 Items to skip. For list_messages, maps to the since cursor (a message ID). For list_applications and list_clients, applied client-side as a row offset.
limit integer 50 Maximum items per page
sort_by string "id" list_messages only. Field to sort by: id, date, priority. Not applied for apps or clients.
sort_order string "desc" list_messages only. "asc" or "desc".
query 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
error string Short error identifier
errorCode integer HTTP status code or 500 for network errors
errorDescription string Human-readable explanation

Common errors:

error errorCode Cause
Unauthorized 401 Wrong or missing token type for the operation
HTTP 403 403 Token valid but operation not permitted for this user
HTTP 404 404 Message, application, or client ID does not exist
NoUpdateFields 400 update_application called with no fields to update
RequestError 500 Network failure reaching the Gotify server
No token provided 401 Neither app_token nor GOTIFY_CLIENT_TOKEN is set

Responses are truncated at 512 KB. Truncated responses include ... [truncated] at the end.

Installation

Marketplace

/plugin marketplace add jmagar/claude-homelab
/plugin install gotify-mcp @jmagar-claude-homelab

Local development

uv sync --dev
uv run gotify-mcp-server

Direct module invocation:

uv run python -m gotify_mcp.server

Docker

just up

Or manually:

docker compose up -d

Configuration

Copy .env.example to .env and fill in the required values:

cp .env.example .env

Environment variables

Variable Required Default Description
GOTIFY_URL yes Base URL of your Gotify server (no trailing slash). Server exits at startup if unset.
GOTIFY_CLIENT_TOKEN yes* Client token for management operations. Without this, all management actions fail.
GOTIFY_APP_TOKEN no App token used in HTTP fallback examples. The MCP tool requires app_token per call.
GOTIFY_MCP_HOST no 0.0.0.0 Interface for the MCP HTTP server to bind to
GOTIFY_MCP_PORT no 9158 Port for the MCP HTTP server
GOTIFY_MCP_TRANSPORT no http Transport mode: http or stdio
GOTIFY_MCP_TOKEN yes** Bearer token for MCP server authentication. Generate with openssl rand -hex 32. Required when transport is http and GOTIFY_MCP_NO_AUTH is not set.
GOTIFY_MCP_NO_AUTH no false Set true to disable bearer auth. Appropriate only behind a trusted reverse proxy.
GOTIFY_LOG_LEVEL no INFO Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
ALLOW_DESTRUCTIVE no false Set true to skip confirm=True requirement for destructive actions
ALLOW_YOLO no false Identical to ALLOW_DESTRUCTIVE
PUID no 1000 User ID for container process
PGID no 1000 Group ID for container process

*GOTIFY_CLIENT_TOKEN is required for management actions. Without it, a warning is logged at startup and management actions return 401.

**GOTIFY_MCP_TOKEN is required when GOTIFY_MCP_TRANSPORT=http and GOTIFY_MCP_NO_AUTH=false. The server exits at startup if neither is set.

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 setup

This 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 artifacts

Verification

Run before committing:

just lint
just typecheck
just test

Live verification (requires a running server and Gotify instance):

just test-live

Server health endpoint

The MCP server exposes an unauthenticated HTTP health endpoint:

GET http://localhost:9158/health

This 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
homelab-core core Core agents, commands, skills, and setup/health workflows for homelab management.
overseerr-mcp media Search movies and TV shows, submit requests, and monitor failed requests via Overseerr.
unraid-mcp infrastructure Query, monitor, and manage Unraid servers: Docker, VMs, array, parity, and live telemetry.
unifi-mcp infrastructure Monitor and manage UniFi devices, clients, firewall rules, and network health.
swag-mcp infrastructure Create, edit, and manage SWAG nginx reverse proxy configurations.
synapse-mcp infrastructure Docker management (Flux) and SSH remote operations (Scout) across homelab hosts.
arcane-mcp infrastructure Manage Docker environments, containers, images, volumes, networks, and GitOps via Arcane.
syslog-mcp infrastructure Receive, index, and search syslog streams from all homelab hosts via SQLite FTS5.
plugin-lab dev-tools Scaffold, review, align, and deploy homelab MCP plugins with agents and canonical templates.
axon research Self-hosted web crawl, ingest, embed, and RAG pipeline with MCP tooling.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gotify_mcp-0.3.1.tar.gz (107.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gotify_mcp-0.3.1-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file gotify_mcp-0.3.1.tar.gz.

File metadata

  • Download URL: gotify_mcp-0.3.1.tar.gz
  • Upload date:
  • Size: 107.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gotify_mcp-0.3.1.tar.gz
Algorithm Hash digest
SHA256 3a817a41bcaf7566851da2bb00dcaf85cf6c1b83b18a25214f774efdae648568
MD5 52aa0947b0936a3b5b29f7a2b10491b1
BLAKE2b-256 7bab5da659271e85416c3bb77204e22c941bc33d1718910cd7185220477c26d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for gotify_mcp-0.3.1.tar.gz:

Publisher: publish-pypi.yml on jmagar/gotify-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gotify_mcp-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: gotify_mcp-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gotify_mcp-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a92dace284fee950340b0df19f35adff2b3d707faed9fd510e21fc55ee74f4b8
MD5 a8c7c6028676d224d84139a652ec56f4
BLAKE2b-256 9efa1e060b3c209da53bba83bb4d9b6633e78d40110c199fe5456e21f0d0f7c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for gotify_mcp-0.3.1-py3-none-any.whl:

Publisher: publish-pypi.yml on jmagar/gotify-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page