Skip to content

jmagar/gotify-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gotify MCP

PyPI ghcr.io

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

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 -d

Local development

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

Configuration

Two deployment paths are supported:

Path Transport Credentials Auth
Plugin (stdio) stdio userConfig in plugin settings None
Docker (HTTP) http .env file 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 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.

License

MIT

About

Gotify push notifications and management via MCP tools with HTTP fallback. Sends alerts for long-running tasks, plan completions, and blocked states.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors