Skip to main content
Glama
jmagar
by jmagar

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

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.

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

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity
Issues opened vs closed

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