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.
- gotify_mcp-0.3.0/.agents/plugins/marketplace.json +20 -0
- gotify_mcp-0.3.0/.app.json +9 -0
- gotify_mcp-0.3.0/.claude-plugin/plugin.json +50 -0
- gotify_mcp-0.3.0/.codex-plugin/plugin.json +43 -0
- gotify_mcp-0.3.0/.dockerignore +49 -0
- gotify_mcp-0.3.0/.env.example +43 -0
- gotify_mcp-0.3.0/.github/workflows/ci.yml +41 -0
- gotify_mcp-0.3.0/.github/workflows/docker-publish.yml +75 -0
- gotify_mcp-0.3.0/.github/workflows/publish-pypi.yml +63 -0
- gotify_mcp-0.3.0/.gitignore +86 -0
- gotify_mcp-0.3.0/.mcp.json +8 -0
- gotify_mcp-0.3.0/.pre-commit-config.yaml +36 -0
- gotify_mcp-0.3.0/AGENTS.md +1 -0
- gotify_mcp-0.3.0/CHANGELOG.md +50 -0
- gotify_mcp-0.3.0/CLAUDE.md +67 -0
- gotify_mcp-0.3.0/Dockerfile +58 -0
- gotify_mcp-0.3.0/GEMINI.md +1 -0
- gotify_mcp-0.3.0/Justfile +78 -0
- gotify_mcp-0.3.0/LICENSE +21 -0
- gotify_mcp-0.3.0/PKG-INFO +696 -0
- gotify_mcp-0.3.0/README.md +685 -0
- gotify_mcp-0.3.0/assets/icon.png +0 -0
- gotify_mcp-0.3.0/assets/logo.svg +0 -0
- gotify_mcp-0.3.0/assets/screenshots/.gitkeep +0 -0
- gotify_mcp-0.3.0/docker-compose.yml +39 -0
- gotify_mcp-0.3.0/docs/gotify-api.json +2678 -0
- gotify_mcp-0.3.0/entrypoint.sh +43 -0
- gotify_mcp-0.3.0/gemini-extension.json +35 -0
- gotify_mcp-0.3.0/gotify_mcp/__init__.py +1 -0
- gotify_mcp-0.3.0/gotify_mcp/server.py +459 -0
- gotify_mcp-0.3.0/gotify_mcp/services/__init__.py +1 -0
- gotify_mcp-0.3.0/gotify_mcp/services/gotify.py +328 -0
- gotify_mcp-0.3.0/hooks/hooks.json +33 -0
- gotify_mcp-0.3.0/hooks/scripts/ensure-ignore-files.sh +111 -0
- gotify_mcp-0.3.0/hooks/scripts/fix-env-perms.sh +33 -0
- gotify_mcp-0.3.0/hooks/scripts/sync-env.sh +60 -0
- gotify_mcp-0.3.0/pyproject.toml +54 -0
- gotify_mcp-0.3.0/scripts/check-docker-security.sh +145 -0
- gotify_mcp-0.3.0/scripts/check-no-baked-env.sh +144 -0
- gotify_mcp-0.3.0/scripts/check-outdated-deps.sh +181 -0
- gotify_mcp-0.3.0/scripts/ensure-ignore-files.sh +314 -0
- gotify_mcp-0.3.0/scripts/lint-plugin.sh +474 -0
- gotify_mcp-0.3.0/scripts/smoke-test.sh +226 -0
- gotify_mcp-0.3.0/server.json +49 -0
- gotify_mcp-0.3.0/skills/gotify/SKILL.md +311 -0
- gotify_mcp-0.3.0/tests/test_live.sh +21 -0
- 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,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,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.
|