mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-17 23:53:24 +02:00
Merge pull request #13 from modelcontextprotocol/mahesh/slack
Updated Slack
This commit is contained in:
13
package-lock.json
generated
13
package-lock.json
generated
@@ -3598,7 +3598,7 @@
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "0.5.0"
|
||||
"@modelcontextprotocol/sdk": "0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"mcp-server-slack": "dist/index.js"
|
||||
@@ -3607,6 +3607,17 @@
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
},
|
||||
"src/slack/node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.6.0.tgz",
|
||||
"integrity": "sha512-9rsDudGhDtMbvxohPoMMyAUOmEzQsOK+XFchh6gZGqo8sx9sBuZQs+CUttXqa8RZXKDaJRCN2tUtgGof7jRkkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
115
src/slack/README.md
Normal file
115
src/slack/README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Slack MCP Server
|
||||
|
||||
MCP Server for the Slack API, enabling Claude to interact with Slack workspaces.
|
||||
|
||||
## Tools
|
||||
|
||||
1. `slack_list_channels`
|
||||
- List public channels in the workspace
|
||||
- Optional inputs:
|
||||
- `limit` (number, default: 100, max: 200): Maximum number of channels to return
|
||||
- `cursor` (string): Pagination cursor for next page
|
||||
- Returns: List of channels with their IDs and information
|
||||
|
||||
2. `slack_post_message`
|
||||
- Post a new message to a Slack channel
|
||||
- Required inputs:
|
||||
- `channel_id` (string): The ID of the channel to post to
|
||||
- `text` (string): The message text to post
|
||||
- Returns: Message posting confirmation and timestamp
|
||||
|
||||
3. `slack_reply_to_thread`
|
||||
- Reply to a specific message thread
|
||||
- Required inputs:
|
||||
- `channel_id` (string): The channel containing the thread
|
||||
- `thread_ts` (string): Timestamp of the parent message
|
||||
- `text` (string): The reply text
|
||||
- Returns: Reply confirmation and timestamp
|
||||
|
||||
4. `slack_add_reaction`
|
||||
- Add an emoji reaction to a message
|
||||
- Required inputs:
|
||||
- `channel_id` (string): The channel containing the message
|
||||
- `timestamp` (string): Message timestamp to react to
|
||||
- `reaction` (string): Emoji name without colons
|
||||
- Returns: Reaction confirmation
|
||||
|
||||
5. `slack_get_channel_history`
|
||||
- Get recent messages from a channel
|
||||
- Required inputs:
|
||||
- `channel_id` (string): The channel ID
|
||||
- Optional inputs:
|
||||
- `limit` (number, default: 10): Number of messages to retrieve
|
||||
- Returns: List of messages with their content and metadata
|
||||
|
||||
6. `slack_get_thread_replies`
|
||||
- Get all replies in a message thread
|
||||
- Required inputs:
|
||||
- `channel_id` (string): The channel containing the thread
|
||||
- `thread_ts` (string): Timestamp of the parent message
|
||||
- Returns: List of replies with their content and metadata
|
||||
|
||||
7. `slack_search_messages`
|
||||
- Search for messages across channels
|
||||
- Required inputs:
|
||||
- `query` (string): The search query
|
||||
- Optional inputs:
|
||||
- `count` (number, default: 5): Number of results to return
|
||||
- Returns: Matching messages with their context
|
||||
|
||||
8. `slack_get_users`
|
||||
- Get list of workspace users with basic profile information
|
||||
- Optional inputs:
|
||||
- `cursor` (string): Pagination cursor for next page
|
||||
- `limit` (number, default: 100, max: 200): Maximum users to return
|
||||
- Returns: List of users with their basic profiles
|
||||
|
||||
9. `slack_get_user_profile`
|
||||
- Get detailed profile information for a specific user
|
||||
- Required inputs:
|
||||
- `user_id` (string): The user's ID
|
||||
- Returns: Detailed user profile information
|
||||
|
||||
## Setup
|
||||
|
||||
1. Create a Slack App:
|
||||
- Visit the [Slack Apps page](https://api.slack.com/apps)
|
||||
- Click "Create New App"
|
||||
- Choose "From scratch"
|
||||
- Name your app and select your workspace
|
||||
|
||||
2. Configure Bot Token Scopes:
|
||||
Navigate to "OAuth & Permissions" and add these scopes:
|
||||
- `channels:history` - View messages and other content in public channels
|
||||
- `channels:read` - View basic channel information
|
||||
- `chat:write` - Send messages as the app
|
||||
- `reactions:write` - Add emoji reactions to messages
|
||||
- `users:read` - View users and their basic information
|
||||
|
||||
4. Install App to Workspace:
|
||||
- Click "Install to Workspace" and authorize the app
|
||||
- Save the "Bot User OAuth Token" that starts with `xoxb-`
|
||||
|
||||
5. Get your Team ID (starts with a `T`) by following [this guidance](https://slack.com/help/articles/221769328-Locate-your-Slack-URL-or-ID#find-your-workspace-or-org-id)
|
||||
|
||||
### Usage with the Claude Desktop app
|
||||
Add the following to your `claude_desktop_config.json`:
|
||||
```json
|
||||
{
|
||||
"mcp-server-slack": {
|
||||
"command": "mcp-server-slack",
|
||||
"env": {
|
||||
"SLACK_BOT_TOKEN": "xoxb-your-bot-token",
|
||||
"SLACK_TEAM_ID": "T01234567"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you encounter permission errors, verify that:
|
||||
1. All required scopes are added to your Slack app
|
||||
2. The app is properly installed to your workspace
|
||||
3. The tokens and workspace ID are correctly copied to your configuration
|
||||
4. The app has been added to the channels it needs to access
|
||||
@@ -41,11 +41,6 @@ interface GetThreadRepliesArgs {
|
||||
thread_ts: string;
|
||||
}
|
||||
|
||||
interface SearchMessagesArgs {
|
||||
query: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
interface GetUsersArgs {
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
@@ -180,26 +175,6 @@ const getThreadRepliesTool: Tool = {
|
||||
},
|
||||
};
|
||||
|
||||
const searchMessagesTool: Tool = {
|
||||
name: "slack_search_messages",
|
||||
description: "Search for messages across channels",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
query: {
|
||||
type: "string",
|
||||
description: "The search query",
|
||||
},
|
||||
count: {
|
||||
type: "number",
|
||||
description: "Number of results to return (default 5)",
|
||||
default: 5,
|
||||
},
|
||||
},
|
||||
required: ["query"],
|
||||
},
|
||||
};
|
||||
|
||||
const getUsersTool: Tool = {
|
||||
name: "slack_get_users",
|
||||
description:
|
||||
@@ -237,17 +212,12 @@ const getUserProfileTool: Tool = {
|
||||
|
||||
class SlackClient {
|
||||
private botHeaders: { Authorization: string; "Content-Type": string };
|
||||
private userHeaders: { Authorization: string; "Content-Type": string };
|
||||
|
||||
constructor(botToken: string, userToken: string) {
|
||||
constructor(botToken: string) {
|
||||
this.botHeaders = {
|
||||
Authorization: `Bearer ${botToken}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
this.userHeaders = {
|
||||
Authorization: `Bearer ${userToken}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
}
|
||||
|
||||
async getChannels(limit: number = 100, cursor?: string): Promise<any> {
|
||||
@@ -350,20 +320,6 @@ class SlackClient {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async searchMessages(query: string, count: number = 5): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
query: query,
|
||||
count: count.toString(),
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/search.messages?${params}`,
|
||||
{ headers: this.userHeaders },
|
||||
);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getUsers(limit: number = 100, cursor?: string): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
limit: Math.min(limit, 200).toString(),
|
||||
@@ -398,12 +354,11 @@ class SlackClient {
|
||||
|
||||
async function main() {
|
||||
const botToken = process.env.SLACK_BOT_TOKEN;
|
||||
const userToken = process.env.SLACK_USER_TOKEN;
|
||||
const teamId = process.env.SLACK_TEAM_ID;
|
||||
|
||||
if (!botToken || !userToken || !teamId) {
|
||||
if (!botToken || !teamId) {
|
||||
console.error(
|
||||
"Please set SLACK_BOT_TOKEN, SLACK_USER_TOKEN, and SLACK_TEAM_ID environment variables",
|
||||
"Please set SLACK_BOT_TOKEN and SLACK_TEAM_ID environment variables",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -421,7 +376,7 @@ async function main() {
|
||||
},
|
||||
);
|
||||
|
||||
const slackClient = new SlackClient(botToken, userToken);
|
||||
const slackClient = new SlackClient(botToken);
|
||||
|
||||
server.setRequestHandler(
|
||||
CallToolRequestSchema,
|
||||
@@ -528,21 +483,6 @@ async function main() {
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_search_messages": {
|
||||
const args = request.params
|
||||
.arguments as unknown as SearchMessagesArgs;
|
||||
if (!args.query) {
|
||||
throw new Error("Missing required argument: query");
|
||||
}
|
||||
const response = await slackClient.searchMessages(
|
||||
args.query,
|
||||
args.count,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_get_users": {
|
||||
const args = request.params.arguments as unknown as GetUsersArgs;
|
||||
const response = await slackClient.getUsers(
|
||||
@@ -595,7 +535,6 @@ async function main() {
|
||||
addReactionTool,
|
||||
getChannelHistoryTool,
|
||||
getThreadRepliesTool,
|
||||
searchMessagesTool,
|
||||
getUsersTool,
|
||||
getUserProfileTool,
|
||||
],
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "0.5.0"
|
||||
"@modelcontextprotocol/sdk": "0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shx": "^0.3.4",
|
||||
|
||||
Reference in New Issue
Block a user