@@ -15,28 +15,25 @@ import (
15
15
"github.com/mark3labs/mcp-go/server"
16
16
)
17
17
18
- // getNotifications creates a tool to list notifications for the current user.
19
- func GetNotifications (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
20
- return mcp .NewTool ("get_notifications" ,
21
- mcp .WithDescription (t ("TOOL_GET_NOTIFICATIONS_DESCRIPTION" , "Get notifications for the authenticated GitHub user" )),
22
- mcp .WithBoolean ("all" ,
23
- mcp .Description ("If true, show notifications marked as read. Default: false" ),
24
- ),
25
- mcp .WithBoolean ("participating" ,
26
- mcp .Description ("If true, only shows notifications in which the user is directly participating or mentioned. Default: false" ),
18
+ // ListNotifications creates a tool to list notifications for the current user.
19
+ func ListNotifications (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
20
+ return mcp .NewTool ("list_notifications" ,
21
+ mcp .WithDescription (t ("TOOL_LIST_NOTIFICATIONS_DESCRIPTION" , "List current notifications for the authenticated GitHub user" )),
22
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
23
+ Title : t ("TOOL_LIST_NOTIFICATIONS_USER_TITLE" , "List notifications" ),
24
+ ReadOnlyHint : toBoolPtr (true ),
25
+ }),
26
+ mcp .WithString ("filter" ,
27
+ mcp .Description ("Filter notifications to, use default unless specified. Read notifications are ones that have already been acknowledged by the user. Participating notifications are those that the user is directly involved in, such as issues or pull requests they have commented on or created." ),
28
+ mcp .Enum ("default" , "include_read_notifications" , "only_participating" ),
27
29
),
28
30
mcp .WithString ("since" ,
29
31
mcp .Description ("Only show notifications updated after the given time (ISO 8601 format)" ),
30
32
),
31
33
mcp .WithString ("before" ,
32
34
mcp .Description ("Only show notifications updated before the given time (ISO 8601 format)" ),
33
35
),
34
- mcp .WithNumber ("per_page" ,
35
- mcp .Description ("Results per page (max 100). Default: 30" ),
36
- ),
37
- mcp .WithNumber ("page" ,
38
- mcp .Description ("Page number of the results to fetch. Default: 1" ),
39
- ),
36
+ WithPagination (),
40
37
),
41
38
func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
42
39
client , err := getClient (ctx )
@@ -65,6 +62,7 @@ func GetNotifications(getClient GetClientFn, t translations.TranslationHelperFun
65
62
return mcp .NewToolResultError (err .Error ()), nil
66
63
}
67
64
65
+ // TODO pagination params from tool
68
66
perPage , err := OptionalIntParamWithDefault (request , "per_page" , 30 )
69
67
if err != nil {
70
68
return mcp .NewToolResultError (err .Error ()), nil
@@ -127,14 +125,19 @@ func GetNotifications(getClient GetClientFn, t translations.TranslationHelperFun
127
125
}
128
126
}
129
127
130
- // markNotificationRead creates a tool to mark a notification as read.
131
- func MarkNotificationRead (getclient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
132
- return mcp .NewTool ("mark_notification_read" ,
133
- mcp .WithDescription (t ("TOOL_MARK_NOTIFICATION_READ_DESCRIPTION" , "Mark a notification as read" )),
128
+ // dismiss notification creates a tool to mark a notification as read/done.
129
+ func DismissNotification (getclient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
130
+ return mcp .NewTool ("dismiss_notification" ,
131
+ mcp .WithDescription (t ("TOOL_DISMISS_NOTIFICATION_DESCRIPTION" , "Dismiss a notification by marking it as read or done" )),
132
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
133
+ Title : t ("TOOL_DISMISS_NOTIFICATION_USER_TITLE" , "Dismiss notification" ),
134
+ ReadOnlyHint : toBoolPtr (false ),
135
+ }),
134
136
mcp .WithString ("threadID" ,
135
137
mcp .Required (),
136
138
mcp .Description ("The ID of the notification thread" ),
137
139
),
140
+ mcp .WithString ("state" , mcp .Description ("The new state of the notification (read/done)" ), mcp .Enum ("read" , "done" )),
138
141
),
139
142
func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
140
143
client , err := getclient (ctx )
@@ -147,9 +150,27 @@ func MarkNotificationRead(getclient GetClientFn, t translations.TranslationHelpe
147
150
return mcp .NewToolResultError (err .Error ()), nil
148
151
}
149
152
150
- resp , err := client .Activity .MarkThreadRead (ctx , threadID )
153
+ state , err := requiredParam [string ](request , "state" )
154
+ if err != nil {
155
+ return mcp .NewToolResultError (err .Error ()), nil
156
+ }
157
+
158
+ var resp * github.Response
159
+
160
+ if state == "done" {
161
+ // for some inexplicable reason, the API seems to have threadID as int64 and string depending on the endpoint
162
+ var threadIDInt int64
163
+ threadIDInt , err = strconv .ParseInt (threadID , 10 , 64 )
164
+ if err != nil {
165
+ return mcp .NewToolResultError (fmt .Sprintf ("invalid threadID format: %v" , err )), nil
166
+ }
167
+ resp , err = client .Activity .MarkThreadDone (ctx , threadIDInt )
168
+ } else {
169
+ resp , err = client .Activity .MarkThreadRead (ctx , threadID )
170
+ }
171
+
151
172
if err != nil {
152
- return nil , fmt .Errorf ("failed to mark notification as read : %w" , err )
173
+ return nil , fmt .Errorf ("failed to mark notification as %s : %w" , state , err )
153
174
}
154
175
defer func () { _ = resp .Body .Close () }()
155
176
@@ -158,17 +179,21 @@ func MarkNotificationRead(getclient GetClientFn, t translations.TranslationHelpe
158
179
if err != nil {
159
180
return nil , fmt .Errorf ("failed to read response body: %w" , err )
160
181
}
161
- return mcp .NewToolResultError (fmt .Sprintf ("failed to mark notification as read : %s" , string (body ))), nil
182
+ return mcp .NewToolResultError (fmt .Sprintf ("failed to mark notification as %s : %s" , state , string (body ))), nil
162
183
}
163
184
164
- return mcp .NewToolResultText ("Notification marked as read" ), nil
185
+ return mcp .NewToolResultText (fmt . Sprintf ( "Notification marked as %s" , state ) ), nil
165
186
}
166
187
}
167
188
168
189
// MarkAllNotificationsRead creates a tool to mark all notifications as read.
169
190
func MarkAllNotificationsRead (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
170
191
return mcp .NewTool ("mark_all_notifications_read" ,
171
192
mcp .WithDescription (t ("TOOL_MARK_ALL_NOTIFICATIONS_READ_DESCRIPTION" , "Mark all notifications as read" )),
193
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
194
+ Title : t ("TOOL_MARK_ALL_NOTIFICATIONS_READ_USER_TITLE" , "Mark all notifications as read" ),
195
+ ReadOnlyHint : toBoolPtr (false ),
196
+ }),
172
197
mcp .WithString ("lastReadAt" ,
173
198
mcp .Description ("Describes the last point that notifications were checked (optional). Default: Now" ),
174
199
),
@@ -179,7 +204,7 @@ func MarkAllNotificationsRead(getClient GetClientFn, t translations.TranslationH
179
204
return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
180
205
}
181
206
182
- lastReadAt , err := OptionalParam (request , "lastReadAt" )
207
+ lastReadAt , err := OptionalParam [ string ] (request , "lastReadAt" )
183
208
if err != nil {
184
209
return mcp .NewToolResultError (err .Error ()), nil
185
210
}
@@ -217,6 +242,10 @@ func MarkAllNotificationsRead(getClient GetClientFn, t translations.TranslationH
217
242
func GetNotificationThread (getClient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
218
243
return mcp .NewTool ("get_notification_thread" ,
219
244
mcp .WithDescription (t ("TOOL_GET_NOTIFICATION_THREAD_DESCRIPTION" , "Get a specific notification thread" )),
245
+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
246
+ Title : t ("TOOL_GET_NOTIFICATION_THREAD_USER_TITLE" , "Get notification thread" ),
247
+ ReadOnlyHint : toBoolPtr (true ),
248
+ }),
220
249
mcp .WithString ("threadID" ,
221
250
mcp .Required (),
222
251
mcp .Description ("The ID of the notification thread" ),
@@ -255,46 +284,3 @@ func GetNotificationThread(getClient GetClientFn, t translations.TranslationHelp
255
284
return mcp .NewToolResultText (string (r )), nil
256
285
}
257
286
}
258
-
259
- // markNotificationDone creates a tool to mark a notification as done.
260
- func MarkNotificationDone (getclient GetClientFn , t translations.TranslationHelperFunc ) (tool mcp.Tool , handler server.ToolHandlerFunc ) {
261
- return mcp .NewTool ("mark_notification_done" ,
262
- mcp .WithDescription (t ("TOOL_MARK_NOTIFICATION_DONE_DESCRIPTION" , "Mark a notification as done" )),
263
- mcp .WithString ("threadID" ,
264
- mcp .Required (),
265
- mcp .Description ("The ID of the notification thread" ),
266
- ),
267
- ),
268
- func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
269
- client , err := getclient (ctx )
270
- if err != nil {
271
- return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
272
- }
273
-
274
- threadIDStr , err := requiredParam [string ](request , "threadID" )
275
- if err != nil {
276
- return mcp .NewToolResultError (err .Error ()), nil
277
- }
278
-
279
- threadID , err := strconv .ParseInt (threadIDStr , 10 , 64 )
280
- if err != nil {
281
- return mcp .NewToolResultError ("Invalid threadID: must be a numeric value" ), nil
282
- }
283
-
284
- resp , err := client .Activity .MarkThreadDone (ctx , threadID )
285
- if err != nil {
286
- return nil , fmt .Errorf ("failed to mark notification as done: %w" , err )
287
- }
288
- defer func () { _ = resp .Body .Close () }()
289
-
290
- if resp .StatusCode != http .StatusResetContent && resp .StatusCode != http .StatusOK {
291
- body , err := io .ReadAll (resp .Body )
292
- if err != nil {
293
- return nil , fmt .Errorf ("failed to read response body: %w" , err )
294
- }
295
- return mcp .NewToolResultError (fmt .Sprintf ("failed to mark notification as done: %s" , string (body ))), nil
296
- }
297
-
298
- return mcp .NewToolResultText ("Notification marked as done" ), nil
299
- }
300
- }
0 commit comments