Repository navigation
Conversation
Expose a stateless Streamable HTTP Model Context Protocol endpoint at /mcp which provides a send_message tool to AI agents. The endpoint only accepts application tokens and can be disabled with GOTIFY_SERVER_MCP_ENABLED=false.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1066 +/- ##
==========================================
+ Coverage 76.12% 76.32% +0.20%
==========================================
Files 67 68 +1
Lines 3619 3688 +69
==========================================
+ Hits 2755 2815 +60
- Misses 653 659 +6
- Partials 211 214 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1059
Adds an optional, built-in Model Context Protocol endpoint at
/mcp, so AI agents can send messages with an application token:claude mcp add gotify --transport http https://gotify.example.com/mcp --header "Authorization: Bearer <apptoken>"Scope
Kept tightly scoped as discussed in #1059: sending messages only, nothing else.
Auth: application tokens only, via the existing
RequireApplicationTokenmiddleware (X-Gotify-Key,Authorization: Bearer, or?token=). Client tokens and unknown tokens get 401, basic auth gets 403, so an agent can never read, delete or manage anything.One tool:
send_messagewithmessage(required),title,priority, and three convenience flags mapped to documented extras:markdown→client::display.contentTypeclick_url→client::notification.click.urlbig_image_url→client::notification.bigImageUrlRaw
extrasare intentionally not exposed, so models can't make up namespaces.Stateless: Streamable HTTP in stateless + JSON-response mode. No sessions, no SSE, no extra server state; it behaves like any other REST endpoint behind a reverse proxy or with multiple instances.
Shared logic: the defaulting/store/notify part of
CreateMessageis extracted intocreateMessage, so REST and MCP behave the same (default title = app name, default priority, stream notification).Opt-out:
GOTIFY_SERVER_MCP_ENABLED(defaulttrue). Withfalse,/mcpis not registered at all.Why built in rather than OpenAPI-to-MCP
click_url/big_image_urlonly take effect in the Android client.api/mcp.go, one tool, reusing the existing message path.Dependency
Uses the official
github.com/modelcontextprotocol/go-sdk(v1.x, maintained by the MCP org with Google). It adds 5 small indirect modules:google/jsonschema-go,segmentio/encoding,segmentio/asm,yosida95/uritemplate,golang.org/x/time.Tests
Integration tests in
router/mcp_test.gouse the SDK client against the real router: sending with and without extras, default title/priority, empty message, token types (app/client/unknown/basic auth), and the disabled switch.Open question
The endpoint is enabled by default, since it doesn't grant anything an application token can't already do via
POST /message. Happy to flip the default tofalseif you prefer.