mirror of
https://github.com/taigrr/gotify-mcp.git
synced 2025-10-23 01:27:18 +03:00
update to use official libraries
This commit is contained in:
7
go.mod
7
go.mod
@@ -1,11 +1,10 @@
|
||||
module github.com/taigrr/gotify-mcp
|
||||
|
||||
go 1.24.5
|
||||
go 1.25.2
|
||||
|
||||
require github.com/mark3labs/mcp-go v0.33.0
|
||||
require github.com/modelcontextprotocol/go-sdk v1.0.0
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/google/jsonschema-go v0.3.0 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
)
|
||||
|
||||
32
go.sum
32
go.sum
@@ -1,26 +1,10 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc=
|
||||
github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
|
||||
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
|
||||
github.com/modelcontextprotocol/go-sdk v1.0.0 h1:Z4MSjLi38bTgLrd/LjSmofqRqyBiVKRyQSJgw8q8V74=
|
||||
github.com/modelcontextprotocol/go-sdk v1.0.0/go.mod h1:nYtYQroQ2KQiM0/SbyEPUWQ6xs4B95gJjEalc9AQyOs=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
|
||||
243
main.go
243
main.go
@@ -5,11 +5,11 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
type GotifyMessage struct {
|
||||
@@ -18,81 +18,55 @@ type GotifyMessage struct {
|
||||
Priority int `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
func getStringArg(args map[string]any, key string, defaultValue string) string {
|
||||
if val, ok := args[key].(string); ok {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
type SendMessageArgs struct {
|
||||
Message string `json:"message" jsonschema:"The message content to send"`
|
||||
Title string `json:"title,omitempty" jsonschema:"Optional title for the message"`
|
||||
Priority float64 `json:"priority,omitempty" jsonschema:"Message priority (0-10 default: 5)"`
|
||||
}
|
||||
|
||||
func getNumberArg(args map[string]any, key string, defaultValue float64) float64 {
|
||||
if val, ok := args[key].(float64); ok {
|
||||
return val
|
||||
}
|
||||
return defaultValue
|
||||
type AskForHelpArgs struct {
|
||||
Context string `json:"context" jsonschema:"Context or description of what help is needed"`
|
||||
Error string `json:"error,omitempty" jsonschema:"Optional error message or details"`
|
||||
}
|
||||
|
||||
type NotifyCompletionArgs struct {
|
||||
Task string `json:"task" jsonschema:"Description of the completed task"`
|
||||
Result string `json:"result,omitempty" jsonschema:"Optional result or outcome details"`
|
||||
}
|
||||
|
||||
type SummarizeActivityArgs struct {
|
||||
Summary string `json:"summary" jsonschema:"Summary of activities or current status"`
|
||||
Details string `json:"details,omitempty" jsonschema:"Optional additional details"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := server.NewMCPServer(
|
||||
"Gotify Notification Server",
|
||||
"1.0.0",
|
||||
server.WithToolCapabilities(false),
|
||||
)
|
||||
server := mcp.NewServer(&mcp.Implementation{
|
||||
Name: "Gotify Notification Server",
|
||||
Version: "1.0.0",
|
||||
}, nil)
|
||||
|
||||
sendMessageTool := mcp.NewTool("send-message",
|
||||
mcp.WithDescription("Send a message to a Gotify server for notifications"),
|
||||
mcp.WithString("message",
|
||||
mcp.Required(),
|
||||
mcp.Description("The message content to send"),
|
||||
),
|
||||
mcp.WithString("title",
|
||||
mcp.Description("Optional title for the message"),
|
||||
),
|
||||
mcp.WithNumber("priority",
|
||||
mcp.Description("Message priority (0-10, default: 5)"),
|
||||
),
|
||||
)
|
||||
mcp.AddTool(server, &mcp.Tool{
|
||||
Name: "send-message",
|
||||
Description: "Send a message to a Gotify server for notifications",
|
||||
}, sendMessage)
|
||||
|
||||
askForHelpTool := mcp.NewTool("ask-for-help",
|
||||
mcp.WithDescription("Send a help request notification to the user via Gotify"),
|
||||
mcp.WithString("context",
|
||||
mcp.Required(),
|
||||
mcp.Description("Context or description of what help is needed"),
|
||||
),
|
||||
mcp.WithString("error",
|
||||
mcp.Description("Optional error message or details"),
|
||||
),
|
||||
)
|
||||
mcp.AddTool(server, &mcp.Tool{
|
||||
Name: "ask-for-help",
|
||||
Description: "Send a help request notification to the user via Gotify",
|
||||
}, askForHelp)
|
||||
|
||||
notifyCompletionTool := mcp.NewTool("notify-completion",
|
||||
mcp.WithDescription("Send a completion notification to the user via Gotify"),
|
||||
mcp.WithString("task",
|
||||
mcp.Required(),
|
||||
mcp.Description("Description of the completed task"),
|
||||
),
|
||||
mcp.WithString("result",
|
||||
mcp.Description("Optional result or outcome details"),
|
||||
),
|
||||
)
|
||||
mcp.AddTool(server, &mcp.Tool{
|
||||
Name: "notify-completion",
|
||||
Description: "Send a completion notification to the user via Gotify",
|
||||
}, notifyCompletion)
|
||||
|
||||
summarizeTool := mcp.NewTool("summarize-activity",
|
||||
mcp.WithDescription("Send a summary of current activities or status to the user via Gotify"),
|
||||
mcp.WithString("summary",
|
||||
mcp.Required(),
|
||||
mcp.Description("Summary of activities or current status"),
|
||||
),
|
||||
mcp.WithString("details",
|
||||
mcp.Description("Optional additional details"),
|
||||
),
|
||||
)
|
||||
mcp.AddTool(server, &mcp.Tool{
|
||||
Name: "summarize-activity",
|
||||
Description: "Send a summary of current activities or status to the user via Gotify",
|
||||
}, summarizeActivity)
|
||||
|
||||
s.AddTool(sendMessageTool, sendMessage)
|
||||
s.AddTool(askForHelpTool, askForHelp)
|
||||
s.AddTool(notifyCompletionTool, notifyCompletion)
|
||||
s.AddTool(summarizeTool, summarizeActivity)
|
||||
|
||||
if err := server.ServeStdio(s); err != nil {
|
||||
fmt.Printf("Server error: %v\n", err)
|
||||
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
|
||||
log.Printf("Server error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,49 +100,38 @@ func sendGotifyMessage(message GotifyMessage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendMessage(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
message, err := request.RequireString("message")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
func sendMessage(ctx context.Context, req *mcp.CallToolRequest, args SendMessageArgs) (*mcp.CallToolResult, any, error) {
|
||||
priority := 5
|
||||
if args.Priority > 0 {
|
||||
priority = int(args.Priority)
|
||||
}
|
||||
|
||||
args, ok := request.Params.Arguments.(map[string]any)
|
||||
if !ok {
|
||||
return mcp.NewToolResultError("invalid arguments type"), nil
|
||||
}
|
||||
|
||||
title := getStringArg(args, "title", "")
|
||||
priority := getNumberArg(args, "priority", 5)
|
||||
|
||||
gotifyMsg := GotifyMessage{
|
||||
Message: message,
|
||||
Title: title,
|
||||
Priority: int(priority),
|
||||
Message: args.Message,
|
||||
Title: args.Title,
|
||||
Priority: priority,
|
||||
}
|
||||
|
||||
if err := sendGotifyMessage(gotifyMsg); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to send message: %s", err)), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: fmt.Sprintf("Failed to send message: %s", err)},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Message sent successfully"), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Message sent successfully"},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func askForHelp(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
contextStr, err := request.RequireString("context")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
|
||||
args, ok := request.Params.Arguments.(map[string]any)
|
||||
if !ok {
|
||||
return mcp.NewToolResultError("invalid arguments type"), nil
|
||||
}
|
||||
|
||||
errorMsg := getStringArg(args, "error", "")
|
||||
|
||||
message := fmt.Sprintf("🆘 Help needed: %s", contextStr)
|
||||
if errorMsg != "" {
|
||||
message += fmt.Sprintf("\nError: %s", errorMsg)
|
||||
func askForHelp(ctx context.Context, req *mcp.CallToolRequest, args AskForHelpArgs) (*mcp.CallToolResult, any, error) {
|
||||
message := fmt.Sprintf("🆘 Help needed: %s", args.Context)
|
||||
if args.Error != "" {
|
||||
message += fmt.Sprintf("\nError: %s", args.Error)
|
||||
}
|
||||
|
||||
gotifyMsg := GotifyMessage{
|
||||
@@ -178,28 +141,25 @@ func askForHelp(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallTool
|
||||
}
|
||||
|
||||
if err := sendGotifyMessage(gotifyMsg); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to send help request: %s", err)), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: fmt.Sprintf("Failed to send help request: %s", err)},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Help request sent successfully"), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Help request sent successfully"},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func notifyCompletion(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
task, err := request.RequireString("task")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
|
||||
args, ok := request.Params.Arguments.(map[string]any)
|
||||
if !ok {
|
||||
return mcp.NewToolResultError("invalid arguments type"), nil
|
||||
}
|
||||
|
||||
result := getStringArg(args, "result", "")
|
||||
|
||||
message := fmt.Sprintf("✅ Task completed: %s", task)
|
||||
if result != "" {
|
||||
message += fmt.Sprintf("\nResult: %s", result)
|
||||
func notifyCompletion(ctx context.Context, req *mcp.CallToolRequest, args NotifyCompletionArgs) (*mcp.CallToolResult, any, error) {
|
||||
message := fmt.Sprintf("✅ Task completed: %s", args.Task)
|
||||
if args.Result != "" {
|
||||
message += fmt.Sprintf("\nResult: %s", args.Result)
|
||||
}
|
||||
|
||||
gotifyMsg := GotifyMessage{
|
||||
@@ -209,28 +169,25 @@ func notifyCompletion(ctx context.Context, request mcp.CallToolRequest) (*mcp.Ca
|
||||
}
|
||||
|
||||
if err := sendGotifyMessage(gotifyMsg); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to send completion notification: %s", err)), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: fmt.Sprintf("Failed to send completion notification: %s", err)},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Completion notification sent successfully"), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Completion notification sent successfully"},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func summarizeActivity(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
summary, err := request.RequireString("summary")
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
|
||||
args, ok := request.Params.Arguments.(map[string]any)
|
||||
if !ok {
|
||||
return mcp.NewToolResultError("invalid arguments type"), nil
|
||||
}
|
||||
|
||||
details := getStringArg(args, "details", "")
|
||||
|
||||
message := fmt.Sprintf("📊 Activity Summary: %s", summary)
|
||||
if details != "" {
|
||||
message += fmt.Sprintf("\nDetails: %s", details)
|
||||
func summarizeActivity(ctx context.Context, req *mcp.CallToolRequest, args SummarizeActivityArgs) (*mcp.CallToolResult, any, error) {
|
||||
message := fmt.Sprintf("📊 Activity Summary: %s", args.Summary)
|
||||
if args.Details != "" {
|
||||
message += fmt.Sprintf("\nDetails: %s", args.Details)
|
||||
}
|
||||
|
||||
gotifyMsg := GotifyMessage{
|
||||
@@ -240,9 +197,17 @@ func summarizeActivity(ctx context.Context, request mcp.CallToolRequest) (*mcp.C
|
||||
}
|
||||
|
||||
if err := sendGotifyMessage(gotifyMsg); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to send summary: %s", err)), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: fmt.Sprintf("Failed to send summary: %s", err)},
|
||||
},
|
||||
IsError: true,
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
return mcp.NewToolResultText("Activity summary sent successfully"), nil
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Activity summary sent successfully"},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user