Skip to main content
Glama
index.ts12.1 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { getSlackConfig } from './config/credentials.js'; import { SlackClientWrapper } from './utils/slack-client.js'; // Import tool handlers import * as channelTools from './tools/channels.js'; import * as userTools from './tools/users.js'; import * as messageTools from './tools/messages.js'; import * as fileTools from './tools/files.js'; import * as reactionTools from './tools/reactions.js'; import * as workspaceTools from './tools/workspace.js'; // Initialize Slack client let slackClient: SlackClientWrapper; try { const config = getSlackConfig(); slackClient = new SlackClientWrapper(config); } catch (error) { console.error('Failed to initialize Slack client:', error); process.exit(1); } // Create MCP server const server = new Server( { name: 'slack-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Tool definitions const tools = [ // Channel tools { name: 'list_channels', description: 'List channels in the Slack workspace', inputSchema: { type: 'object', properties: { types: { type: 'string', description: 'Comma-separated list of channel types (public_channel, private_channel, mpim, im)', default: 'public_channel,private_channel', }, exclude_archived: { type: 'boolean', description: 'Exclude archived channels', default: true, }, limit: { type: 'number', description: 'Maximum number of channels to return', default: 100, minimum: 1, maximum: 1000, }, }, }, }, { name: 'get_channel_info', description: 'Get detailed information about a specific channel', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID (e.g., C1234567890)', }, }, required: ['channel'], }, }, { name: 'create_channel', description: 'Create a new channel', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Channel name (lowercase, no spaces)', }, is_private: { type: 'boolean', description: 'Create as private channel', default: false, }, }, required: ['name'], }, }, { name: 'archive_channel', description: 'Archive a channel', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID to archive', }, }, required: ['channel'], }, }, // User tools { name: 'list_users', description: 'List users in the Slack workspace', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of users to return', default: 100, minimum: 1, maximum: 1000, }, }, }, }, { name: 'get_user_info', description: 'Get detailed information about a specific user', inputSchema: { type: 'object', properties: { user: { type: 'string', description: 'User ID (e.g., U1234567890)', }, }, required: ['user'], }, }, { name: 'invite_to_channel', description: 'Invite users to a channel', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, users: { type: 'array', items: { type: 'string', }, description: 'Array of user IDs to invite', }, }, required: ['channel', 'users'], }, }, // Message tools { name: 'send_message', description: 'Send a message to a channel', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, text: { type: 'string', description: 'Message text', }, thread_ts: { type: 'string', description: 'Optional thread timestamp to reply to', }, }, required: ['channel', 'text'], }, }, { name: 'update_message', description: 'Update an existing message', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, ts: { type: 'string', description: 'Message timestamp', }, text: { type: 'string', description: 'New message text', }, }, required: ['channel', 'ts', 'text'], }, }, { name: 'delete_message', description: 'Delete a message', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, ts: { type: 'string', description: 'Message timestamp', }, }, required: ['channel', 'ts'], }, }, { name: 'get_channel_history', description: 'Get message history from a channel', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, limit: { type: 'number', description: 'Maximum number of messages to return', default: 100, minimum: 1, maximum: 1000, }, oldest: { type: 'string', description: 'Start of time range (timestamp)', }, latest: { type: 'string', description: 'End of time range (timestamp)', }, }, required: ['channel'], }, }, { name: 'search_messages', description: 'Search for messages across the workspace', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query', }, count: { type: 'number', description: 'Number of results to return', default: 20, minimum: 1, maximum: 100, }, sort: { type: 'string', enum: ['score', 'timestamp'], description: 'Sort order', default: 'score', }, }, required: ['query'], }, }, { name: 'send_formatted_message', description: 'Send a message with Block Kit formatting', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, text: { type: 'string', description: 'Fallback text', }, blocks: { type: 'array', description: 'Block Kit blocks array', }, thread_ts: { type: 'string', description: 'Optional thread timestamp to reply to', }, }, required: ['channel', 'text', 'blocks'], }, }, // File tools { name: 'upload_file', description: 'Upload a file to Slack', inputSchema: { type: 'object', properties: { channels: { type: 'array', items: { type: 'string', }, description: 'Array of channel IDs to share the file to', }, content: { type: 'string', description: 'File content', }, filename: { type: 'string', description: 'Filename', }, title: { type: 'string', description: 'File title', }, initial_comment: { type: 'string', description: 'Initial comment', }, }, required: ['channels', 'content', 'filename'], }, }, // Reaction tools { name: 'add_reaction', description: 'Add an emoji reaction to a message', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, timestamp: { type: 'string', description: 'Message timestamp', }, name: { type: 'string', description: 'Emoji name (without colons)', }, }, required: ['channel', 'timestamp', 'name'], }, }, { name: 'remove_reaction', description: 'Remove an emoji reaction from a message', inputSchema: { type: 'object', properties: { channel: { type: 'string', description: 'Channel ID', }, timestamp: { type: 'string', description: 'Message timestamp', }, name: { type: 'string', description: 'Emoji name (without colons)', }, }, required: ['channel', 'timestamp', 'name'], }, }, // Workspace tools { name: 'get_team_info', description: 'Get information about the Slack workspace', inputSchema: { type: 'object', properties: {}, }, }, ]; // Register list_tools handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools, })); // Tool handler map const toolHandlers: Record<string, (args: unknown) => Promise<unknown>> = { // Channel tools list_channels: (args) => channelTools.listChannels(slackClient, args), get_channel_info: (args) => channelTools.getChannelInfo(slackClient, args), create_channel: (args) => channelTools.createChannel(slackClient, args), archive_channel: (args) => channelTools.archiveChannel(slackClient, args), // User tools list_users: (args) => userTools.listUsers(slackClient, args), get_user_info: (args) => userTools.getUserInfo(slackClient, args), invite_to_channel: (args) => userTools.inviteToChannel(slackClient, args), // Message tools send_message: (args) => messageTools.sendMessage(slackClient, args), update_message: (args) => messageTools.updateMessage(slackClient, args), delete_message: (args) => messageTools.deleteMessage(slackClient, args), get_channel_history: (args) => messageTools.getChannelHistory(slackClient, args), search_messages: (args) => messageTools.searchMessages(slackClient, args), send_formatted_message: (args) => messageTools.sendFormattedMessage(slackClient, args), // File tools upload_file: (args) => fileTools.uploadFile(slackClient, args), // Reaction tools add_reaction: (args) => reactionTools.addReaction(slackClient, args), remove_reaction: (args) => reactionTools.removeReaction(slackClient, args), // Workspace tools get_team_info: (args) => workspaceTools.getTeamInfo(slackClient, args), }; // Register call_tool handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const handler = toolHandlers[name]; if (!handler) { throw new Error(`Unknown tool: ${name}`); } const result = await handler(args); return { content: [ { type: 'text', text: JSON.stringify(result), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { content: [ { type: 'text', text: `Error: ${errorMessage}`, }, ], isError: true, }; } }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('Slack MCP Server running on stdio'); } main().catch((error) => { console.error('Server error:', error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Hais/slack-bot-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server