@@ -17,31 +17,25 @@ import (
1717)
1818
1919type ReactionResponse struct {
20- Channel string `json:"channel"`
21- Timestamp string `json:"timestamp"`
22- Emoji string `json:"emoji"`
23- Success bool `json:"success"`
24- Message string `json:"message"`
25- }
26-
27- type ReactionDetail struct {
28- Name string `json:"name"`
29- Count int `json:"count"`
30- Users []string `json:"users"`
20+ Channel string `csv:"channel"`
21+ Timestamp string `csv:"timestamp"`
22+ Emoji string `csv:"emoji"`
23+ Success bool `csv:"success"`
24+ Message string `csv:"message"`
3125}
3226
3327type MessageReactions struct {
34- Channel string `json :"channel"`
35- Timestamp string `json :"timestamp"`
36- Reactions [] ReactionDetail `json :"reactions"`
28+ Channel string `csv :"channel"`
29+ Timestamp string `csv :"timestamp"`
30+ Reactions string `csv :"reactions"`
3731}
3832
3933type UserReaction struct {
40- Channel string `json :"channel"`
41- Timestamp string `json :"timestamp"`
42- Emoji string `json :"emoji"`
43- Type string `json :"type"` // "message" or "file"
44- Cursor string `json :"cursor"`
34+ Channel string `csv :"channel"`
35+ Timestamp string `csv :"timestamp"`
36+ Emoji string `csv :"emoji"`
37+ Type string `csv :"type"`
38+ Cursor string `csv :"cursor"`
4539}
4640
4741type addReactionParams struct {
@@ -79,17 +73,14 @@ func NewReactionsHandler(apiProvider *provider.ApiProvider, logger *zap.Logger)
7973 }
8074}
8175
82- // ReactionsAddHandler adds an emoji reaction to a message
8376func (rh * ReactionsHandler ) ReactionsAddHandler (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
8477 rh .logger .Debug ("ReactionsAddHandler called" , zap .Any ("params" , request .Params ))
8578
86- // Authentication
8779 if authenticated , err := auth .IsAuthenticated (ctx , rh .apiProvider .ServerTransport (), rh .logger ); ! authenticated {
8880 rh .logger .Error ("Authentication failed for reactions add" , zap .Error (err ))
8981 return nil , err
9082 }
9183
92- // Provider readiness
9384 if ready , err := rh .apiProvider .IsReady (); ! ready {
9485 rh .logger .Error ("API provider not ready" , zap .Error (err ))
9586 return nil , err
@@ -101,7 +92,6 @@ func (rh *ReactionsHandler) ReactionsAddHandler(ctx context.Context, request mcp
10192 return nil , err
10293 }
10394
104- // Add the reaction
10595 err = rh .apiProvider .Slack ().AddReactionContext (ctx , params .emoji , slack.ItemRef {
10696 Channel : params .channel ,
10797 Timestamp : params .timestamp ,
@@ -129,17 +119,14 @@ func (rh *ReactionsHandler) ReactionsAddHandler(ctx context.Context, request mcp
129119 return marshalReactionResponseToCSV ([]ReactionResponse {response })
130120}
131121
132- // ReactionsRemoveHandler removes an emoji reaction from a message
133122func (rh * ReactionsHandler ) ReactionsRemoveHandler (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
134123 rh .logger .Debug ("ReactionsRemoveHandler called" , zap .Any ("params" , request .Params ))
135124
136- // Authentication
137125 if authenticated , err := auth .IsAuthenticated (ctx , rh .apiProvider .ServerTransport (), rh .logger ); ! authenticated {
138126 rh .logger .Error ("Authentication failed for reactions remove" , zap .Error (err ))
139127 return nil , err
140128 }
141129
142- // Provider readiness
143130 if ready , err := rh .apiProvider .IsReady (); ! ready {
144131 rh .logger .Error ("API provider not ready" , zap .Error (err ))
145132 return nil , err
@@ -151,7 +138,6 @@ func (rh *ReactionsHandler) ReactionsRemoveHandler(ctx context.Context, request
151138 return nil , err
152139 }
153140
154- // Remove the reaction
155141 err = rh .apiProvider .Slack ().RemoveReactionContext (ctx , params .emoji , slack.ItemRef {
156142 Channel : params .channel ,
157143 Timestamp : params .timestamp ,
@@ -179,17 +165,14 @@ func (rh *ReactionsHandler) ReactionsRemoveHandler(ctx context.Context, request
179165 return marshalReactionResponseToCSV ([]ReactionResponse {response })
180166}
181167
182- // ReactionsGetHandler gets all reactions for a specific message
183168func (rh * ReactionsHandler ) ReactionsGetHandler (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
184169 rh .logger .Debug ("ReactionsGetHandler called" , zap .Any ("params" , request .Params ))
185170
186- // Authentication
187171 if authenticated , err := auth .IsAuthenticated (ctx , rh .apiProvider .ServerTransport (), rh .logger ); ! authenticated {
188172 rh .logger .Error ("Authentication failed for reactions get" , zap .Error (err ))
189173 return nil , err
190174 }
191175
192- // Provider readiness
193176 if ready , err := rh .apiProvider .IsReady (); ! ready {
194177 rh .logger .Error ("API provider not ready" , zap .Error (err ))
195178 return nil , err
@@ -201,7 +184,6 @@ func (rh *ReactionsHandler) ReactionsGetHandler(ctx context.Context, request mcp
201184 return nil , err
202185 }
203186
204- // Get reactions
205187 reactions , err := rh .apiProvider .Slack ().GetReactionsContext (ctx , slack.ItemRef {
206188 Channel : params .channel ,
207189 Timestamp : params .timestamp ,
@@ -212,36 +194,28 @@ func (rh *ReactionsHandler) ReactionsGetHandler(ctx context.Context, request mcp
212194 return nil , err
213195 }
214196
215- // Convert to our format
216- var reactionDetails []ReactionDetail
197+ var reactionStrings []string
217198 for _ , r := range reactions {
218- reactionDetails = append (reactionDetails , ReactionDetail {
219- Name : r .Name ,
220- Count : r .Count ,
221- Users : r .Users ,
222- })
199+ reactionStrings = append (reactionStrings , fmt .Sprintf ("%s:%d" , r .Name , r .Count ))
223200 }
224201
225202 messageReactions := MessageReactions {
226203 Channel : params .channel ,
227204 Timestamp : params .timestamp ,
228- Reactions : reactionDetails ,
205+ Reactions : strings . Join ( reactionStrings , "|" ) ,
229206 }
230207
231208 return marshalMessageReactionsToCSV ([]MessageReactions {messageReactions })
232209}
233210
234- // ReactionsListHandler lists all reactions made by a specific user
235211func (rh * ReactionsHandler ) ReactionsListHandler (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
236212 rh .logger .Debug ("ReactionsListHandler called" , zap .Any ("params" , request .Params ))
237213
238- // Authentication
239214 if authenticated , err := auth .IsAuthenticated (ctx , rh .apiProvider .ServerTransport (), rh .logger ); ! authenticated {
240215 rh .logger .Error ("Authentication failed for reactions list" , zap .Error (err ))
241216 return nil , err
242217 }
243218
244- // Provider readiness
245219 if ready , err := rh .apiProvider .IsReady (); ! ready {
246220 rh .logger .Error ("API provider not ready" , zap .Error (err ))
247221 return nil , err
@@ -253,15 +227,13 @@ func (rh *ReactionsHandler) ReactionsListHandler(ctx context.Context, request mc
253227 return nil , err
254228 }
255229
256- // List reactions
257230 listParams := slack.ListReactionsParameters {
258231 User : params .user ,
259232 Count : params .limit ,
260- Page : 1 , // We'll use cursor for pagination if needed
233+ Page : 1 ,
261234 }
262235
263236 if params .cursor != "" {
264- // Parse cursor to get page number
265237 if page , err := strconv .Atoi (params .cursor ); err == nil && page > 0 {
266238 listParams .Page = page
267239 }
@@ -273,7 +245,6 @@ func (rh *ReactionsHandler) ReactionsListHandler(ctx context.Context, request mc
273245 return nil , err
274246 }
275247
276- // Convert to our format
277248 var userReactions []UserReaction
278249 for _ , item := range reactions {
279250 itemType := "message"
@@ -282,7 +253,6 @@ func (rh *ReactionsHandler) ReactionsListHandler(ctx context.Context, request mc
282253 }
283254
284255 for _ , reaction := range item .Reactions {
285- // Check if this user reacted
286256 for _ , user := range reaction .Users {
287257 if user == params .user {
288258 userReactions = append (userReactions , UserReaction {
@@ -297,7 +267,6 @@ func (rh *ReactionsHandler) ReactionsListHandler(ctx context.Context, request mc
297267 }
298268 }
299269
300- // Add cursor for pagination
301270 if len (userReactions ) > 0 && paging .Page < paging .Pages {
302271 userReactions [len (userReactions )- 1 ].Cursor = strconv .Itoa (paging .Page + 1 )
303272 }
@@ -337,7 +306,6 @@ func (rh *ReactionsHandler) parseReactionParams(request mcp.CallToolRequest) (*a
337306 return nil , errors .New ("emoji must be a string" )
338307 }
339308
340- // Resolve channel name to ID if needed
341309 if strings .HasPrefix (channel , "#" ) || strings .HasPrefix (channel , "@" ) {
342310 if ready , err := rh .apiProvider .IsReady (); ! ready {
343311 rh .logger .Warn ("Provider not ready for channel resolution" , zap .Error (err ))
@@ -351,12 +319,10 @@ func (rh *ReactionsHandler) parseReactionParams(request mcp.CallToolRequest) (*a
351319 channel = channelsMaps .Channels [chn ].ID
352320 }
353321
354- // Validate timestamp format
355322 if ! strings .Contains (timestamp , "." ) {
356323 return nil , errors .New ("timestamp must be in format 1234567890.123456" )
357324 }
358325
359- // Clean emoji name (remove colons if present)
360326 emoji = strings .Trim (emoji , ":" )
361327
362328 return & addReactionParams {
@@ -377,7 +343,6 @@ func (rh *ReactionsHandler) parseGetReactionsParams(request mcp.CallToolRequest)
377343 return nil , errors .New ("timestamp must be a string" )
378344 }
379345
380- // Resolve channel name to ID if needed
381346 if strings .HasPrefix (channel , "#" ) || strings .HasPrefix (channel , "@" ) {
382347 if ready , err := rh .apiProvider .IsReady (); ! ready {
383348 rh .logger .Warn ("Provider not ready for channel resolution" , zap .Error (err ))
@@ -391,7 +356,6 @@ func (rh *ReactionsHandler) parseGetReactionsParams(request mcp.CallToolRequest)
391356 channel = channelsMaps .Channels [chn ].ID
392357 }
393358
394- // Validate timestamp format
395359 if ! strings .Contains (timestamp , "." ) {
396360 return nil , errors .New ("timestamp must be in format 1234567890.123456" )
397361 }
@@ -415,7 +379,6 @@ func (rh *ReactionsHandler) parseListReactionsParams(request mcp.CallToolRequest
415379
416380 cursor := request .GetString ("cursor" , "" )
417381
418- // Resolve user name to ID if needed
419382 if strings .HasPrefix (user , "@" ) {
420383 if ready , err := rh .apiProvider .IsReady (); ! ready {
421384 rh .logger .Warn ("Provider not ready for user resolution" , zap .Error (err ))
@@ -436,7 +399,6 @@ func (rh *ReactionsHandler) parseListReactionsParams(request mcp.CallToolRequest
436399 }, nil
437400}
438401
439- // Check if reactions tool is enabled for channel
440402func isReactionsToolEnabled (channel string ) bool {
441403 config := os .Getenv ("SLACK_MCP_REACTIONS_TOOL" )
442404 if config == "" || config == "true" || config == "1" {
0 commit comments