@@ -14,6 +14,7 @@ import (
1414 "github.com/rusq/slackdump/v3/auth"
1515 "github.com/slack-go/slack"
1616 "go.uber.org/zap"
17+ "golang.org/x/time/rate"
1718)
1819
1920const usersNotReadyMsg = "users cache is not ready yet, sync process is still running... please wait"
@@ -77,6 +78,7 @@ type MCPSlackClient struct {
7778 authProvider auth.Provider
7879
7980 isEnterprise bool
81+ isOAuth bool
8082 teamEndpoint string
8183}
8284
@@ -85,6 +87,8 @@ type ApiProvider struct {
8587 client SlackAPI
8688 logger * zap.Logger
8789
90+ rateLimiter * rate.Limiter
91+
8892 users map [string ]slack.User
8993 usersInv map [string ]string
9094 usersCache string
@@ -138,6 +142,7 @@ func NewMCPSlackClient(authProvider auth.Provider, logger *zap.Logger) (*MCPSlac
138142 authResponse : authResponse ,
139143 authProvider : authProvider ,
140144 isEnterprise : isEnterprise ,
145+ isOAuth : strings .HasPrefix (authProvider .SlackToken (), "xoxp-" ),
141146 teamEndpoint : authResp .URL ,
142147 }, nil
143148}
@@ -179,49 +184,57 @@ func (c *MCPSlackClient) MarkConversationContext(ctx context.Context, channel, t
179184}
180185
181186func (c * MCPSlackClient ) GetConversationsContext (ctx context.Context , params * slack.GetConversationsParameters ) ([]slack.Channel , string , error ) {
187+ // Please see https://github.com/korotovsky/slack-mcp-server/issues/73
188+ // It seems that `conversations.list` works with `xoxp` tokens within Enterprise Grid setups
189+ // and if `xoxc`/`xoxd` defined we fallback to edge client.
190+ // In non Enterprise Grid setups we always use `conversations.list` api as it accepts both token types wtf.
182191 if c .isEnterprise {
183- edgeChannels , _ , err := c .edgeClient .GetConversationsContext (ctx , nil )
184- if err != nil {
185- return nil , "" , err
186- }
187-
188- var channels []slack.Channel
189- for _ , ec := range edgeChannels {
190- if params != nil && params .ExcludeArchived && ec .IsArchived {
191- continue
192+ if c .isOAuth {
193+ return c .slackClient .GetConversationsContext (ctx , params )
194+ } else {
195+ edgeChannels , _ , err := c .edgeClient .GetConversationsContext (ctx , nil )
196+ if err != nil {
197+ return nil , "" , err
192198 }
193199
194- channels = append (channels , slack.Channel {
195- IsGeneral : ec .IsGeneral ,
196- GroupConversation : slack.GroupConversation {
197- Conversation : slack.Conversation {
198- ID : ec .ID ,
199- IsIM : ec .IsIM ,
200- IsMpIM : ec .IsMpIM ,
201- IsPrivate : ec .IsPrivate ,
202- Created : slack .JSONTime (ec .Created .Time ().UnixMilli ()),
203- Unlinked : ec .Unlinked ,
204- NameNormalized : ec .NameNormalized ,
205- IsShared : ec .IsShared ,
206- IsExtShared : ec .IsExtShared ,
207- IsOrgShared : ec .IsOrgShared ,
208- IsPendingExtShared : ec .IsPendingExtShared ,
209- NumMembers : ec .NumMembers ,
210- },
211- Name : ec .Name ,
212- IsArchived : ec .IsArchived ,
213- Members : ec .Members ,
214- Topic : slack.Topic {
215- Value : ec .Topic .Value ,
216- },
217- Purpose : slack.Purpose {
218- Value : ec .Purpose .Value ,
200+ var channels []slack.Channel
201+ for _ , ec := range edgeChannels {
202+ if params != nil && params .ExcludeArchived && ec .IsArchived {
203+ continue
204+ }
205+
206+ channels = append (channels , slack.Channel {
207+ IsGeneral : ec .IsGeneral ,
208+ GroupConversation : slack.GroupConversation {
209+ Conversation : slack.Conversation {
210+ ID : ec .ID ,
211+ IsIM : ec .IsIM ,
212+ IsMpIM : ec .IsMpIM ,
213+ IsPrivate : ec .IsPrivate ,
214+ Created : slack .JSONTime (ec .Created .Time ().UnixMilli ()),
215+ Unlinked : ec .Unlinked ,
216+ NameNormalized : ec .NameNormalized ,
217+ IsShared : ec .IsShared ,
218+ IsExtShared : ec .IsExtShared ,
219+ IsOrgShared : ec .IsOrgShared ,
220+ IsPendingExtShared : ec .IsPendingExtShared ,
221+ NumMembers : ec .NumMembers ,
222+ },
223+ Name : ec .Name ,
224+ IsArchived : ec .IsArchived ,
225+ Members : ec .Members ,
226+ Topic : slack.Topic {
227+ Value : ec .Topic .Value ,
228+ },
229+ Purpose : slack.Purpose {
230+ Value : ec .Purpose .Value ,
231+ },
219232 },
220- },
221- })
222- }
233+ })
234+ }
223235
224- return channels , "" , nil
236+ return channels , "" , nil
237+ }
225238 }
226239
227240 return c .slackClient .GetConversationsContext (ctx , params )
@@ -331,6 +344,8 @@ func newWithXOXP(transport string, authProvider auth.ValueAuth, logger *zap.Logg
331344 client : client ,
332345 logger : logger ,
333346
347+ rateLimiter : limiter .Tier2 .Limiter (),
348+
334349 users : make (map [string ]slack.User ),
335350 usersInv : map [string ]string {},
336351 usersCache : usersCache ,
@@ -371,6 +386,8 @@ func newWithXOXC(transport string, authProvider auth.ValueAuth, logger *zap.Logg
371386 client : client ,
372387 logger : logger ,
373388
389+ rateLimiter : limiter .Tier2 .Limiter (),
390+
374391 users : make (map [string ]slack.User ),
375392 usersInv : map [string ]string {},
376393 usersCache : usersCache ,
@@ -551,8 +568,12 @@ func (ap *ApiProvider) GetChannels(ctx context.Context, channelTypes []string) [
551568 err error
552569 )
553570
554- lim := limiter .Tier2boost .Limiter ()
555571 for {
572+ if err := ap .rateLimiter .Wait (ctx ); err != nil {
573+ ap .logger .Error ("Rate limiter wait failed" , zap .Error (err ))
574+ return nil
575+ }
576+
556577 channels , nextcur , err = ap .client .GetConversationsContext (ctx , params )
557578 if err != nil {
558579 ap .logger .Error ("Failed to fetch channels" , zap .Error (err ))
@@ -578,10 +599,6 @@ func (ap *ApiProvider) GetChannels(ctx context.Context, channelTypes []string) [
578599 chans = append (chans , ch )
579600 }
580601
581- if err := lim .Wait (ctx ); err != nil {
582- return nil
583- }
584-
585602 for _ , ch := range chans {
586603 ap .channels [ch .ID ] = ch
587604 ap .channelsInv [ch .Name ] = ch .ID
0 commit comments