mirror of
https://github.com/open-webui/openapi-servers
synced 2025-06-26 18:17:04 +00:00
Delete servers/slack/slack.ts
This commit is contained in:
parent
fd91c939f2
commit
fa3eda516e
@ -1,582 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequest,
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
Tool,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
|
||||
// Type definitions for tool arguments
|
||||
interface ListChannelsArgs {
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
}
|
||||
|
||||
interface PostMessageArgs {
|
||||
channel_id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface ReplyToThreadArgs {
|
||||
channel_id: string;
|
||||
thread_ts: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface AddReactionArgs {
|
||||
channel_id: string;
|
||||
timestamp: string;
|
||||
reaction: string;
|
||||
}
|
||||
|
||||
interface GetChannelHistoryArgs {
|
||||
channel_id: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
interface GetThreadRepliesArgs {
|
||||
channel_id: string;
|
||||
thread_ts: string;
|
||||
}
|
||||
|
||||
interface GetUsersArgs {
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
interface GetUserProfileArgs {
|
||||
user_id: string;
|
||||
}
|
||||
|
||||
// Tool definitions
|
||||
const listChannelsTool: Tool = {
|
||||
name: "slack_list_channels",
|
||||
description: "List public or pre-defined channels in the workspace with pagination",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
limit: {
|
||||
type: "number",
|
||||
description:
|
||||
"Maximum number of channels to return (default 100, max 200)",
|
||||
default: 100,
|
||||
},
|
||||
cursor: {
|
||||
type: "string",
|
||||
description: "Pagination cursor for next page of results",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const postMessageTool: Tool = {
|
||||
name: "slack_post_message",
|
||||
description: "Post a new message to a Slack channel",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
channel_id: {
|
||||
type: "string",
|
||||
description: "The ID of the channel to post to",
|
||||
},
|
||||
text: {
|
||||
type: "string",
|
||||
description: "The message text to post",
|
||||
},
|
||||
},
|
||||
required: ["channel_id", "text"],
|
||||
},
|
||||
};
|
||||
|
||||
const replyToThreadTool: Tool = {
|
||||
name: "slack_reply_to_thread",
|
||||
description: "Reply to a specific message thread in Slack",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
channel_id: {
|
||||
type: "string",
|
||||
description: "The ID of the channel containing the thread",
|
||||
},
|
||||
thread_ts: {
|
||||
type: "string",
|
||||
description: "The timestamp of the parent message in the format '1234567890.123456'. Timestamps in the format without the period can be converted by adding the period such that 6 numbers come after it.",
|
||||
},
|
||||
text: {
|
||||
type: "string",
|
||||
description: "The reply text",
|
||||
},
|
||||
},
|
||||
required: ["channel_id", "thread_ts", "text"],
|
||||
},
|
||||
};
|
||||
|
||||
const addReactionTool: Tool = {
|
||||
name: "slack_add_reaction",
|
||||
description: "Add a reaction emoji to a message",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
channel_id: {
|
||||
type: "string",
|
||||
description: "The ID of the channel containing the message",
|
||||
},
|
||||
timestamp: {
|
||||
type: "string",
|
||||
description: "The timestamp of the message to react to",
|
||||
},
|
||||
reaction: {
|
||||
type: "string",
|
||||
description: "The name of the emoji reaction (without ::)",
|
||||
},
|
||||
},
|
||||
required: ["channel_id", "timestamp", "reaction"],
|
||||
},
|
||||
};
|
||||
|
||||
const getChannelHistoryTool: Tool = {
|
||||
name: "slack_get_channel_history",
|
||||
description: "Get recent messages from a channel",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
channel_id: {
|
||||
type: "string",
|
||||
description: "The ID of the channel",
|
||||
},
|
||||
limit: {
|
||||
type: "number",
|
||||
description: "Number of messages to retrieve (default 10)",
|
||||
default: 10,
|
||||
},
|
||||
},
|
||||
required: ["channel_id"],
|
||||
},
|
||||
};
|
||||
|
||||
const getThreadRepliesTool: Tool = {
|
||||
name: "slack_get_thread_replies",
|
||||
description: "Get all replies in a message thread",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
channel_id: {
|
||||
type: "string",
|
||||
description: "The ID of the channel containing the thread",
|
||||
},
|
||||
thread_ts: {
|
||||
type: "string",
|
||||
description: "The timestamp of the parent message in the format '1234567890.123456'. Timestamps in the format without the period can be converted by adding the period such that 6 numbers come after it.",
|
||||
},
|
||||
},
|
||||
required: ["channel_id", "thread_ts"],
|
||||
},
|
||||
};
|
||||
|
||||
const getUsersTool: Tool = {
|
||||
name: "slack_get_users",
|
||||
description:
|
||||
"Get a list of all users in the workspace with their basic profile information",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
cursor: {
|
||||
type: "string",
|
||||
description: "Pagination cursor for next page of results",
|
||||
},
|
||||
limit: {
|
||||
type: "number",
|
||||
description: "Maximum number of users to return (default 100, max 200)",
|
||||
default: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const getUserProfileTool: Tool = {
|
||||
name: "slack_get_user_profile",
|
||||
description: "Get detailed profile information for a specific user",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
user_id: {
|
||||
type: "string",
|
||||
description: "The ID of the user",
|
||||
},
|
||||
},
|
||||
required: ["user_id"],
|
||||
},
|
||||
};
|
||||
|
||||
class SlackClient {
|
||||
private botHeaders: { Authorization: string; "Content-Type": string };
|
||||
|
||||
constructor(botToken: string) {
|
||||
this.botHeaders = {
|
||||
Authorization: `Bearer ${botToken}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
}
|
||||
|
||||
async getChannels(limit: number = 100, cursor?: string): Promise<any> {
|
||||
const predefinedChannelIds = process.env.SLACK_CHANNEL_IDS;
|
||||
if (!predefinedChannelIds) {
|
||||
const params = new URLSearchParams({
|
||||
types: "public_channel",
|
||||
exclude_archived: "true",
|
||||
limit: Math.min(limit, 200).toString(),
|
||||
team_id: process.env.SLACK_TEAM_ID!,
|
||||
});
|
||||
|
||||
if (cursor) {
|
||||
params.append("cursor", cursor);
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/conversations.list?${params}`,
|
||||
{ headers: this.botHeaders },
|
||||
);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
const predefinedChannelIdsArray = predefinedChannelIds.split(",").map((id: string) => id.trim());
|
||||
const channels = [];
|
||||
|
||||
for (const channelId of predefinedChannelIdsArray) {
|
||||
const params = new URLSearchParams({
|
||||
channel: channelId,
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/conversations.info?${params}`,
|
||||
{ headers: this.botHeaders }
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.ok && data.channel && !data.channel.is_archived) {
|
||||
channels.push(data.channel);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
channels: channels,
|
||||
response_metadata: { next_cursor: "" },
|
||||
};
|
||||
}
|
||||
|
||||
async postMessage(channel_id: string, text: string): Promise<any> {
|
||||
const response = await fetch("https://slack.com/api/chat.postMessage", {
|
||||
method: "POST",
|
||||
headers: this.botHeaders,
|
||||
body: JSON.stringify({
|
||||
channel: channel_id,
|
||||
text: text,
|
||||
}),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async postReply(
|
||||
channel_id: string,
|
||||
thread_ts: string,
|
||||
text: string,
|
||||
): Promise<any> {
|
||||
const response = await fetch("https://slack.com/api/chat.postMessage", {
|
||||
method: "POST",
|
||||
headers: this.botHeaders,
|
||||
body: JSON.stringify({
|
||||
channel: channel_id,
|
||||
thread_ts: thread_ts,
|
||||
text: text,
|
||||
}),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async addReaction(
|
||||
channel_id: string,
|
||||
timestamp: string,
|
||||
reaction: string,
|
||||
): Promise<any> {
|
||||
const response = await fetch("https://slack.com/api/reactions.add", {
|
||||
method: "POST",
|
||||
headers: this.botHeaders,
|
||||
body: JSON.stringify({
|
||||
channel: channel_id,
|
||||
timestamp: timestamp,
|
||||
name: reaction,
|
||||
}),
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getChannelHistory(
|
||||
channel_id: string,
|
||||
limit: number = 10,
|
||||
): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
channel: channel_id,
|
||||
limit: limit.toString(),
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/conversations.history?${params}`,
|
||||
{ headers: this.botHeaders },
|
||||
);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getThreadReplies(channel_id: string, thread_ts: string): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
channel: channel_id,
|
||||
ts: thread_ts,
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/conversations.replies?${params}`,
|
||||
{ headers: this.botHeaders },
|
||||
);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getUsers(limit: number = 100, cursor?: string): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
limit: Math.min(limit, 200).toString(),
|
||||
team_id: process.env.SLACK_TEAM_ID!,
|
||||
});
|
||||
|
||||
if (cursor) {
|
||||
params.append("cursor", cursor);
|
||||
}
|
||||
|
||||
const response = await fetch(`https://slack.com/api/users.list?${params}`, {
|
||||
headers: this.botHeaders,
|
||||
});
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getUserProfile(user_id: string): Promise<any> {
|
||||
const params = new URLSearchParams({
|
||||
user: user_id,
|
||||
include_labels: "true",
|
||||
});
|
||||
|
||||
const response = await fetch(
|
||||
`https://slack.com/api/users.profile.get?${params}`,
|
||||
{ headers: this.botHeaders },
|
||||
);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const botToken = process.env.SLACK_BOT_TOKEN;
|
||||
const teamId = process.env.SLACK_TEAM_ID;
|
||||
|
||||
if (!botToken || !teamId) {
|
||||
console.error(
|
||||
"Please set SLACK_BOT_TOKEN and SLACK_TEAM_ID environment variables",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.error("Starting Slack MCP Server...");
|
||||
const server = new Server(
|
||||
{
|
||||
name: "Slack MCP Server",
|
||||
version: "1.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const slackClient = new SlackClient(botToken);
|
||||
|
||||
server.setRequestHandler(
|
||||
CallToolRequestSchema,
|
||||
async (request: CallToolRequest) => {
|
||||
console.error("Received CallToolRequest:", request);
|
||||
try {
|
||||
if (!request.params.arguments) {
|
||||
throw new Error("No arguments provided");
|
||||
}
|
||||
|
||||
switch (request.params.name) {
|
||||
case "slack_list_channels": {
|
||||
const args = request.params
|
||||
.arguments as unknown as ListChannelsArgs;
|
||||
const response = await slackClient.getChannels(
|
||||
args.limit,
|
||||
args.cursor,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_post_message": {
|
||||
const args = request.params.arguments as unknown as PostMessageArgs;
|
||||
if (!args.channel_id || !args.text) {
|
||||
throw new Error(
|
||||
"Missing required arguments: channel_id and text",
|
||||
);
|
||||
}
|
||||
const response = await slackClient.postMessage(
|
||||
args.channel_id,
|
||||
args.text,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_reply_to_thread": {
|
||||
const args = request.params
|
||||
.arguments as unknown as ReplyToThreadArgs;
|
||||
if (!args.channel_id || !args.thread_ts || !args.text) {
|
||||
throw new Error(
|
||||
"Missing required arguments: channel_id, thread_ts, and text",
|
||||
);
|
||||
}
|
||||
const response = await slackClient.postReply(
|
||||
args.channel_id,
|
||||
args.thread_ts,
|
||||
args.text,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_add_reaction": {
|
||||
const args = request.params.arguments as unknown as AddReactionArgs;
|
||||
if (!args.channel_id || !args.timestamp || !args.reaction) {
|
||||
throw new Error(
|
||||
"Missing required arguments: channel_id, timestamp, and reaction",
|
||||
);
|
||||
}
|
||||
const response = await slackClient.addReaction(
|
||||
args.channel_id,
|
||||
args.timestamp,
|
||||
args.reaction,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_get_channel_history": {
|
||||
const args = request.params
|
||||
.arguments as unknown as GetChannelHistoryArgs;
|
||||
if (!args.channel_id) {
|
||||
throw new Error("Missing required argument: channel_id");
|
||||
}
|
||||
const response = await slackClient.getChannelHistory(
|
||||
args.channel_id,
|
||||
args.limit,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_get_thread_replies": {
|
||||
const args = request.params
|
||||
.arguments as unknown as GetThreadRepliesArgs;
|
||||
if (!args.channel_id || !args.thread_ts) {
|
||||
throw new Error(
|
||||
"Missing required arguments: channel_id and thread_ts",
|
||||
);
|
||||
}
|
||||
const response = await slackClient.getThreadReplies(
|
||||
args.channel_id,
|
||||
args.thread_ts,
|
||||
);
|
||||
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(
|
||||
args.limit,
|
||||
args.cursor,
|
||||
);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "slack_get_user_profile": {
|
||||
const args = request.params
|
||||
.arguments as unknown as GetUserProfileArgs;
|
||||
if (!args.user_id) {
|
||||
throw new Error("Missing required argument: user_id");
|
||||
}
|
||||
const response = await slackClient.getUserProfile(args.user_id);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(response) }],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error executing tool:", error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
console.error("Received ListToolsRequest");
|
||||
return {
|
||||
tools: [
|
||||
listChannelsTool,
|
||||
postMessageTool,
|
||||
replyToThreadTool,
|
||||
addReactionTool,
|
||||
getChannelHistoryTool,
|
||||
getThreadRepliesTool,
|
||||
getUsersTool,
|
||||
getUserProfileTool,
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
console.error("Connecting server to transport...");
|
||||
await server.connect(transport);
|
||||
|
||||
console.error("Slack MCP Server running on stdio");
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error in main():", error);
|
||||
process.exit(1);
|
||||
});
|
Loading…
Reference in New Issue
Block a user