@striderlabs/mcp-slack 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +244 -0
- package/package.json +24 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema
|
|
9
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var BOT_TOKEN = process.env.SLACK_BOT_TOKEN;
|
|
12
|
+
var BASE_URL = "https://slack.com/api";
|
|
13
|
+
async function slackRequest(method, endpoint, params) {
|
|
14
|
+
const headers = {
|
|
15
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
16
|
+
};
|
|
17
|
+
if (BOT_TOKEN) {
|
|
18
|
+
headers["Authorization"] = `Bearer ${BOT_TOKEN}`;
|
|
19
|
+
}
|
|
20
|
+
let url = `${BASE_URL}/${endpoint}`;
|
|
21
|
+
let body;
|
|
22
|
+
if (method === "GET" && params) {
|
|
23
|
+
const qs = new URLSearchParams();
|
|
24
|
+
for (const [k, v] of Object.entries(params)) {
|
|
25
|
+
if (v !== void 0) qs.set(k, String(v));
|
|
26
|
+
}
|
|
27
|
+
url += `?${qs}`;
|
|
28
|
+
} else if (method === "POST" && params) {
|
|
29
|
+
body = JSON.stringify(params);
|
|
30
|
+
}
|
|
31
|
+
const res = await fetch(url, { method, headers, body });
|
|
32
|
+
const data = await res.json();
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`Slack HTTP error ${res.status}`);
|
|
35
|
+
}
|
|
36
|
+
if (!data.ok) {
|
|
37
|
+
throw new Error(`Slack API error: ${data.error}`);
|
|
38
|
+
}
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
var server = new Server(
|
|
42
|
+
{ name: "mcp-slack", version: "1.0.0" },
|
|
43
|
+
{ capabilities: { tools: {} } }
|
|
44
|
+
);
|
|
45
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
46
|
+
tools: [
|
|
47
|
+
{
|
|
48
|
+
name: "list_channels",
|
|
49
|
+
description: "List Slack channels",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
limit: { type: "number", description: "Max channels to return (default 100)" },
|
|
54
|
+
cursor: { type: "string", description: "Pagination cursor" },
|
|
55
|
+
types: { type: "string", description: "Channel types: public_channel, private_channel, mpim, im" },
|
|
56
|
+
exclude_archived: { type: "boolean", description: "Exclude archived channels" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "send_message",
|
|
62
|
+
description: "Send a message to a Slack channel",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties: {
|
|
66
|
+
channel: { type: "string", description: "Channel ID or name" },
|
|
67
|
+
text: { type: "string", description: "Message text" },
|
|
68
|
+
blocks: { type: "array", description: "Block Kit blocks" },
|
|
69
|
+
unfurl_links: { type: "boolean", description: "Enable link unfurling" }
|
|
70
|
+
},
|
|
71
|
+
required: ["channel", "text"]
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "list_messages",
|
|
76
|
+
description: "List messages in a Slack channel",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
channel: { type: "string", description: "Channel ID" },
|
|
81
|
+
limit: { type: "number", description: "Max messages to return" },
|
|
82
|
+
cursor: { type: "string", description: "Pagination cursor" },
|
|
83
|
+
oldest: { type: "string", description: "Start of time range (Unix timestamp)" },
|
|
84
|
+
latest: { type: "string", description: "End of time range (Unix timestamp)" }
|
|
85
|
+
},
|
|
86
|
+
required: ["channel"]
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "search_messages",
|
|
91
|
+
description: "Search for messages in Slack",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
query: { type: "string", description: "Search query" },
|
|
96
|
+
count: { type: "number", description: "Number of results per page" },
|
|
97
|
+
page: { type: "number", description: "Page number" },
|
|
98
|
+
sort: { type: "string", description: "Sort by: score or timestamp" },
|
|
99
|
+
sort_dir: { type: "string", description: "Sort direction: asc or desc" }
|
|
100
|
+
},
|
|
101
|
+
required: ["query"]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "list_users",
|
|
106
|
+
description: "List Slack workspace members",
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: "object",
|
|
109
|
+
properties: {
|
|
110
|
+
limit: { type: "number", description: "Max users to return" },
|
|
111
|
+
cursor: { type: "string", description: "Pagination cursor" }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "post_thread_reply",
|
|
117
|
+
description: "Post a reply to a Slack thread",
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {
|
|
121
|
+
channel: { type: "string", description: "Channel ID" },
|
|
122
|
+
thread_ts: { type: "string", description: "Timestamp of the parent message" },
|
|
123
|
+
text: { type: "string", description: "Reply text" },
|
|
124
|
+
blocks: { type: "array", description: "Block Kit blocks" }
|
|
125
|
+
},
|
|
126
|
+
required: ["channel", "thread_ts", "text"]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}));
|
|
131
|
+
var ListChannelsSchema = z.object({
|
|
132
|
+
limit: z.number().optional(),
|
|
133
|
+
cursor: z.string().optional(),
|
|
134
|
+
types: z.string().optional(),
|
|
135
|
+
exclude_archived: z.boolean().optional()
|
|
136
|
+
});
|
|
137
|
+
var SendMessageSchema = z.object({
|
|
138
|
+
channel: z.string(),
|
|
139
|
+
text: z.string(),
|
|
140
|
+
blocks: z.array(z.unknown()).optional(),
|
|
141
|
+
unfurl_links: z.boolean().optional()
|
|
142
|
+
});
|
|
143
|
+
var ListMessagesSchema = z.object({
|
|
144
|
+
channel: z.string(),
|
|
145
|
+
limit: z.number().optional(),
|
|
146
|
+
cursor: z.string().optional(),
|
|
147
|
+
oldest: z.string().optional(),
|
|
148
|
+
latest: z.string().optional()
|
|
149
|
+
});
|
|
150
|
+
var SearchMessagesSchema = z.object({
|
|
151
|
+
query: z.string(),
|
|
152
|
+
count: z.number().optional(),
|
|
153
|
+
page: z.number().optional(),
|
|
154
|
+
sort: z.string().optional(),
|
|
155
|
+
sort_dir: z.string().optional()
|
|
156
|
+
});
|
|
157
|
+
var ListUsersSchema = z.object({
|
|
158
|
+
limit: z.number().optional(),
|
|
159
|
+
cursor: z.string().optional()
|
|
160
|
+
});
|
|
161
|
+
var PostThreadReplySchema = z.object({
|
|
162
|
+
channel: z.string(),
|
|
163
|
+
thread_ts: z.string(),
|
|
164
|
+
text: z.string(),
|
|
165
|
+
blocks: z.array(z.unknown()).optional()
|
|
166
|
+
});
|
|
167
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
168
|
+
const { name, arguments: args } = request.params;
|
|
169
|
+
try {
|
|
170
|
+
switch (name) {
|
|
171
|
+
case "list_channels": {
|
|
172
|
+
const params = ListChannelsSchema.parse(args);
|
|
173
|
+
const result = await slackRequest("GET", "conversations.list", {
|
|
174
|
+
limit: params.limit ?? 100,
|
|
175
|
+
cursor: params.cursor,
|
|
176
|
+
types: params.types ?? "public_channel",
|
|
177
|
+
exclude_archived: params.exclude_archived ?? true
|
|
178
|
+
});
|
|
179
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
180
|
+
}
|
|
181
|
+
case "send_message": {
|
|
182
|
+
const params = SendMessageSchema.parse(args);
|
|
183
|
+
const body = {
|
|
184
|
+
channel: params.channel,
|
|
185
|
+
text: params.text
|
|
186
|
+
};
|
|
187
|
+
if (params.blocks) body.blocks = params.blocks;
|
|
188
|
+
if (params.unfurl_links !== void 0) body.unfurl_links = params.unfurl_links;
|
|
189
|
+
const result = await slackRequest("POST", "chat.postMessage", body);
|
|
190
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
191
|
+
}
|
|
192
|
+
case "list_messages": {
|
|
193
|
+
const params = ListMessagesSchema.parse(args);
|
|
194
|
+
const result = await slackRequest("GET", "conversations.history", {
|
|
195
|
+
channel: params.channel,
|
|
196
|
+
limit: params.limit ?? 100,
|
|
197
|
+
cursor: params.cursor,
|
|
198
|
+
oldest: params.oldest,
|
|
199
|
+
latest: params.latest
|
|
200
|
+
});
|
|
201
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
202
|
+
}
|
|
203
|
+
case "search_messages": {
|
|
204
|
+
const params = SearchMessagesSchema.parse(args);
|
|
205
|
+
const result = await slackRequest("GET", "search.messages", {
|
|
206
|
+
query: params.query,
|
|
207
|
+
count: params.count ?? 20,
|
|
208
|
+
page: params.page ?? 1,
|
|
209
|
+
sort: params.sort ?? "score",
|
|
210
|
+
sort_dir: params.sort_dir ?? "desc"
|
|
211
|
+
});
|
|
212
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
213
|
+
}
|
|
214
|
+
case "list_users": {
|
|
215
|
+
const params = ListUsersSchema.parse(args);
|
|
216
|
+
const result = await slackRequest("GET", "users.list", {
|
|
217
|
+
limit: params.limit ?? 100,
|
|
218
|
+
cursor: params.cursor
|
|
219
|
+
});
|
|
220
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
221
|
+
}
|
|
222
|
+
case "post_thread_reply": {
|
|
223
|
+
const params = PostThreadReplySchema.parse(args);
|
|
224
|
+
const body = {
|
|
225
|
+
channel: params.channel,
|
|
226
|
+
thread_ts: params.thread_ts,
|
|
227
|
+
text: params.text
|
|
228
|
+
};
|
|
229
|
+
if (params.blocks) body.blocks = params.blocks;
|
|
230
|
+
const result = await slackRequest("POST", "chat.postMessage", body);
|
|
231
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
232
|
+
}
|
|
233
|
+
default:
|
|
234
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
235
|
+
}
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return {
|
|
238
|
+
content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
239
|
+
isError: true
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
var transport = new StdioServerTransport();
|
|
244
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@striderlabs/mcp-slack",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP connector for Slack Web API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-slack": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
12
|
+
"dev": "tsup src/index.ts --format esm --watch"
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist"],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "latest",
|
|
17
|
+
"zod": "latest"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "latest",
|
|
21
|
+
"typescript": "latest",
|
|
22
|
+
"@types/node": "latest"
|
|
23
|
+
}
|
|
24
|
+
}
|