fix(slack): replace Slack MCP stdio client with direct web API#1066
fix(slack): replace Slack MCP stdio client with direct web API#1066saddlepaddle merged 1 commit intomainfrom
Conversation
The Slack MCP client used StdioClientTransport to spawn `npx @modelcontextprotocol/server-slack` as a child process. This fails on Vercel serverless (no writable home dir, no persistent processes). Replace with a single `slack_get_channel_history` tool implemented directly via @slack/web-api. The Superset MCP client (in-memory transport) is unaffected.
📝 WalkthroughWalkthroughThe changes remove the Slack MCP client integration and replace it with a simpler built-in tool for fetching channel history. The Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/api/src/app/api/integrations/slack/events/utils/run-agent/run-agent.ts`:
- Around line 159-202: Extract the magic numbers into named constants (e.g.,
DEFAULT_CHANNEL_HISTORY_LIMIT = 20, MAX_CHANNEL_HISTORY_LIMIT = 100,
EFFECTIVE_MAX_CHANNEL_HISTORY_LIMIT = 15) and update
SLACK_GET_CHANNEL_HISTORY_TOOL.input_schema to declare numeric constraints
(integer type, minimum 1, maximum equal to MAX_CHANNEL_HISTORY_LIMIT) and a
documented default; in handleGetChannelHistory, validate and sanitize the
LLM-supplied limit by coercing to an integer, treating
non-numeric/NaN/negative/zero values as DEFAULT_CHANNEL_HISTORY_LIMIT, and clamp
the value to the allowed max (use Math.min(parsedLimit,
MAX_CHANNEL_HISTORY_LIMIT, EFFECTIVE_MAX_CHANNEL_HISTORY_LIMIT) or similar)
before passing it to WebClient.conversations.history to ensure only a safe,
bounded integer is sent.
| const SLACK_GET_CHANNEL_HISTORY_TOOL: Anthropic.Tool = { | ||
| name: "slack_get_channel_history", | ||
| description: | ||
| "Get recent messages from the current Slack channel. Use this to understand what the team has been discussing.", | ||
| input_schema: { | ||
| type: "object" as const, | ||
| properties: { | ||
| limit: { | ||
| type: "number", | ||
| description: "Number of messages to retrieve (default 20, max 100)", | ||
| }, | ||
| }, | ||
| required: [], | ||
| }, | ||
| }; | ||
|
|
||
| async function handleGetChannelHistory({ | ||
| token, | ||
| channelId, | ||
| limit = 20, | ||
| }: { | ||
| token: string; | ||
| channelId: string; | ||
| limit?: number; | ||
| }): Promise<string> { | ||
| const slack = new WebClient(token); | ||
| const result = await slack.conversations.history({ | ||
| channel: channelId, | ||
| limit: Math.min(limit, 100), | ||
| }); | ||
|
|
||
| if (!result.messages || result.messages.length === 0) { | ||
| return JSON.stringify({ messages: [] }); | ||
| } | ||
|
|
||
| const messages = result.messages.map((msg) => ({ | ||
| user: msg.user, | ||
| text: msg.text, | ||
| ts: msg.ts, | ||
| thread_ts: msg.thread_ts, | ||
| })); | ||
|
|
||
| return JSON.stringify({ messages }); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Slack Web API conversations.history limit parameter valid range behavior
💡 Result:
For conversations.history, Slack documents the limit parameter as:
- Type: number
- What it does: “maximum number of items to return”; Slack may return fewer than requested even if more history exists. [1]
- Default: 100 (unless you’re in the reduced-limit category below). [1]
- Maximum (normal behavior): 999 (and Slack notes using a
limitunder 1000 for pagination). [1][4]
Important: reduced limit for some non‑Marketplace apps
Slack introduced lower limits for apps commercially distributed outside the Slack Marketplace:
- For new apps / new installations (effective May 29, 2025):
conversations.historyis 1 request/minute and the maximum + defaultlimitare reduced to 15. [1][3] - Slack’s developer docs indicate the same reduced limits will apply to existing installations starting March 3, 2026. [4][6]
So in practice, the “valid range” depends on the app category: up to 999 normally, but effectively capped at 15 for affected non‑Marketplace commercially distributed apps. [1][3][4]
Sources: Slack method reference and changelog/rate-limit docs. [1][3][4][6]
🏁 Script executed:
# Check the codebase for similar Slack API calls and validation patterns
rg "conversations\.history" -A 5 -B 5Repository: superset-sh/superset
Length of output: 1179
🏁 Script executed:
# Look for other instances where the code handles LLM-supplied parameters or similar validation
rg "Math\.min|Math\.max|Number\.isFinite" apps/api/src/app/api/integrations/slack -B 3 -A 3Repository: superset-sh/superset
Length of output: 800
🏁 Script executed:
# Check if there are existing constants for Slack API limits elsewhere in the codebase
rg "LIMIT|HISTORY|SLACK.*20|SLACK.*100" apps/api/src/app/api/integrations/slack -iRepository: superset-sh/superset
Length of output: 2824
Extract magic numbers to constants and add input validation for LLM-supplied limit parameter.
limit defaults and caps (20, 100) are magic numbers that should be extracted per guidelines. More critically, limit is LLM-supplied and lacks validation—negative, NaN, or non-integer values will be passed directly to the Slack API, potentially causing issues. The Slack API conversations.history accepts values up to 999 (normally) but effective limits are dropping to 15 for non-Marketplace apps starting March 3, 2026.
🔧 Proposed fix
+const DEFAULT_CHANNEL_HISTORY_LIMIT = 20;
+const MAX_CHANNEL_HISTORY_LIMIT = 100;
+
const SLACK_GET_CHANNEL_HISTORY_TOOL: Anthropic.Tool = {
name: "slack_get_channel_history",
description:
"Get recent messages from the current Slack channel. Use this to understand what the team has been discussing.",
input_schema: {
type: "object" as const,
properties: {
limit: {
type: "number",
- description: "Number of messages to retrieve (default 20, max 100)",
+ description: `Number of messages to retrieve (default ${DEFAULT_CHANNEL_HISTORY_LIMIT}, max ${MAX_CHANNEL_HISTORY_LIMIT})`,
},
},
required: [],
},
};
async function handleGetChannelHistory({
token,
channelId,
- limit = 20,
+ limit = DEFAULT_CHANNEL_HISTORY_LIMIT,
}: {
token: string;
channelId: string;
limit?: number;
}): Promise<string> {
const slack = new WebClient(token);
+ const safeLimit = Number.isFinite(limit)
+ ? Math.max(1, Math.min(Math.trunc(limit), MAX_CHANNEL_HISTORY_LIMIT))
+ : DEFAULT_CHANNEL_HISTORY_LIMIT;
const result = await slack.conversations.history({
channel: channelId,
- limit: Math.min(limit, 100),
+ limit: safeLimit,
});🤖 Prompt for AI Agents
In `@apps/api/src/app/api/integrations/slack/events/utils/run-agent/run-agent.ts`
around lines 159 - 202, Extract the magic numbers into named constants (e.g.,
DEFAULT_CHANNEL_HISTORY_LIMIT = 20, MAX_CHANNEL_HISTORY_LIMIT = 100,
EFFECTIVE_MAX_CHANNEL_HISTORY_LIMIT = 15) and update
SLACK_GET_CHANNEL_HISTORY_TOOL.input_schema to declare numeric constraints
(integer type, minimum 1, maximum equal to MAX_CHANNEL_HISTORY_LIMIT) and a
documented default; in handleGetChannelHistory, validate and sanitize the
LLM-supplied limit by coercing to an integer, treating
non-numeric/NaN/negative/zero values as DEFAULT_CHANNEL_HISTORY_LIMIT, and clamp
the value to the allowed max (use Math.min(parsedLimit,
MAX_CHANNEL_HISTORY_LIMIT, EFFECTIVE_MAX_CHANNEL_HISTORY_LIMIT) or similar)
before passing it to WebClient.conversations.history to ensure only a safe,
bounded integer is sent.
Summary
npx @modelcontextprotocol/server-slackvia stdio transport, which fails on Vercel serverless (no writable home dir, npm can't cache packages, no persistent child processes)slack_get_channel_historytool using@slack/web-apidirectlyTest plan
Summary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.