Skip to main content
Glama
channelManager.ts8.55 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { UserConfigManager } from "../config/userConfig.js"; import { listSlackChannels, validateSlackToken } from "../slackClient.js"; import { getOAuthInstructions } from "../auth/slackOAuth.js"; import type { UserConfig } from "../config/schema.js"; const listChannelsArgsSchema = z.object({}); const setDefaultChannelArgsSchema = z.object({ channel: z.string().describe("Channel name or ID to set as default"), }); export function registerChannelManagerTools(server: McpServer) { server.registerTool( "list_channels", { title: "List Slack Channels", description: "List all available Slack channels for the configured workspace", inputSchema: listChannelsArgsSchema, }, async () => { console.error("[list_channels] Tool called"); const configManager = new UserConfigManager(); const slackToken = configManager.getSlackToken(); console.error("[list_channels] Token found:", slackToken ? `Yes (${slackToken.substring(0, 15)}...)` : "No"); if (!slackToken) { console.error("[list_channels] Error: No token found"); return { isError: true, content: [ { type: "text", text: "Slack token not found. Please set SLACK_BOT_TOKEN or SLACK_TOKEN environment variable, or run the 'configure' tool to set up your Slack integration.", }, ], }; } // Validate token before attempting to list channels const config = configManager.getCurrentUserConfig(); const hasStoredConfig = config !== null; try { console.error("[list_channels] Validating token..."); const tokenValidation = await validateSlackToken(slackToken); if (!tokenValidation.valid) { console.error("[list_channels] Token validation failed:", tokenValidation.error); let errorMessage = "Your Slack token is invalid or expired."; if (hasStoredConfig) { errorMessage += " Please run the 'configure' tool again with a valid token to update your configuration."; } else { errorMessage += `\n\n${getOAuthInstructions()}`; } return { isError: true, content: [ { type: "text", text: errorMessage, }, ], }; } console.error("[list_channels] Token validated, fetching channels from Slack..."); const channels = await listSlackChannels(slackToken); console.error("[list_channels] Found", channels.length, "channels"); if (channels.length === 0) { return { content: [ { type: "text", text: "No channels found. Make sure your Slack token has the 'channels:read' scope.", }, ], }; } const defaultChannel = config?.default_channel || process.env.SLACK_DEFAULT_CHANNEL || null; let response = `Available Slack Channels:\n\n`; channels.forEach((channel, index) => { const marker = channel.name === defaultChannel ? " (default)" : ""; const privacy = channel.is_private ? "🔒" : "🌐"; response += `${index + 1}. ${privacy} ${channel.name}${marker}\n`; }); console.error("[list_channels] Success! Returning", channels.length, "channels"); return { content: [ { type: "text", text: response, }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; const isAuthError = (error as any)?.isAuthError || errorMessage.includes("invalid_auth") || errorMessage.includes("not_authed"); console.error("[list_channels] Error:", errorMessage); // Provide more helpful error messages based on error type let userMessage: string; // Check for authentication errors if (isAuthError) { if (hasStoredConfig) { userMessage = "Your Slack token is invalid or expired. Please run the 'configure' tool again with a valid token to update your configuration."; } else { userMessage = `Slack authentication failed. Please verify your Slack token is valid and has the required scopes (channels:read, groups:read).\n\n${getOAuthInstructions()}`; } } else if (errorMessage.includes("missing_scope")) { userMessage = "Your Slack token is missing required scopes. Please add 'channels:read' and 'groups:read' scopes to your Slack app and reinstall it to your workspace."; } else { // For other errors, clean up double-wrapped messages if (errorMessage.startsWith("Failed to list channels: Failed to list channels:")) { // Remove the duplicate prefix userMessage = errorMessage.replace(/^Failed to list channels: /, ""); } else if (!errorMessage.includes("Failed to list channels")) { userMessage = `Failed to list channels: ${errorMessage}`; } else { userMessage = errorMessage; } } return { isError: true, content: [ { type: "text", text: userMessage, }, ], }; } } ); server.registerTool( "set_default_channel", { title: "Set Default Channel", description: "Set the default Slack channel for EOD status updates", inputSchema: setDefaultChannelArgsSchema, }, async (args) => { const configManager = new UserConfigManager(); const slackToken = configManager.getSlackToken(); if (!slackToken) { return { isError: true, content: [ { type: "text", text: "Slack token not found. Please set SLACK_BOT_TOKEN or SLACK_TOKEN environment variable, or run the 'configure' tool to set up your Slack integration.", }, ], }; } const config = configManager.getCurrentUserConfig(); try { let updatedConfig: UserConfig | null = null; // If no config exists but we have a token, create a config first if (!config && slackToken) { // Create a new config with the token from environment variable console.error("[set_default_channel] Creating new config with token from environment"); updatedConfig = configManager.saveConfig({ slack_token: slackToken, default_channel: args.channel, }); } else if (config) { // Update existing config console.error("[set_default_channel] Updating existing config"); updatedConfig = configManager.updateConfig({ default_channel: args.channel, }); if (!updatedConfig) { return { isError: true, content: [ { type: "text", text: "Failed to update default channel. Please run the 'configure' tool first to set up your Slack integration.", }, ], }; } } else { return { isError: true, content: [ { type: "text", text: "No configuration found. Please run the 'configure' tool first to set up your Slack integration.", }, ], }; } if (!updatedConfig) { return { isError: true, content: [ { type: "text", text: "Failed to set default channel.", }, ], }; } return { content: [ { type: "text", text: `✅ Default channel set to: ${updatedConfig.default_channel}`, }, ], }; } catch (error) { return { isError: true, content: [ { type: "text", text: `Failed to set default channel: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], }; } } ); }

Latest Blog Posts

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/SackeyDavid/cursor-eod-mcp'

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