@nrjdalal/slack-mcp-server 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server-BxCuWiEW.mjs +1 -0
- package/package.json +1 -1
- package/dist/server-D7nrZd31.mjs +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{t as e}from"./server-
|
|
2
|
+
import{t as e}from"./server-BxCuWiEW.mjs";import{StdioServerTransport as t}from"@modelcontextprotocol/sdk/server/stdio.js";const n=`SLACK_MCP_ALLOW_WRITE`,r=new Set([`true`,`1`]),i=new Set([``,`false`,`0`]),a=e=>e[n]?.trim().toLowerCase(),o=(e=process.env)=>r.has(a(e)??``),s=(e=process.env)=>{let t=a(e);if(!(t===void 0||r.has(t)||i.has(t)))return`${n}="${e[n]}" is not recognized; writes stay disabled (use "true" to enable).`};(async()=>{let n=s();n&&console.error(`slack-mcp-server: ${n}`);let r=o();await e({allowWrite:r}).connect(new t),console.error(`slack-mcp-server: listening on stdio (${r?`read+write`:`read-only`})`)})().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./server-
|
|
1
|
+
import{t as e}from"./server-BxCuWiEW.mjs";export{e as createServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{McpServer as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{WebClient as t}from"@slack/web-api";import{createHash as n}from"node:crypto";import{existsSync as r,mkdirSync as i,readFileSync as a,writeFileSync as o}from"node:fs";import{homedir as ee}from"node:os";import{join as s}from"node:path";import{z as c}from"zod";var l={"api.test":`Tier 4`,"apps.activities.list":`Tier 3`,"apps.auth.external.delete":`Tier 4`,"apps.auth.external.get":`Tier 3`,"apps.connections.open":`Tier 3`,"apps.datastore.bulkDelete":`Tier 3`,"apps.datastore.bulkGet":`Tier 3`,"apps.datastore.bulkPut":`Tier 3`,"apps.datastore.count":`Tier 3`,"apps.datastore.delete":`Tier 4`,"apps.datastore.get":`Tier 4`,"apps.datastore.put":`Tier 4`,"apps.datastore.query":`Tier 4`,"apps.datastore.update":`Tier 4`,"apps.event.authorizations.list":`Special`,"apps.icon.set":`Tier 1`,"apps.manifest.create":`Tier 1`,"apps.manifest.delete":`Tier 1`,"apps.manifest.export":`Tier 3`,"apps.manifest.update":`Tier 1`,"apps.manifest.validate":`Tier 3`,"apps.uninstall":`Tier 1`,"apps.user.connection.update":`Tier 2`,"assistant.search.context":`Special`,"assistant.search.info":`Tier 2`,"assistant.threads.setStatus":`Special`,"assistant.threads.setSuggestedPrompts":`Tier 4`,"assistant.threads.setTitle":`Tier 4`,"auth.revoke":`Tier 3`,"auth.teams.list":`Tier 2`,"auth.test":`Special`,"blocks.validate":`Special`,"bookmarks.add":`Tier 2`,"bookmarks.edit":`Tier 2`,"bookmarks.list":`Tier 3`,"bookmarks.remove":`Tier 2`,"bots.info":`Tier 3`,"calls.add":`Tier 3`,"calls.end":`Tier 3`,"calls.info":`Tier 3`,"calls.participants.add":`Tier 3`,"calls.participants.remove":`Tier 3`,"calls.update":`Tier 3`,"canvases.access.delete":`Tier 3`,"canvases.access.set":`Tier 3`,"canvases.create":`Tier 2`,"canvases.delete":`Tier 3`,"canvases.edit":`Tier 3`,"canvases.sections.lookup":`Tier 3`,"chat.appendStream":`Tier 4`,"chat.delete":`Tier 3`,"chat.deleteScheduledMessage":`Tier 3`,"chat.getPermalink":`Special`,"chat.meMessage":`Tier 3`,"chat.postEphemeral":`Tier 4`,"chat.postMessage":`Special`,"chat.scheduledMessages.list":`Tier 3`,"chat.scheduleMessage":`Tier 3`,"chat.startStream":`Tier 2`,"chat.stopStream":`Tier 2`,"chat.unfurl":`Tier 3`,"chat.update":`Tier 3`,"conversations.acceptSharedInvite":`Tier 2`,"conversations.approveSharedInvite":`Tier 3`,"conversations.archive":`Tier 2`,"conversations.canvases.create":`Tier 2`,"conversations.close":`Tier 2`,"conversations.create":`Tier 2`,"conversations.declineSharedInvite":`Tier 3`,"conversations.externalInvitePermissions.set":`Tier 2`,"conversations.history":`Tier 3`,"conversations.info":`Tier 3`,"conversations.invite":`Tier 3`,"conversations.inviteShared":`Tier 2`,"conversations.join":`Tier 3`,"conversations.kick":`Tier 3`,"conversations.leave":`Tier 3`,"conversations.list":`Tier 2`,"conversations.listConnectInvites":`Tier 1`,"conversations.mark":`Tier 3`,"conversations.members":`Tier 4`,"conversations.open":`Tier 3`,"conversations.rename":`Tier 2`,"conversations.replies":`Tier 3`,"conversations.requestSharedInvite.approve":`Tier 2`,"conversations.requestSharedInvite.deny":`Tier 2`,"conversations.requestSharedInvite.list":`Tier 2`,"conversations.setPurpose":`Tier 2`,"conversations.setTopic":`Tier 2`,"conversations.unarchive":`Tier 2`,"developer.apps.owners.add":`Tier 1`,"developer.apps.owners.list":`Tier 2`,"developer.apps.owners.remove":`Tier 1`,"dialog.open":`Tier 4`,"dnd.endDnd":`Tier 2`,"dnd.endSnooze":`Tier 2`,"dnd.info":`Tier 3`,"dnd.setSnooze":`Tier 2`,"dnd.teamInfo":`Tier 2`,"emoji.list":`Tier 2`,"entity.presentDetails":`Tier 3`,"files.comments.delete":`Tier 2`,"files.completeUploadExternal":`Tier 4`,"files.delete":`Tier 3`,"files.getUploadURLExternal":`Tier 4`,"files.info":`Tier 4`,"files.list":`Tier 3`,"files.remote.add":`Tier 2`,"files.remote.info":`Tier 2`,"files.remote.list":`Tier 2`,"files.remote.remove":`Tier 2`,"files.remote.share":`Tier 2`,"files.remote.update":`Tier 2`,"files.revokePublicURL":`Tier 3`,"files.sharedPublicURL":`Tier 3`,"files.upload":`Tier 2`,"functions.completeError":`Tier 3`,"functions.completeSuccess":`Tier 3`,"functions.distributions.permissions.add":`Tier 3`,"functions.distributions.permissions.list":`Tier 3`,"functions.distributions.permissions.remove":`Tier 3`,"functions.distributions.permissions.set":`Tier 3`,"functions.workflows.steps.list":`Tier 3`,"functions.workflows.steps.responses.export":`Tier 3`,"migration.exchange":`Tier 2`,"oauth.access":`Tier 4`,"oauth.v2.access":`Special`,"oauth.v2.exchange":`Tier 3`,"oauth.v2.user.access":`Special`,"openid.connect.token":`Tier 4`,"openid.connect.userInfo":`Tier 3`,"pins.add":`Tier 2`,"pins.list":`Tier 2`,"pins.remove":`Tier 2`,"reactions.add":`Tier 3`,"reactions.get":`Tier 3`,"reactions.list":`Tier 2`,"reactions.remove":`Tier 2`,"reminders.add":`Tier 2`,"reminders.complete":`Tier 2`,"reminders.delete":`Tier 2`,"reminders.info":`Tier 2`,"reminders.list":`Tier 2`,"rtm.connect":`Tier 1`,"rtm.start":`Tier 1`,"search.all":`Tier 2`,"search.files":`Tier 2`,"search.messages":`Tier 2`,"slackLists.access.delete":`Tier 3`,"slackLists.access.set":`Tier 3`,"slackLists.create":`Tier 2`,"slackLists.download.get":`Tier 4`,"slackLists.download.start":`Tier 2`,"slackLists.items.create":`Tier 3`,"slackLists.items.delete":`Tier 2`,"slackLists.items.deleteMultiple":`Tier 2`,"slackLists.items.info":`Tier 2`,"slackLists.items.list":`Tier 2`,"slackLists.items.update":`Tier 3`,"slackLists.update":`Tier 2`,"stars.add":`Tier 2`,"stars.list":`Tier 3`,"stars.remove":`Tier 2`,"team.accessLogs":`Tier 2`,"team.billableInfo":`Tier 2`,"team.billing.info":`Tier 3`,"team.externalTeams.disconnect":`Tier 1`,"team.externalTeams.list":`Tier 2`,"team.info":`Tier 3`,"team.integrationLogs":`Tier 2`,"team.preferences.list":`Tier 3`,"team.profile.get":`Tier 3`,"tooling.tokens.rotate":`Special`,"usergroups.create":`Tier 2`,"usergroups.disable":`Tier 2`,"usergroups.enable":`Tier 2`,"usergroups.list":`Tier 2`,"usergroups.update":`Tier 2`,"usergroups.users.list":`Tier 2`,"usergroups.users.update":`Tier 2`,"users.conversations":`Tier 3`,"users.deletePhoto":`Tier 2`,"users.discoverableContacts.lookup":`Tier 2`,"users.getPresence":`Tier 3`,"users.identity":`Tier 3`,"users.info":`Tier 4`,"users.list":`Tier 2`,"users.lookupByEmail":`Tier 3`,"users.profile.get":`Tier 4`,"users.profile.set":`Tier 3`,"users.setActive":`Tier 2`,"users.setPhoto":`Tier 2`,"users.setPresence":`Tier 2`,"views.open":`Tier 4`,"views.publish":`Tier 4`,"views.push":`Tier 4`,"views.update":`Tier 4`,"workflows.featured.add":`Tier 2`,"workflows.featured.list":`Tier 2`,"workflows.featured.remove":`Tier 2`,"workflows.featured.set":`Tier 2`,"workflows.triggers.permissions.add":`Tier 3`,"workflows.triggers.permissions.list":`Tier 3`,"workflows.triggers.permissions.remove":`Tier 3`,"workflows.triggers.permissions.set":`Tier 3`};const u={intervalMs:6e4,burst:1},d={intervalMs:3e3,burst:3},f={intervalMs:1200,burst:4},te={"Tier 1":u,"Tier 2":d,"Tier 3":f,"Tier 4":{intervalMs:600,burst:5},Special:{intervalMs:1e3,burst:1}},ne=l,re=e=>te[ne[e]??``]??f,ie=e=>new Promise(t=>setTimeout(t,e)),ae=({intervalMs:e,burst:t})=>{let n=t,r=Date.now(),i=Promise.resolve(),a=async()=>{let i=Date.now();if(n=Math.min(t,n+(i-r)/e),r=i,n>=1){--n;return}await ie((1-n)*e),r=Date.now(),n=0};return{acquire:()=>{let e=i.then(a);return i=e.catch(()=>{}),e}}},p=()=>{let e=new Map;return async t=>{let n=(t.url??``).split(`/`).pop()??``,r=e.get(n);return r||(r=ae(re(n)),e.set(n,r)),await r.acquire(),t}},m=`SLACK_MCP_XOXP_TOKEN`,h={retries:3,factor:2,minTimeout:1e3,maxTimeout:3e4,randomize:!0},g=new WeakMap,_=(e=process.env[m],n={})=>{if(!e)throw Error(`${m} is not set`);let r=new t(e,{retryConfig:h,maxRequestConcurrency:8,requestInterceptor:p(),...n});return g.set(r,e),r},v=e=>g.get(e)??process.env.SLACK_MCP_XOXP_TOKEN,y=(Number(process.env.SLACK_MCP_CACHE_TTL)||86400)*1e3,b=()=>process.env.SLACK_MCP_CACHE_DIR||s(ee(),`.cache`,`slack-mcp-server`),x=e=>{let t=n(`sha256`).update(v(e)??``).digest(`hex`).slice(0,12);return s(b(),`cache-${t}.json`)},S=new WeakMap,oe=e=>{let t=S.get(e);if(t)return t;let n={};try{let t=x(e);r(t)&&(n=JSON.parse(a(t,`utf8`)))}catch{n={}}return S.set(e,n),n},se=(e,t)=>{try{i(b(),{recursive:!0,mode:448}),o(x(e),JSON.stringify(t),{mode:384})}catch{}},ce={channels:async e=>{let t={},n;do{let r=await e.conversations.list({types:`public_channel,private_channel`,exclude_archived:!0,limit:1e3,cursor:n});for(let e of r.channels??[])e.id&&e.name&&(t[e.name.toLowerCase()]=e.id);n=r.response_metadata?.next_cursor||void 0}while(n);return t},users:async e=>{let t={},n;do{let r=await e.users.list({limit:1e3,cursor:n});for(let e of r.members??[]){if(!e.id)continue;e.name&&(t[e.name.toLowerCase()]=e.id);let n=e.profile?.display_name;n&&(t[n.toLowerCase()]=e.id)}n=r.response_metadata?.next_cursor||void 0}while(n);return t}},C=new WeakMap,le=(e,t)=>{let n=C.get(e);n||(n={},C.set(e,n));let r=n[t];if(r)return r;let i=ce[t](e).finally(()=>{delete n[t]});return n[t]=i,i},w=async(e,t,n)=>{let r=oe(e),i=r[t];return(n||!i||Date.now()-i.at>=y)&&(r[t]={at:Date.now(),entries:await le(e,t)},se(e,r)),r[t]},T=async(e,t,n)=>{let r=await w(e,t,!1);if(r.entries[n]!==void 0)return r.entries[n];if(!(Date.now()-r.at<5e3))return(await w(e,t,!0)).entries[n]},E=(e,t)=>T(e,`channels`,t),D=(e,t)=>T(e,`users`,t),O=/^[CGD][A-Z0-9]+$/,k=/^[UW][A-Z0-9]+$/,A=async(e,t)=>{let n=t.trim();if(O.test(n))return n;let r=await E(e,n.replace(/^#/,``).toLowerCase());if(!r)throw Error(`channel not found: ${t}`);return r},j=async(e,t)=>{let n=t.trim();if(k.test(n))return n;let r=await D(e,n.replace(/^@/,``).toLowerCase());if(!r)throw Error(`user not found: ${t}`);return r},M=async(e,t,n)=>typeof t==`string`?n(e,t):Array.isArray(t)?Promise.all(t.map(t=>typeof t==`string`?n(e,t):t)):t,N=[`channel`,`channels`,`additional_channels`],P=[`user`,`users`],F=async(e,t,n={})=>{let r=e.input.parse(n);for(let e of N)e in r&&(r[e]=await M(t,r[e],A));for(let e of P)e in r&&(r[e]=await M(t,r[e],j));return e.handler(t,r)},I=e=>e,L=I({name:`chat_post_message`,description:`Sends a message to a channel.`,tier:`write`,scopes:[`chat:write`],input:c.object({channel:c.string().describe(`An encoded ID or channel name that represents a channel, private group, or IM channel to send the message to.`),text:c.string().optional().describe(`How this field works and whether it is required depends on other fields you use in your API call.`),blocks:c.array(c.unknown()).optional().describe(`An array of structured blocks.`),attachments:c.array(c.unknown()).optional().describe(`An array of structured attachments.`),markdown_text:c.string().optional().describe(`Accepts message text formatted in markdown. Should not be used with blocks or text. Limit to 12,000 characters.`),thread_ts:c.string().optional().describe(`Provide another message's ts value to make this message a reply. Use the parent's ts, not a reply's.`),reply_broadcast:c.boolean().optional().describe(`Used with thread_ts; indicates whether the reply should be made visible to everyone in the channel. Defaults to false.`),mrkdwn:c.boolean().optional().describe(`Disable Slack markup parsing by setting to false. Enabled by default.`),parse:c.string().optional().describe(`Change how messages are treated.`),link_names:c.boolean().optional().describe(`Find and link user groups.`),unfurl_links:c.boolean().optional().describe(`Pass true to enable unfurling of primarily text-based content.`),unfurl_media:c.boolean().optional().describe(`Pass false to disable unfurling of media content.`),metadata:c.unknown().optional().describe(`JSON object with event_type and event_payload fields.`),icon_emoji:c.string().optional().describe(`Emoji to use as the icon for this message. Overrides icon_url.`),icon_url:c.string().optional().describe(`URL to an image to use as the icon for this message.`),username:c.string().optional().describe(`Set your bot's user name.`),as_user:c.boolean().optional().describe(`(Legacy) Pass true to post the message as the authed user. Can only be used by classic apps.`)}),handler:async(e,t)=>{let n=await e.chat.postMessage(t);return{ts:n.ts,channel:n.channel}}}),R=async(e,t,n)=>{let r=[];r.length=e.length;let i=0,a=async()=>{for(;i<e.length;){let t=i++;r[t]=await n(e[t],t)}},o=Math.max(1,Math.min(t,e.length));return await Promise.all(Array.from({length:o},a)),r},z=[`channels:read`,`groups:read`,`im:read`,`mpim:read`],B=[`channels:history`,`groups:history`,`im:history`,`mpim:history`],V=[`channels:write`,`groups:write`,`im:write`,`mpim:write`],H=c.string().optional().describe(`Paginate through collections of data by setting the cursor parameter to a next_cursor attribute returned by a previous request's response_metadata.`),U=c.string().optional().describe(`Mix and match channel types by providing a comma-separated list of any combination of public_channel, private_channel, mpim, im.`),W=I({name:`conversations_history`,description:`Fetches a conversation's history of messages and events.`,tier:`read`,scopes:B,input:c.object({channel:c.string().describe(`Conversation ID to fetch history for.`),cursor:H,include_all_metadata:c.boolean().optional().describe(`Return all metadata associated with this message.`),inclusive:c.boolean().optional().describe(`Include messages with oldest or latest timestamps in results. Ignored unless either timestamp is specified.`),latest:c.string().optional().describe(`Only messages before this Unix timestamp will be included in results. Default is the current time.`),limit:c.number().int().min(1).max(999).default(100).describe(`The maximum number of items to return. Maximum of 999.`),oldest:c.string().optional().describe(`Only messages after this Unix timestamp will be included in results.`)}),handler:async(e,t)=>{let n=await e.conversations.history({channel:t.channel,cursor:t.cursor,include_all_metadata:t.include_all_metadata,inclusive:t.inclusive,latest:t.latest,limit:t.limit,oldest:t.oldest});return{messages:n.messages??[],has_more:n.has_more??!1,next_cursor:n.response_metadata?.next_cursor||void 0}}}),ue=I({name:`conversations_replies`,description:`Retrieve a thread of messages posted to a conversation.`,tier:`read`,scopes:B,input:c.object({channel:c.string().describe(`Conversation ID to fetch thread from.`),ts:c.string().describe(`Unique identifier of either a thread's parent message or a message in the thread.`),cursor:H,include_all_metadata:c.boolean().optional().describe(`Return all metadata associated with this message.`),inclusive:c.boolean().optional().describe(`Include messages with oldest or latest timestamps in results. Ignored unless either timestamp is specified.`),latest:c.string().optional().describe(`Only messages before this Unix timestamp will be included in results.`),limit:c.number().int().min(1).max(999).default(100).describe(`The maximum number of items to return.`),oldest:c.string().optional().describe(`Only messages after this Unix timestamp will be included in results.`)}),handler:async(e,t)=>{let n=await e.conversations.replies({channel:t.channel,ts:t.ts,cursor:t.cursor,include_all_metadata:t.include_all_metadata,inclusive:t.inclusive,latest:t.latest,limit:t.limit,oldest:t.oldest});return{messages:n.messages??[],has_more:n.has_more??!1,next_cursor:n.response_metadata?.next_cursor||void 0}}}),de=I({name:`conversations_list`,description:`Lists all channels in a Slack team.`,tier:`read`,scopes:z,input:c.object({cursor:H,exclude_archived:c.boolean().default(!0).describe(`Set to true to exclude archived channels from the list.`),limit:c.number().int().min(1).max(999).default(200).describe(`The maximum number of items to return. Must be an integer under 1000.`),team_id:c.string().optional().describe(`Encoded team id to list channels in, required if token belongs to org-wide app.`),types:U}),handler:async(e,t)=>{let n=await e.conversations.list({cursor:t.cursor,exclude_archived:t.exclude_archived,limit:t.limit,team_id:t.team_id,types:t.types});return{channels:n.channels??[],next_cursor:n.response_metadata?.next_cursor||void 0}}}),fe=I({name:`users_conversations`,description:`List conversations the calling user is a member of.`,tier:`read`,scopes:z,input:c.object({cursor:H,exclude_archived:c.boolean().default(!0).describe(`Set to true to exclude archived channels from the list.`),limit:c.number().int().min(1).max(999).default(200).describe(`The maximum number of items to return. Must be an integer with a max value of 999.`),team_id:c.string().optional().describe(`Encoded team id to list conversations in, required if org token is used.`),types:U,user:c.string().optional().describe(`Browse conversations by a specific user ID's membership.`)}),handler:async(e,t)=>{let n=await e.users.conversations({cursor:t.cursor,exclude_archived:t.exclude_archived,limit:t.limit,team_id:t.team_id,types:t.types,user:t.user});return{channels:n.channels??[],next_cursor:n.response_metadata?.next_cursor||void 0}}}),pe=I({name:`conversations_unreads`,description:`List the calling user's channels that have unread messages. Composite over users.conversations and conversations.info; partial on large workspaces.`,tier:`read`,scopes:[...z,...B],input:c.object({types:U,max_channels:c.number().int().min(1).max(200).default(50).describe(`Maximum number of member channels to scan for unreads.`)}),handler:async(e,t)=>({unreads:(await R((await e.users.conversations({types:t.types,limit:t.max_channels})).channels??[],4,async t=>{if(t.id)try{let n=(await e.conversations.info({channel:t.id})).channel,r=n?.unread_count_display??n?.unread_count??0;return r>0?{id:t.id,name:t.name,unread_count:r}:void 0}catch{return}})).filter(e=>e!==void 0)})}),me=I({name:`conversations_mark`,description:`Sets the read cursor in a channel.`,tier:`write`,scopes:V,input:c.object({channel:c.string().describe(`Channel or conversation to set the read cursor for.`),ts:c.string().describe(`Unique identifier of message you want marked as most recently seen in this conversation.`)}),handler:async(e,t)=>(await e.conversations.mark({channel:t.channel,ts:t.ts}),{ok:!0})}),he=I({name:`conversations_join`,description:`Joins an existing conversation.`,tier:`write`,scopes:[`channels:write`],input:c.object({channel:c.string().describe(`ID of conversation to join.`)}),handler:async(e,t)=>({channel:(await e.conversations.join({channel:t.channel})).channel})}),ge=I({name:`conversations_leave`,description:`Leaves a conversation.`,tier:`write`,scopes:V,input:c.object({channel:c.string().describe(`Conversation to leave.`)}),handler:async(e,t)=>(await e.conversations.leave({channel:t.channel}),{ok:!0})}),_e=I({name:`files_info`,description:`Gets information about a file (and, when under 5MB, its content: text as-is, binary as base64).`,tier:`read`,scopes:[`files:read`],input:c.object({file:c.string().describe(`Specify a file by providing its ID.`),count:c.number().int().optional().describe(`Number of comments to return per page.`),cursor:c.string().optional().describe(`Parameter for pagination. Set to the next_cursor attribute returned by the previous request's response_metadata.`),limit:c.number().int().optional().describe(`The maximum number of items to return.`),page:c.number().int().optional().describe(`Page number of comments to return.`)}),handler:async(e,t)=>{let n=await e.files.info({file:t.file,count:t.count,cursor:t.cursor,limit:t.limit,page:t.page}),r=n.file,i=r?.url_private_download??r?.url_private,a=v(e),o;if(i&&a&&(r?.size??0)<=5242880){let e=await fetch(i,{headers:{Authorization:`Bearer ${a}`}}),t=Buffer.from(await e.arrayBuffer());o=(r?.mimetype??``).startsWith(`text/`)?{encoding:`utf8`,data:t.toString(`utf8`)}:{encoding:`base64`,data:t.toString(`base64`)}}return{file:n.file,content:o}}}),ve=I({name:`reactions_add`,description:`Adds a reaction to an item.`,tier:`write`,scopes:[`reactions:write`],input:c.object({channel:c.string().describe(`Channel where the message to add reaction to was posted.`),name:c.string().describe(`Reaction (emoji) name.`),timestamp:c.string().describe(`Timestamp of the message to add reaction to.`)}),handler:async(e,t)=>(await e.reactions.add({channel:t.channel,name:t.name,timestamp:t.timestamp}),{ok:!0})}),ye=I({name:`reactions_remove`,description:`Removes a reaction from an item.`,tier:`write`,scopes:[`reactions:write`],input:c.object({name:c.string().describe(`Reaction (emoji) name.`),channel:c.string().optional().describe(`Channel where the message to remove reaction from was posted.`),timestamp:c.string().optional().describe(`Timestamp of the message to remove reaction from.`),file:c.string().optional().describe(`File to remove reaction from.`),file_comment:c.string().optional().describe(`File comment to remove reaction from.`)}),handler:async(e,t)=>(await e.reactions.remove({name:t.name,channel:t.channel,timestamp:t.timestamp,file:t.file,file_comment:t.file_comment}),{ok:!0})}),be=I({name:`search_messages`,description:`Searches for messages matching a query.`,tier:`read`,scopes:[`search:read`],input:c.object({query:c.string().describe(`Search query.`),count:c.number().int().min(1).max(100).default(20).describe(`Number of results you want per "page". Maximum of 100.`),highlight:c.boolean().optional().describe(`Pass true to enable query highlight markers.`),page:c.number().int().min(1).optional().describe(`Page number of results to return.`),cursor:c.string().optional().describe(`Use for cursormark pagination. Send * for the first call, then the next_cursor from the previous results.`),sort:c.enum([`score`,`timestamp`]).optional().describe(`Return matches sorted by either score or timestamp.`),sort_dir:c.enum([`asc`,`desc`]).optional().describe(`Change sort direction to ascending (asc) or descending (desc).`),team_id:c.string().optional().describe(`Encoded team id to search in, required if org token is used.`)}),handler:async(e,t)=>{let n=await e.search.messages({query:t.query,count:t.count,highlight:t.highlight,page:t.page,cursor:t.cursor,sort:t.sort,sort_dir:t.sort_dir,team_id:t.team_id});return{matches:n.messages?.matches??[],total:n.messages?.total??0,pagination:n.messages?.pagination,next_cursor:n.response_metadata?.next_cursor||void 0}}}),G=c.array(c.string()).optional().describe(`Encoded channel IDs the User Group uses as a default.`),K=c.array(c.string()).optional().describe(`Encoded channel IDs the User Group can custom add usergroup members to.`),q=c.string().optional().describe(`A short description of the User Group.`),J=c.string().optional().describe(`A mention handle. Must be unique among channels, users and User Groups.`),Y=c.boolean().optional().describe(`Include the number of users in each User Group.`),X=c.boolean().optional().describe(`Configure this user group to show as a sidebar section for all group members.`),Z=c.string().optional().describe(`Encoded team id where the user group exists, required if org token is used.`),xe=I({name:`usergroups_list`,description:`List all User Groups for a team.`,tier:`read`,scopes:[`usergroups:read`],input:c.object({include_count:Y,include_disabled:c.boolean().optional().describe(`Include results for disabled User Groups.`),include_users:c.boolean().optional().describe(`Include the list of users for each User Group.`),team_id:c.string().optional().describe(`The user group's encoded team ID. Required if org token is used.`)}),handler:async(e,t)=>({usergroups:(await e.usergroups.list({include_count:t.include_count,include_disabled:t.include_disabled,include_users:t.include_users,team_id:t.team_id})).usergroups??[]})}),Se=I({name:`usergroups_me`,description:`List the user groups the authenticated user belongs to. Composite over auth.test and usergroups.list.`,tier:`read`,scopes:[`usergroups:read`],input:c.object({}),handler:async e=>{let t=await e.auth.test();return{usergroups:((await e.usergroups.list({include_users:!0})).usergroups??[]).filter(e=>(e.users??[]).includes(t.user_id??``))}}}),Ce=I({name:`usergroups_create`,description:`Create a User Group.`,tier:`write`,scopes:[`usergroups:write`],input:c.object({name:c.string().describe(`A name for the User Group. Must be unique among User Groups.`),channels:G,additional_channels:K,description:q,handle:J,include_count:Y,team_id:c.string().optional().describe(`Encoded team id where the user group has to be created, required if org token is used.`),enable_section:X}),handler:async(e,t)=>({usergroup:(await e.usergroups.create({name:t.name,channels:t.channels?.join(`,`),additional_channels:t.additional_channels?.join(`,`),description:t.description,handle:t.handle,include_count:t.include_count,team_id:t.team_id,enable_section:t.enable_section})).usergroup})}),we=I({name:`usergroups_update`,description:`Update an existing User Group.`,tier:`write`,scopes:[`usergroups:write`],input:c.object({usergroup:c.string().describe(`The encoded ID of the User Group to update.`),channels:G,additional_channels:K,description:q,handle:J,include_count:Y,name:c.string().optional().describe(`A name for the User Group. Must be unique among User Groups.`),team_id:Z,enable_section:X}),handler:async(e,t)=>({usergroup:(await e.usergroups.update({usergroup:t.usergroup,channels:t.channels?.join(`,`),additional_channels:t.additional_channels?.join(`,`),description:t.description,handle:t.handle,include_count:t.include_count,name:t.name,team_id:t.team_id,enable_section:t.enable_section})).usergroup})}),Q=I({name:`usergroups_users_update`,description:`Update the list of users for a user group.`,tier:`write`,scopes:[`usergroups:write`],input:c.object({usergroup:c.string().describe(`The encoded ID of the user group to update.`),users:c.array(c.string()).describe(`Encoded user IDs that represent the entire list of users for the user group.`),include_count:c.boolean().optional().describe(`Include the number of users in the user group.`),team_id:Z,additional_channels:K,is_shared:c.boolean().optional().describe(`Identify if the API is called when a shared section is getting shared.`)}),handler:async(e,t)=>({usergroup:(await e.usergroups.users.update({usergroup:t.usergroup,users:t.users.join(`,`),include_count:t.include_count,team_id:t.team_id,additional_channels:t.additional_channels?.join(`,`),is_shared:t.is_shared})).usergroup})}),$=[W,ue,de,fe,pe,be,I({name:`users_search`,description:`Find users by matching a query against id, name, real name, display name, or email (case-insensitive). Composite over users.list.`,tier:`read`,scopes:[`users:read`,`users:read.email`],input:c.object({query:c.string().describe(`Substring to match against id, name, real name, display name, or email.`),limit:c.number().int().min(1).max(1e3).default(200).describe(`The maximum number of users to scan from users.list.`)}),handler:async(e,t)=>{let n=await e.users.list({limit:t.limit}),r=t.query.toLowerCase();return{matches:(n.members??[]).filter(e=>[e.id,e.name,e.real_name,e.profile?.display_name,e.profile?.real_name,e.profile?.email].some(e=>typeof e==`string`&&e.toLowerCase().includes(r)))}}}),xe,Se,_e],Te=[L,ve,ye,me,he,ge,Ce,we,Q],Ee=[...$,...Te],De=e=>e?Ee:$;var Oe=`0.1.2`;const ke=({client:t=_(),allowWrite:n=!1}={})=>{let r=new e({name:`slack-mcp-server`,version:Oe});for(let e of De(n))r.registerTool(e.name,{description:e.description,inputSchema:e.input,annotations:{readOnlyHint:e.tier===`read`}},async n=>{let r=await F(e,t,n);return{content:[{type:`text`,text:JSON.stringify(r)}]}});return r};export{ke as t};
|
package/package.json
CHANGED
package/dist/server-D7nrZd31.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{McpServer as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{WebClient as t}from"@slack/web-api";import{z as n}from"zod";const r=`SLACK_MCP_XOXP_TOKEN`,i={retries:3,factor:2,minTimeout:1e3,maxTimeout:3e4,randomize:!0},a=new WeakMap,o=(e=process.env[r],n={})=>{if(!e)throw Error(`${r} is not set`);let o=new t(e,{retryConfig:i,maxRequestConcurrency:8,...n});return a.set(o,e),o},s=e=>a.get(e)??process.env.SLACK_MCP_XOXP_TOKEN,c=async(e,t,n={})=>e.handler(t,e.input.parse(n)),l=e=>e,u=l({name:`chat_post_message`,description:`Sends a message to a channel.`,tier:`write`,scopes:[`chat:write`],input:n.object({channel:n.string().describe(`An encoded ID or channel name that represents a channel, private group, or IM channel to send the message to.`),text:n.string().optional().describe(`How this field works and whether it is required depends on other fields you use in your API call.`),blocks:n.array(n.unknown()).optional().describe(`An array of structured blocks.`),attachments:n.array(n.unknown()).optional().describe(`An array of structured attachments.`),markdown_text:n.string().optional().describe(`Accepts message text formatted in markdown. Should not be used with blocks or text. Limit to 12,000 characters.`),thread_ts:n.string().optional().describe(`Provide another message's ts value to make this message a reply. Use the parent's ts, not a reply's.`),reply_broadcast:n.boolean().optional().describe(`Used with thread_ts; indicates whether the reply should be made visible to everyone in the channel. Defaults to false.`),mrkdwn:n.boolean().optional().describe(`Disable Slack markup parsing by setting to false. Enabled by default.`),parse:n.string().optional().describe(`Change how messages are treated.`),link_names:n.boolean().optional().describe(`Find and link user groups.`),unfurl_links:n.boolean().optional().describe(`Pass true to enable unfurling of primarily text-based content.`),unfurl_media:n.boolean().optional().describe(`Pass false to disable unfurling of media content.`),metadata:n.unknown().optional().describe(`JSON object with event_type and event_payload fields.`),icon_emoji:n.string().optional().describe(`Emoji to use as the icon for this message. Overrides icon_url.`),icon_url:n.string().optional().describe(`URL to an image to use as the icon for this message.`),username:n.string().optional().describe(`Set your bot's user name.`),as_user:n.boolean().optional().describe(`(Legacy) Pass true to post the message as the authed user. Can only be used by classic apps.`)}),handler:async(e,t)=>{let n=await e.chat.postMessage(t);return{ts:n.ts,channel:n.channel}}}),d=async(e,t,n)=>{let r=[];r.length=e.length;let i=0,a=async()=>{for(;i<e.length;){let t=i++;r[t]=await n(e[t],t)}},o=Math.max(1,Math.min(t,e.length));return await Promise.all(Array.from({length:o},a)),r},f=[`channels:read`,`groups:read`,`im:read`,`mpim:read`],p=[`channels:history`,`groups:history`,`im:history`,`mpim:history`],m=[`channels:write`,`groups:write`,`im:write`,`mpim:write`],h=n.string().optional().describe(`Paginate through collections of data by setting the cursor parameter to a next_cursor attribute returned by a previous request's response_metadata.`),g=n.string().optional().describe(`Mix and match channel types by providing a comma-separated list of any combination of public_channel, private_channel, mpim, im.`),_=l({name:`conversations_history`,description:`Fetches a conversation's history of messages and events.`,tier:`read`,scopes:p,input:n.object({channel:n.string().describe(`Conversation ID to fetch history for.`),cursor:h,include_all_metadata:n.boolean().optional().describe(`Return all metadata associated with this message.`),inclusive:n.boolean().optional().describe(`Include messages with oldest or latest timestamps in results. Ignored unless either timestamp is specified.`),latest:n.string().optional().describe(`Only messages before this Unix timestamp will be included in results. Default is the current time.`),limit:n.number().int().min(1).max(999).default(100).describe(`The maximum number of items to return. Maximum of 999.`),oldest:n.string().optional().describe(`Only messages after this Unix timestamp will be included in results.`)}),handler:async(e,t)=>{let n=await e.conversations.history({channel:t.channel,cursor:t.cursor,include_all_metadata:t.include_all_metadata,inclusive:t.inclusive,latest:t.latest,limit:t.limit,oldest:t.oldest});return{messages:n.messages??[],has_more:n.has_more??!1,next_cursor:n.response_metadata?.next_cursor||void 0}}}),v=l({name:`conversations_replies`,description:`Retrieve a thread of messages posted to a conversation.`,tier:`read`,scopes:p,input:n.object({channel:n.string().describe(`Conversation ID to fetch thread from.`),ts:n.string().describe(`Unique identifier of either a thread's parent message or a message in the thread.`),cursor:h,include_all_metadata:n.boolean().optional().describe(`Return all metadata associated with this message.`),inclusive:n.boolean().optional().describe(`Include messages with oldest or latest timestamps in results. Ignored unless either timestamp is specified.`),latest:n.string().optional().describe(`Only messages before this Unix timestamp will be included in results.`),limit:n.number().int().min(1).max(999).default(100).describe(`The maximum number of items to return.`),oldest:n.string().optional().describe(`Only messages after this Unix timestamp will be included in results.`)}),handler:async(e,t)=>{let n=await e.conversations.replies({channel:t.channel,ts:t.ts,cursor:t.cursor,include_all_metadata:t.include_all_metadata,inclusive:t.inclusive,latest:t.latest,limit:t.limit,oldest:t.oldest});return{messages:n.messages??[],has_more:n.has_more??!1,next_cursor:n.response_metadata?.next_cursor||void 0}}}),y=l({name:`conversations_list`,description:`Lists all channels in a Slack team.`,tier:`read`,scopes:f,input:n.object({cursor:h,exclude_archived:n.boolean().default(!0).describe(`Set to true to exclude archived channels from the list.`),limit:n.number().int().min(1).max(999).default(200).describe(`The maximum number of items to return. Must be an integer under 1000.`),team_id:n.string().optional().describe(`Encoded team id to list channels in, required if token belongs to org-wide app.`),types:g}),handler:async(e,t)=>{let n=await e.conversations.list({cursor:t.cursor,exclude_archived:t.exclude_archived,limit:t.limit,team_id:t.team_id,types:t.types});return{channels:n.channels??[],next_cursor:n.response_metadata?.next_cursor||void 0}}}),b=l({name:`users_conversations`,description:`List conversations the calling user is a member of.`,tier:`read`,scopes:f,input:n.object({cursor:h,exclude_archived:n.boolean().default(!0).describe(`Set to true to exclude archived channels from the list.`),limit:n.number().int().min(1).max(999).default(200).describe(`The maximum number of items to return. Must be an integer with a max value of 999.`),team_id:n.string().optional().describe(`Encoded team id to list conversations in, required if org token is used.`),types:g,user:n.string().optional().describe(`Browse conversations by a specific user ID's membership.`)}),handler:async(e,t)=>{let n=await e.users.conversations({cursor:t.cursor,exclude_archived:t.exclude_archived,limit:t.limit,team_id:t.team_id,types:t.types,user:t.user});return{channels:n.channels??[],next_cursor:n.response_metadata?.next_cursor||void 0}}}),x=l({name:`conversations_unreads`,description:`List the calling user's channels that have unread messages. Composite over users.conversations and conversations.info; partial on large workspaces.`,tier:`read`,scopes:[...f,...p],input:n.object({types:g,max_channels:n.number().int().min(1).max(200).default(50).describe(`Maximum number of member channels to scan for unreads.`)}),handler:async(e,t)=>({unreads:(await d((await e.users.conversations({types:t.types,limit:t.max_channels})).channels??[],4,async t=>{if(t.id)try{let n=(await e.conversations.info({channel:t.id})).channel,r=n?.unread_count_display??n?.unread_count??0;return r>0?{id:t.id,name:t.name,unread_count:r}:void 0}catch{return}})).filter(e=>e!==void 0)})}),S=l({name:`conversations_mark`,description:`Sets the read cursor in a channel.`,tier:`write`,scopes:m,input:n.object({channel:n.string().describe(`Channel or conversation to set the read cursor for.`),ts:n.string().describe(`Unique identifier of message you want marked as most recently seen in this conversation.`)}),handler:async(e,t)=>(await e.conversations.mark({channel:t.channel,ts:t.ts}),{ok:!0})}),C=l({name:`conversations_join`,description:`Joins an existing conversation.`,tier:`write`,scopes:[`channels:write`],input:n.object({channel:n.string().describe(`ID of conversation to join.`)}),handler:async(e,t)=>({channel:(await e.conversations.join({channel:t.channel})).channel})}),w=l({name:`conversations_leave`,description:`Leaves a conversation.`,tier:`write`,scopes:m,input:n.object({channel:n.string().describe(`Conversation to leave.`)}),handler:async(e,t)=>(await e.conversations.leave({channel:t.channel}),{ok:!0})}),T=l({name:`files_info`,description:`Gets information about a file (and, when under 5MB, its content: text as-is, binary as base64).`,tier:`read`,scopes:[`files:read`],input:n.object({file:n.string().describe(`Specify a file by providing its ID.`),count:n.number().int().optional().describe(`Number of comments to return per page.`),cursor:n.string().optional().describe(`Parameter for pagination. Set to the next_cursor attribute returned by the previous request's response_metadata.`),limit:n.number().int().optional().describe(`The maximum number of items to return.`),page:n.number().int().optional().describe(`Page number of comments to return.`)}),handler:async(e,t)=>{let n=await e.files.info({file:t.file,count:t.count,cursor:t.cursor,limit:t.limit,page:t.page}),r=n.file,i=r?.url_private_download??r?.url_private,a=s(e),o;if(i&&a&&(r?.size??0)<=5242880){let e=await fetch(i,{headers:{Authorization:`Bearer ${a}`}}),t=Buffer.from(await e.arrayBuffer());o=(r?.mimetype??``).startsWith(`text/`)?{encoding:`utf8`,data:t.toString(`utf8`)}:{encoding:`base64`,data:t.toString(`base64`)}}return{file:n.file,content:o}}}),E=l({name:`reactions_add`,description:`Adds a reaction to an item.`,tier:`write`,scopes:[`reactions:write`],input:n.object({channel:n.string().describe(`Channel where the message to add reaction to was posted.`),name:n.string().describe(`Reaction (emoji) name.`),timestamp:n.string().describe(`Timestamp of the message to add reaction to.`)}),handler:async(e,t)=>(await e.reactions.add({channel:t.channel,name:t.name,timestamp:t.timestamp}),{ok:!0})}),D=l({name:`reactions_remove`,description:`Removes a reaction from an item.`,tier:`write`,scopes:[`reactions:write`],input:n.object({name:n.string().describe(`Reaction (emoji) name.`),channel:n.string().optional().describe(`Channel where the message to remove reaction from was posted.`),timestamp:n.string().optional().describe(`Timestamp of the message to remove reaction from.`),file:n.string().optional().describe(`File to remove reaction from.`),file_comment:n.string().optional().describe(`File comment to remove reaction from.`)}),handler:async(e,t)=>(await e.reactions.remove({name:t.name,channel:t.channel,timestamp:t.timestamp,file:t.file,file_comment:t.file_comment}),{ok:!0})}),O=l({name:`search_messages`,description:`Searches for messages matching a query.`,tier:`read`,scopes:[`search:read`],input:n.object({query:n.string().describe(`Search query.`),count:n.number().int().min(1).max(100).default(20).describe(`Number of results you want per "page". Maximum of 100.`),highlight:n.boolean().optional().describe(`Pass true to enable query highlight markers.`),page:n.number().int().min(1).optional().describe(`Page number of results to return.`),cursor:n.string().optional().describe(`Use for cursormark pagination. Send * for the first call, then the next_cursor from the previous results.`),sort:n.enum([`score`,`timestamp`]).optional().describe(`Return matches sorted by either score or timestamp.`),sort_dir:n.enum([`asc`,`desc`]).optional().describe(`Change sort direction to ascending (asc) or descending (desc).`),team_id:n.string().optional().describe(`Encoded team id to search in, required if org token is used.`)}),handler:async(e,t)=>{let n=await e.search.messages({query:t.query,count:t.count,highlight:t.highlight,page:t.page,cursor:t.cursor,sort:t.sort,sort_dir:t.sort_dir,team_id:t.team_id});return{matches:n.messages?.matches??[],total:n.messages?.total??0,pagination:n.messages?.pagination,next_cursor:n.response_metadata?.next_cursor||void 0}}}),k=n.array(n.string()).optional().describe(`Encoded channel IDs the User Group uses as a default.`),A=n.array(n.string()).optional().describe(`Encoded channel IDs the User Group can custom add usergroup members to.`),j=n.string().optional().describe(`A short description of the User Group.`),M=n.string().optional().describe(`A mention handle. Must be unique among channels, users and User Groups.`),N=n.boolean().optional().describe(`Include the number of users in each User Group.`),P=n.boolean().optional().describe(`Configure this user group to show as a sidebar section for all group members.`),F=n.string().optional().describe(`Encoded team id where the user group exists, required if org token is used.`),I=l({name:`usergroups_list`,description:`List all User Groups for a team.`,tier:`read`,scopes:[`usergroups:read`],input:n.object({include_count:N,include_disabled:n.boolean().optional().describe(`Include results for disabled User Groups.`),include_users:n.boolean().optional().describe(`Include the list of users for each User Group.`),team_id:n.string().optional().describe(`The user group's encoded team ID. Required if org token is used.`)}),handler:async(e,t)=>({usergroups:(await e.usergroups.list({include_count:t.include_count,include_disabled:t.include_disabled,include_users:t.include_users,team_id:t.team_id})).usergroups??[]})}),L=l({name:`usergroups_me`,description:`List the user groups the authenticated user belongs to. Composite over auth.test and usergroups.list.`,tier:`read`,scopes:[`usergroups:read`],input:n.object({}),handler:async e=>{let t=await e.auth.test();return{usergroups:((await e.usergroups.list({include_users:!0})).usergroups??[]).filter(e=>(e.users??[]).includes(t.user_id??``))}}}),R=l({name:`usergroups_create`,description:`Create a User Group.`,tier:`write`,scopes:[`usergroups:write`],input:n.object({name:n.string().describe(`A name for the User Group. Must be unique among User Groups.`),channels:k,additional_channels:A,description:j,handle:M,include_count:N,team_id:n.string().optional().describe(`Encoded team id where the user group has to be created, required if org token is used.`),enable_section:P}),handler:async(e,t)=>({usergroup:(await e.usergroups.create({name:t.name,channels:t.channels?.join(`,`),additional_channels:t.additional_channels?.join(`,`),description:t.description,handle:t.handle,include_count:t.include_count,team_id:t.team_id,enable_section:t.enable_section})).usergroup})}),z=l({name:`usergroups_update`,description:`Update an existing User Group.`,tier:`write`,scopes:[`usergroups:write`],input:n.object({usergroup:n.string().describe(`The encoded ID of the User Group to update.`),channels:k,additional_channels:A,description:j,handle:M,include_count:N,name:n.string().optional().describe(`A name for the User Group. Must be unique among User Groups.`),team_id:F,enable_section:P}),handler:async(e,t)=>({usergroup:(await e.usergroups.update({usergroup:t.usergroup,channels:t.channels?.join(`,`),additional_channels:t.additional_channels?.join(`,`),description:t.description,handle:t.handle,include_count:t.include_count,name:t.name,team_id:t.team_id,enable_section:t.enable_section})).usergroup})}),B=l({name:`usergroups_users_update`,description:`Update the list of users for a user group.`,tier:`write`,scopes:[`usergroups:write`],input:n.object({usergroup:n.string().describe(`The encoded ID of the user group to update.`),users:n.array(n.string()).describe(`Encoded user IDs that represent the entire list of users for the user group.`),include_count:n.boolean().optional().describe(`Include the number of users in the user group.`),team_id:F,additional_channels:A,is_shared:n.boolean().optional().describe(`Identify if the API is called when a shared section is getting shared.`)}),handler:async(e,t)=>({usergroup:(await e.usergroups.users.update({usergroup:t.usergroup,users:t.users.join(`,`),include_count:t.include_count,team_id:t.team_id,additional_channels:t.additional_channels?.join(`,`),is_shared:t.is_shared})).usergroup})}),V=[_,v,y,b,x,O,l({name:`users_search`,description:`Find users by matching a query against id, name, real name, display name, or email (case-insensitive). Composite over users.list.`,tier:`read`,scopes:[`users:read`,`users:read.email`],input:n.object({query:n.string().describe(`Substring to match against id, name, real name, display name, or email.`),limit:n.number().int().min(1).max(1e3).default(200).describe(`The maximum number of users to scan from users.list.`)}),handler:async(e,t)=>{let n=await e.users.list({limit:t.limit}),r=t.query.toLowerCase();return{matches:(n.members??[]).filter(e=>[e.id,e.name,e.real_name,e.profile?.display_name,e.profile?.real_name,e.profile?.email].some(e=>typeof e==`string`&&e.toLowerCase().includes(r)))}}}),I,L,T],H=[u,E,D,S,C,w,R,z,B],U=[...V,...H],W=e=>e?U:V;var G=`0.1.0`;const K=({client:t=o(),allowWrite:n=!1}={})=>{let r=new e({name:`slack-mcp-server`,version:G});for(let e of W(n))r.registerTool(e.name,{description:e.description,inputSchema:e.input,annotations:{readOnlyHint:e.tier===`read`}},async n=>{let r=await c(e,t,n);return{content:[{type:`text`,text:JSON.stringify(r)}]}});return r};export{K as t};
|