gotify-mcp 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. gotify_mcp-0.3.0/.agents/plugins/marketplace.json +20 -0
  2. gotify_mcp-0.3.0/.app.json +9 -0
  3. gotify_mcp-0.3.0/.claude-plugin/plugin.json +50 -0
  4. gotify_mcp-0.3.0/.codex-plugin/plugin.json +43 -0
  5. gotify_mcp-0.3.0/.dockerignore +49 -0
  6. gotify_mcp-0.3.0/.env.example +43 -0
  7. gotify_mcp-0.3.0/.github/workflows/ci.yml +41 -0
  8. gotify_mcp-0.3.0/.github/workflows/docker-publish.yml +75 -0
  9. gotify_mcp-0.3.0/.github/workflows/publish-pypi.yml +63 -0
  10. gotify_mcp-0.3.0/.gitignore +86 -0
  11. gotify_mcp-0.3.0/.mcp.json +8 -0
  12. gotify_mcp-0.3.0/.pre-commit-config.yaml +36 -0
  13. gotify_mcp-0.3.0/AGENTS.md +1 -0
  14. gotify_mcp-0.3.0/CHANGELOG.md +50 -0
  15. gotify_mcp-0.3.0/CLAUDE.md +67 -0
  16. gotify_mcp-0.3.0/Dockerfile +58 -0
  17. gotify_mcp-0.3.0/GEMINI.md +1 -0
  18. gotify_mcp-0.3.0/Justfile +78 -0
  19. gotify_mcp-0.3.0/LICENSE +21 -0
  20. gotify_mcp-0.3.0/PKG-INFO +696 -0
  21. gotify_mcp-0.3.0/README.md +685 -0
  22. gotify_mcp-0.3.0/assets/icon.png +0 -0
  23. gotify_mcp-0.3.0/assets/logo.svg +0 -0
  24. gotify_mcp-0.3.0/assets/screenshots/.gitkeep +0 -0
  25. gotify_mcp-0.3.0/docker-compose.yml +39 -0
  26. gotify_mcp-0.3.0/docs/gotify-api.json +2678 -0
  27. gotify_mcp-0.3.0/entrypoint.sh +43 -0
  28. gotify_mcp-0.3.0/gemini-extension.json +35 -0
  29. gotify_mcp-0.3.0/gotify_mcp/__init__.py +1 -0
  30. gotify_mcp-0.3.0/gotify_mcp/server.py +459 -0
  31. gotify_mcp-0.3.0/gotify_mcp/services/__init__.py +1 -0
  32. gotify_mcp-0.3.0/gotify_mcp/services/gotify.py +328 -0
  33. gotify_mcp-0.3.0/hooks/hooks.json +33 -0
  34. gotify_mcp-0.3.0/hooks/scripts/ensure-ignore-files.sh +111 -0
  35. gotify_mcp-0.3.0/hooks/scripts/fix-env-perms.sh +33 -0
  36. gotify_mcp-0.3.0/hooks/scripts/sync-env.sh +60 -0
  37. gotify_mcp-0.3.0/pyproject.toml +54 -0
  38. gotify_mcp-0.3.0/scripts/check-docker-security.sh +145 -0
  39. gotify_mcp-0.3.0/scripts/check-no-baked-env.sh +144 -0
  40. gotify_mcp-0.3.0/scripts/check-outdated-deps.sh +181 -0
  41. gotify_mcp-0.3.0/scripts/ensure-ignore-files.sh +314 -0
  42. gotify_mcp-0.3.0/scripts/lint-plugin.sh +474 -0
  43. gotify_mcp-0.3.0/scripts/smoke-test.sh +226 -0
  44. gotify_mcp-0.3.0/server.json +49 -0
  45. gotify_mcp-0.3.0/skills/gotify/SKILL.md +311 -0
  46. gotify_mcp-0.3.0/tests/test_live.sh +21 -0
  47. gotify_mcp-0.3.0/uv.lock +1337 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "gotify-mcp",
3
+ "interface": {
4
+ "displayName": "Gotify MCP"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "gotify-mcp",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Utilities"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "apps": [
3
+ {
4
+ "name": "gotify-mcp",
5
+ "type": "mcp",
6
+ "config": "./.mcp.json"
7
+ }
8
+ ]
9
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "gotify-mcp",
3
+ "version": "0.3.0",
4
+ "description": "Gotify push notifications and management via MCP tools with HTTP fallback. Sends alerts for long-running tasks, plan completions, and blocked states.",
5
+ "author": {
6
+ "name": "Jacob Magar"
7
+ },
8
+ "repository": "https://github.com/jmagar/gotify-mcp",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "gotify",
12
+ "notifications",
13
+ "push",
14
+ "homelab",
15
+ "mcp"
16
+ ],
17
+ "userConfig": {
18
+ "gotify_mcp_url": {
19
+ "type": "string",
20
+ "title": "Gotify MCP Server URL",
21
+ "description": "Full MCP endpoint URL (e.g. http://localhost:9158/mcp). Default works if running via docker compose in this repo.",
22
+ "default": "https://gotify.tootie.tv/mcp",
23
+ "sensitive": false
24
+ },
25
+ "gotify_mcp_token": {
26
+ "type": "string",
27
+ "title": "MCP Server Bearer Token",
28
+ "description": "Bearer token for authenticating with the gotify-mcp server. Must match GOTIFY_MCP_TOKEN in .env. Generate with: openssl rand -hex 32",
29
+ "sensitive": true
30
+ },
31
+ "gotify_url": {
32
+ "type": "string",
33
+ "title": "Gotify Server URL",
34
+ "description": "Base URL of your Gotify server, e.g. http://gotify or https://gotify.example.com. No trailing slash.",
35
+ "sensitive": true
36
+ },
37
+ "gotify_app_token": {
38
+ "type": "string",
39
+ "title": "Gotify App Token",
40
+ "description": "Gotify application token for sending messages. Found in Gotify UI under Settings -> Apps -> Create Application.",
41
+ "sensitive": true
42
+ },
43
+ "gotify_client_token": {
44
+ "type": "string",
45
+ "title": "Gotify Client Token",
46
+ "description": "Gotify client token for management operations (list messages, manage apps/clients). Found in Gotify UI under Settings -> Clients.",
47
+ "sensitive": true
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "gotify-mcp",
3
+ "version": "0.3.0",
4
+ "description": "Gotify push notification management via MCP.",
5
+ "homepage": "https://github.com/jmagar/gotify-mcp",
6
+ "repository": "https://github.com/jmagar/gotify-mcp",
7
+ "license": "MIT",
8
+ "keywords": [
9
+ "gotify",
10
+ "notifications",
11
+ "push",
12
+ "homelab",
13
+ "mcp"
14
+ ],
15
+ "skills": "./skills/",
16
+ "mcpServers": "./.mcp.json",
17
+ "apps": "./.app.json",
18
+ "interface": {
19
+ "displayName": "Gotify MCP",
20
+ "shortDescription": "Send and manage Gotify push notifications",
21
+ "longDescription": "Send push notifications and manage Gotify applications, clients, and messages through MCP tools and bundled skills.",
22
+ "developerName": "Jacob Magar",
23
+ "category": "Utilities",
24
+ "capabilities": [
25
+ "Read",
26
+ "Write"
27
+ ],
28
+ "websiteURL": "https://github.com/jmagar/gotify-mcp",
29
+ "defaultPrompt": [
30
+ "Send a Gotify alert when this task finishes.",
31
+ "List my Gotify applications and clients.",
32
+ "Review recent Gotify messages."
33
+ ],
34
+ "brandColor": "#7B44F2",
35
+ "composerIcon": "./assets/icon.png",
36
+ "logo": "./assets/logo.svg"
37
+ },
38
+ "author": {
39
+ "name": "Jacob Magar",
40
+ "email": "jmagar@users.noreply.github.com",
41
+ "url": "https://github.com/jmagar"
42
+ }
43
+ }
@@ -0,0 +1,49 @@
1
+ .git
2
+ .github
3
+ .claude-plugin
4
+ .codex-plugin
5
+ .agents
6
+ .beads
7
+ .dolt
8
+ .omc
9
+ .lavra
10
+ .serena
11
+ .cache
12
+ .worktrees
13
+ .full-review
14
+ .full-review-archive-*
15
+ .vscode
16
+ .cursor
17
+ .windsurf
18
+ .1code
19
+ .idea
20
+ .env
21
+ .env.*
22
+ !.env.example
23
+ *.log
24
+ logs/
25
+ backups/
26
+ docs/
27
+ specs/
28
+ *.md
29
+ !README.md
30
+ __pycache__
31
+ *.pyc
32
+ .pytest_cache
33
+ .ruff_cache
34
+ .mypy_cache
35
+ .coverage
36
+ htmlcov
37
+ .hypothesis
38
+ node_modules
39
+ dist
40
+ coverage
41
+ *.tsbuildinfo
42
+ target
43
+ Justfile
44
+ biome.json
45
+ .pre-commit-config.yaml
46
+ .prettierrc
47
+ .prettierignore
48
+ tests/
49
+
@@ -0,0 +1,43 @@
1
+ # =============================================================================
2
+ # GOTIFY SERVER CONFIGURATION
3
+ # =============================================================================
4
+ GOTIFY_URL=https://your-gotify-instance.example.com
5
+ GOTIFY_CLIENT_TOKEN=your_gotify_client_token
6
+ GOTIFY_APP_TOKEN=your_gotify_app_token
7
+
8
+ # =============================================================================
9
+ # MCP SERVER CONFIGURATION
10
+ # =============================================================================
11
+ GOTIFY_MCP_HOST=0.0.0.0
12
+ GOTIFY_MCP_PORT=9158
13
+ GOTIFY_MCP_TRANSPORT=http
14
+
15
+ # Bearer token for MCP server authentication.
16
+ # Generate with: openssl rand -hex 32
17
+ GOTIFY_MCP_TOKEN=
18
+
19
+ # Set to true to disable bearer auth (e.g. behind a trusted reverse proxy)
20
+ GOTIFY_MCP_NO_AUTH=false
21
+
22
+ # =============================================================================
23
+ # LOGGING
24
+ # =============================================================================
25
+ GOTIFY_LOG_LEVEL=INFO
26
+
27
+ # =============================================================================
28
+ # DOCKER / CONTAINER SETTINGS
29
+ # =============================================================================
30
+ PUID=1000
31
+ PGID=1000
32
+
33
+ # External Docker network name (leave empty to use default bridge)
34
+ DOCKER_NETWORK=
35
+
36
+ # =============================================================================
37
+ # USAGE
38
+ # =============================================================================
39
+ # 1. Copy this file to .env: cp .env.example .env
40
+ # 2. Set GOTIFY_URL, GOTIFY_CLIENT_TOKEN, GOTIFY_APP_TOKEN
41
+ # 3. Generate and set GOTIFY_MCP_TOKEN: openssl rand -hex 32
42
+ # 4. Run: docker compose up -d
43
+ # 5. Test: curl http://localhost:9158/health
@@ -0,0 +1,41 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ jobs:
7
+ lint:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - uses: astral-sh/setup-uv@v5
12
+ - run: uv sync --group dev
13
+ - run: uv run ruff check .
14
+ - run: uv run ruff format --check .
15
+ typecheck:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: astral-sh/setup-uv@v5
20
+ - run: uv sync --group dev
21
+ - run: uv run ty check
22
+ test:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: astral-sh/setup-uv@v5
27
+ - run: uv sync --group dev
28
+ - run: uv run pytest
29
+ audit:
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - uses: astral-sh/setup-uv@v5
34
+ - run: uv sync --group dev
35
+ - run: uv export --no-hashes | uv pip compile - -q | uv pip audit --stdin || true
36
+ contract-drift:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - uses: astral-sh/setup-uv@v5
41
+ - run: bash scripts/lint-plugin.sh
@@ -0,0 +1,75 @@
1
+ name: Build and Push Docker Image
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - 'v*'
9
+ pull_request:
10
+ branches:
11
+ - main
12
+ workflow_dispatch:
13
+
14
+ env:
15
+ REGISTRY: ghcr.io
16
+ IMAGE_NAME: ${{ github.repository }}
17
+
18
+ jobs:
19
+ build-and-push:
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ contents: read
23
+ packages: write
24
+
25
+ steps:
26
+ - name: Checkout repository
27
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
28
+
29
+ - name: Set up Docker Buildx
30
+ uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
31
+
32
+ - name: Log in to GitHub Container Registry
33
+ if: github.event_name != 'pull_request'
34
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
35
+ with:
36
+ registry: ${{ env.REGISTRY }}
37
+ username: ${{ github.actor }}
38
+ password: ${{ secrets.GITHUB_TOKEN }}
39
+
40
+ - name: Extract metadata
41
+ id: meta
42
+ uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
43
+ with:
44
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45
+ tags: |
46
+ type=ref,event=branch
47
+ type=ref,event=pr
48
+ type=semver,pattern={{version}}
49
+ type=semver,pattern={{major}}.{{minor}}
50
+ type=semver,pattern={{major}}
51
+ type=raw,value=latest,enable={{is_default_branch}}
52
+ type=sha
53
+
54
+ - name: Build and push Docker image
55
+ uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
56
+ with:
57
+ context: .
58
+ platforms: linux/amd64,linux/arm64
59
+ push: ${{ github.event_name != 'pull_request' }}
60
+ tags: ${{ steps.meta.outputs.tags }}
61
+ labels: ${{ steps.meta.outputs.labels }}
62
+ cache-from: type=gha
63
+ cache-to: type=gha,mode=max
64
+ sbom: true
65
+ provenance: mode=max
66
+
67
+ - name: Scan image for vulnerabilities
68
+ if: github.event_name != 'pull_request'
69
+ uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0
70
+ with:
71
+ image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
72
+ format: 'sarif'
73
+ output: 'trivy-results.sarif'
74
+ severity: 'CRITICAL,HIGH'
75
+
@@ -0,0 +1,63 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write # required for pypa/gh-action-pypi-publish trusted publishing
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment: release
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: astral-sh/setup-uv@v5
20
+
21
+ - name: Verify tag matches pyproject.toml version
22
+ run: |
23
+ PKG_VERSION=$(grep -m1 '^version' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')
24
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
25
+ if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
26
+ echo "Version mismatch: pyproject.toml=$PKG_VERSION tag=$TAG_VERSION"
27
+ exit 1
28
+ fi
29
+
30
+ - name: Build package
31
+ run: uv build
32
+
33
+ - name: Publish to PyPI
34
+ uses: pypa/gh-action-pypi-publish@release/v1
35
+ with:
36
+ attestations: true
37
+
38
+ - name: Create GitHub Release
39
+ env:
40
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
+ run: |
42
+ gh release create "$GITHUB_REF_NAME" \
43
+ --title "Release $GITHUB_REF_NAME" \
44
+ --generate-notes \
45
+ dist/*
46
+
47
+ - name: Install mcp-publisher
48
+ run: |
49
+ curl -fsSL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
50
+
51
+ - name: Set version in server.json
52
+ run: |
53
+ VERSION="${GITHUB_REF_NAME#v}"
54
+ jq --arg v "$VERSION" '
55
+ .version = $v |
56
+ .packages = [.packages[] | if .registryType == "pypi" then .version = $v else . end]
57
+ ' server.json > server.tmp && mv server.tmp server.json
58
+
59
+ - name: Authenticate to MCP Registry
60
+ run: ./mcp-publisher login dns --domain tootie.tv --private-key ${{ secrets.MCP_PRIVATE_KEY }}
61
+
62
+ - name: Publish to MCP Registry
63
+ run: ./mcp-publisher publish
@@ -0,0 +1,86 @@
1
+ # ── Secrets ──────────────────────────────────────────────────────────────────
2
+ .env
3
+ .env.*
4
+ !.env.example
5
+
6
+ # ── Runtime artifacts ────────────────────────────────────────────────────────
7
+ logs/
8
+ backups/
9
+ *.log
10
+ *.pid
11
+ *.bak
12
+ *.bak-*
13
+
14
+ # ── Claude Code / AI tooling ────────────────────────────────────────────────
15
+ .claude/settings.local.json
16
+ .claude/worktrees/
17
+ .omc/
18
+ .lavra/
19
+ .beads/
20
+ .dolt/
21
+ *.db
22
+ *.db-shm
23
+ *.db-wal
24
+ .beads-credential-key
25
+ .serena/
26
+ .worktrees/
27
+ .full-review/
28
+ .full-review-archive-*
29
+ .bivvy
30
+
31
+ # ── IDE / editor ─────────────────────────────────────────────────────────────
32
+ .vscode/
33
+ .cursor/
34
+ .windsurf/
35
+ .1code/
36
+ .idea/
37
+ .zed/
38
+ *.iml
39
+ *.swp
40
+ *.swo
41
+ *~
42
+ .emdash.json
43
+
44
+ # ── OS generated ─────────────────────────────────────────────────────────────
45
+ .DS_Store
46
+ Thumbs.db
47
+
48
+ # ── Caches (ALL tool caches go here) ─────────────────────────────────────────
49
+ .cache/
50
+
51
+ # ── Documentation artifacts (session/plan docs, not reference) ───────────────
52
+ .docs/
53
+ docs/plans/
54
+ docs/sessions/
55
+ docs/reports/
56
+ docs/research/
57
+ docs/superpowers/
58
+ specs/
59
+
60
+ # ── Python ───────────────────────────────────────────────────────────────────
61
+ .venv/
62
+ __pycache__/
63
+ *.py[oc]
64
+ *.egg-info/
65
+ *.egg
66
+ build/
67
+ dist/
68
+ sdist/
69
+ wheels/
70
+ pip-wheel-metadata/
71
+ *.whl
72
+ .hypothesis/
73
+ .pytest_cache/
74
+ .ruff_cache/
75
+ .ty_cache/
76
+ .mypy_cache/
77
+ .pytype/
78
+ .pyre/
79
+ .pyright/
80
+ htmlcov/
81
+ .coverage
82
+ .coverage.*
83
+ coverage.xml
84
+ .tox/
85
+ .nox/
86
+ pip-log.txt
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "gotify-mcp": {
4
+ "type": "http",
5
+ "url": "${GOTIFY_MCP_URL}"
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,36 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-merge-conflict
9
+ - repo: https://github.com/astral-sh/ruff-pre-commit
10
+ rev: v0.8.4
11
+ hooks:
12
+ - id: ruff
13
+ args: [--fix]
14
+ - id: ruff-format
15
+ - repo: local
16
+ hooks:
17
+ - id: skills-validate
18
+ name: Validate skills
19
+ entry: just validate-skills
20
+ language: system
21
+ pass_filenames: false
22
+ - id: docker-security
23
+ name: Docker security check
24
+ entry: bash scripts/check-docker-security.sh
25
+ language: system
26
+ pass_filenames: false
27
+ - id: no-baked-env
28
+ name: No baked env vars
29
+ entry: bash scripts/check-no-baked-env.sh
30
+ language: system
31
+ pass_filenames: false
32
+ - id: ensure-ignore-files
33
+ name: Ensure ignore files
34
+ entry: bash scripts/ensure-ignore-files.sh --check
35
+ language: system
36
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ CLAUDE.md
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-04-04
11
+
12
+ ### Added
13
+ - **MCP Registry publishing**: `server.json` conforming to the official MCP Registry schema; published as `tv.tootie/gotify-mcp`
14
+ - **Automated registry CI**: `publish-pypi.yml` extended to authenticate via DNS (tootie.tv Ed25519 key) and publish to `registry.modelcontextprotocol.io` after each PyPI release
15
+ - **PyPI ownership verification**: `<!-- mcp-name: tv.tootie/gotify-mcp -->` comment in README for registry validation
16
+ - **OCI discoverability label**: `io.modelcontextprotocol.server.name` LABEL added to Dockerfile
17
+
18
+ ## [0.2.2] - 2026-04-03
19
+
20
+ ### Fixed
21
+ - **OAuth discovery 401 cascade**: BearerAuthMiddleware was blocking GET /.well-known/oauth-protected-resource, causing MCP clients to surface generic "unknown error". Added WellKnownMiddleware (RFC 9728) to return resource metadata.
22
+
23
+ ### Added
24
+ - **docs/AUTHENTICATION.md**: New setup guide covering token generation and client config.
25
+ - **README Authentication section**: Added quick-start examples and link to full guide.
26
+
27
+
28
+
29
+ ### Added
30
+ - FastMCP server with `gotify` and `gotify_help` tools
31
+ - BearerAuthMiddleware with startup token validation
32
+ - Dual transport (http/stdio via GOTIFY_MCP_TRANSPORT)
33
+ - Action+subaction pattern for all Gotify operations
34
+ - CLAUDE.md, AGENTS.md, GEMINI.md AI memory files
35
+ - Multi-stage Dockerfile with non-root user (1000:1000)
36
+ - ensure-ignore-files.sh hook for .gitignore and .dockerignore
37
+ - .codex-plugin/plugin.json and .app.json for Codex CLI support
38
+ - assets/ directory with icon and logo placeholders
39
+ - gotify_mcp_token userConfig entry in plugin.json
40
+ - .dockerignore with all required patterns
41
+ - flock-based concurrency in sync-env.sh
42
+ - awk-based env replacement in sync-env.sh
43
+
44
+ ## [0.1.0] - 2026-03-29
45
+
46
+ ### Added
47
+ - Initial release
48
+ - Gotify message sending, listing, deleting
49
+ - Gotify application and client management
50
+ - Docker Compose deployment
@@ -0,0 +1,67 @@
1
+ # gotify-mcp
2
+
3
+ MCP server for Gotify push notification management.
4
+
5
+ ## Development
6
+
7
+ - Language: Python (FastMCP + uv)
8
+ - Port: 9158 (GOTIFY_MCP_PORT)
9
+ - Auth: Bearer token (GOTIFY_MCP_TOKEN)
10
+
11
+ ## Commands
12
+
13
+ ```bash
14
+ just dev # run locally
15
+ just test # run tests
16
+ just lint # ruff check
17
+ just build # docker build
18
+ ```
19
+
20
+ ## Environment Variables
21
+
22
+ | Variable | Required | Description |
23
+ |---|---|---|
24
+ | `GOTIFY_URL` | Yes | Base URL of your Gotify server |
25
+ | `GOTIFY_CLIENT_TOKEN` | Yes | Gotify client token for management |
26
+ | `GOTIFY_APP_TOKEN` | Yes | Gotify app token for sending messages |
27
+ | `GOTIFY_MCP_TOKEN` | Yes (HTTP) | Bearer token for MCP server auth |
28
+ | `GOTIFY_MCP_URL` | No | MCP server URL (for .mcp.json) |
29
+ | `GOTIFY_MCP_PORT` | No | MCP server port (default 9158) |
30
+ | `GOTIFY_MCP_HOST` | No | MCP server host (default 0.0.0.0) |
31
+ | `GOTIFY_MCP_TRANSPORT` | No | Transport mode: http or stdio (default http) |
32
+ | `GOTIFY_MCP_NO_AUTH` | No | Set true to disable bearer auth |
33
+ | `GOTIFY_LOG_LEVEL` | No | Log level (default INFO) |
34
+ | `PUID` | No | User ID for container (default 1000) |
35
+ | `PGID` | No | Group ID for container (default 1000) |
36
+
37
+ ## Architecture
38
+
39
+ - `gotify_mcp/server.py` — FastMCP server entry point, action+subaction pattern
40
+ - `gotify_mcp/client.py` — Gotify HTTP API client
41
+ - `entrypoint.sh` — Container entrypoint with env validation
42
+ - `hooks/scripts/sync-env.sh` — Syncs userConfig to .env at session start
43
+ - `hooks/scripts/ensure-ignore-files.sh` — Ensures .gitignore and .dockerignore have required patterns
44
+ - `hooks/scripts/fix-env-perms.sh` — Enforces chmod 600 on .env
45
+
46
+
47
+ ## Version Bumping
48
+
49
+ **Every feature branch push MUST bump the version in ALL version-bearing files.**
50
+
51
+ Bump type is determined by the commit message prefix:
52
+ - `feat!:` or `BREAKING CHANGE` → **major** (X+1.0.0)
53
+ - `feat` or `feat(...)` → **minor** (X.Y+1.0)
54
+ - Everything else (`fix`, `chore`, `refactor`, `test`, `docs`, etc.) → **patch** (X.Y.Z+1)
55
+
56
+ **Files to update (if they exist in this repo):**
57
+ - `Cargo.toml` — `version = "X.Y.Z"` in `[package]`
58
+ - `package.json` — `"version": "X.Y.Z"`
59
+ - `pyproject.toml` — `version = "X.Y.Z"` in `[project]`
60
+ - `.claude-plugin/plugin.json` — `"version": "X.Y.Z"`
61
+ - `.codex-plugin/plugin.json` — `"version": "X.Y.Z"`
62
+ - `gemini-extension.json` — `"version": "X.Y.Z"`
63
+ - `README.md` — version badge or header
64
+ - `CHANGELOG.md` — new entry under the bumped version
65
+
66
+ All files MUST have the same version. Never bump only one file.
67
+ CHANGELOG.md must have an entry for every version bump.