@jtalk22/slack-mcp 3.0.0 → 3.2.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.
Files changed (59) hide show
  1. package/README.md +63 -28
  2. package/docs/SETUP.md +64 -29
  3. package/docs/TROUBLESHOOTING.md +28 -0
  4. package/lib/handlers.js +156 -0
  5. package/lib/slack-client.js +11 -3
  6. package/lib/token-store.js +6 -5
  7. package/lib/tools.js +131 -0
  8. package/package.json +35 -36
  9. package/public/index.html +10 -6
  10. package/public/share.html +128 -0
  11. package/scripts/setup-wizard.js +1 -1
  12. package/server.json +10 -4
  13. package/src/server-http.js +16 -1
  14. package/src/server.js +31 -7
  15. package/src/web-server.js +119 -4
  16. package/docs/CLOUDFLARE-BROWSER-TOOLKIT.md +0 -67
  17. package/docs/COMMUNICATION-STYLE.md +0 -66
  18. package/docs/COMPATIBILITY.md +0 -19
  19. package/docs/DEPLOYMENT-MODES.md +0 -55
  20. package/docs/HN-LAUNCH.md +0 -72
  21. package/docs/INDEX.md +0 -40
  22. package/docs/INSTALL-PROOF.md +0 -18
  23. package/docs/LAUNCH-COPY-v3.0.0.md +0 -73
  24. package/docs/LAUNCH-MATRIX.md +0 -22
  25. package/docs/LAUNCH-OPS.md +0 -71
  26. package/docs/RELEASE-HEALTH.md +0 -90
  27. package/docs/SUPPORT-BOUNDARIES.md +0 -49
  28. package/docs/USE_CASE_RECIPES.md +0 -69
  29. package/docs/WEB-API.md +0 -303
  30. package/docs/images/demo-channel-messages.png +0 -0
  31. package/docs/images/demo-channels.png +0 -0
  32. package/docs/images/demo-claude-mobile-360x800.png +0 -0
  33. package/docs/images/demo-claude-mobile-390x844.png +0 -0
  34. package/docs/images/demo-main-mobile-360x800.png +0 -0
  35. package/docs/images/demo-main-mobile-390x844.png +0 -0
  36. package/docs/images/demo-main.png +0 -0
  37. package/docs/images/demo-messages.png +0 -0
  38. package/docs/images/demo-poster.png +0 -0
  39. package/docs/images/demo-sidebar.png +0 -0
  40. package/docs/images/diagram-oauth-comparison.svg +0 -80
  41. package/docs/images/diagram-session-flow.svg +0 -105
  42. package/docs/images/web-api-mobile-360x800.png +0 -0
  43. package/docs/images/web-api-mobile-390x844.png +0 -0
  44. package/public/demo-claude.html +0 -1958
  45. package/public/demo-video.html +0 -235
  46. package/public/demo.html +0 -1196
  47. package/scripts/build-release-health-delta.js +0 -201
  48. package/scripts/capture-screenshots.js +0 -146
  49. package/scripts/check-owner-attribution.sh +0 -80
  50. package/scripts/check-public-language.sh +0 -25
  51. package/scripts/check-version-parity.js +0 -176
  52. package/scripts/cloudflare-browser-tool.js +0 -237
  53. package/scripts/collect-release-health.js +0 -150
  54. package/scripts/record-demo.js +0 -162
  55. package/scripts/release-preflight.js +0 -243
  56. package/scripts/setup-git-hooks.sh +0 -15
  57. package/scripts/verify-core.js +0 -159
  58. package/scripts/verify-install-flow.js +0 -193
  59. package/scripts/verify-web.js +0 -269
package/lib/tools.js CHANGED
@@ -268,5 +268,136 @@ export const TOOLS = [
268
268
  idempotentHint: true,
269
269
  openWorldHint: true
270
270
  }
271
+ },
272
+ {
273
+ name: "slack_add_reaction",
274
+ description: "Add an emoji reaction to a message",
275
+ inputSchema: {
276
+ type: "object",
277
+ properties: {
278
+ channel_id: {
279
+ type: "string",
280
+ description: "Channel or DM ID containing the message"
281
+ },
282
+ timestamp: {
283
+ type: "string",
284
+ description: "Message timestamp to react to"
285
+ },
286
+ reaction: {
287
+ type: "string",
288
+ description: "Emoji name without colons (e.g., 'thumbsup', 'eyes', 'white_check_mark')"
289
+ }
290
+ },
291
+ required: ["channel_id", "timestamp", "reaction"]
292
+ },
293
+ annotations: {
294
+ title: "Add Reaction",
295
+ readOnlyHint: false,
296
+ destructiveHint: false,
297
+ idempotentHint: true,
298
+ openWorldHint: true
299
+ }
300
+ },
301
+ {
302
+ name: "slack_remove_reaction",
303
+ description: "Remove an emoji reaction from a message",
304
+ inputSchema: {
305
+ type: "object",
306
+ properties: {
307
+ channel_id: {
308
+ type: "string",
309
+ description: "Channel or DM ID containing the message"
310
+ },
311
+ timestamp: {
312
+ type: "string",
313
+ description: "Message timestamp to remove reaction from"
314
+ },
315
+ reaction: {
316
+ type: "string",
317
+ description: "Emoji name without colons (e.g., 'thumbsup', 'eyes')"
318
+ }
319
+ },
320
+ required: ["channel_id", "timestamp", "reaction"]
321
+ },
322
+ annotations: {
323
+ title: "Remove Reaction",
324
+ readOnlyHint: false,
325
+ destructiveHint: false,
326
+ idempotentHint: true,
327
+ openWorldHint: true
328
+ }
329
+ },
330
+ {
331
+ name: "slack_conversations_mark",
332
+ description: "Mark a conversation as read up to a specific message timestamp",
333
+ inputSchema: {
334
+ type: "object",
335
+ properties: {
336
+ channel_id: {
337
+ type: "string",
338
+ description: "Channel or DM ID to mark as read"
339
+ },
340
+ timestamp: {
341
+ type: "string",
342
+ description: "Message timestamp to mark as read up to (all messages at or before this are marked read)"
343
+ }
344
+ },
345
+ required: ["channel_id", "timestamp"]
346
+ },
347
+ annotations: {
348
+ title: "Mark as Read",
349
+ readOnlyHint: false,
350
+ destructiveHint: false,
351
+ idempotentHint: true,
352
+ openWorldHint: true
353
+ }
354
+ },
355
+ {
356
+ name: "slack_conversations_unreads",
357
+ description: "Get channels and DMs with unread messages, sorted by unread count (highest first)",
358
+ inputSchema: {
359
+ type: "object",
360
+ properties: {
361
+ types: {
362
+ type: "string",
363
+ description: "Comma-separated types: im, mpim, public_channel, private_channel (default all)",
364
+ default: "im,mpim,public_channel,private_channel"
365
+ },
366
+ limit: {
367
+ type: "number",
368
+ description: "Maximum conversations to return (default 50)"
369
+ }
370
+ }
371
+ },
372
+ annotations: {
373
+ title: "Unread Conversations",
374
+ readOnlyHint: true,
375
+ idempotentHint: true,
376
+ openWorldHint: true
377
+ }
378
+ },
379
+ {
380
+ name: "slack_users_search",
381
+ description: "Search workspace users by name, display name, or email. Case-insensitive partial match.",
382
+ inputSchema: {
383
+ type: "object",
384
+ properties: {
385
+ query: {
386
+ type: "string",
387
+ description: "Search term to match against name, display name, real name, or email"
388
+ },
389
+ limit: {
390
+ type: "number",
391
+ description: "Maximum results to return (default 20)"
392
+ }
393
+ },
394
+ required: ["query"]
395
+ },
396
+ annotations: {
397
+ title: "Search Users",
398
+ readOnlyHint: true,
399
+ idempotentHint: true,
400
+ openWorldHint: true
401
+ }
271
402
  }
272
403
  ];
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@jtalk22/slack-mcp",
3
3
  "mcpName": "io.github.jtalk22/slack-mcp-server",
4
- "version": "3.0.0",
5
- "description": "Session-based Slack access for Claude - DMs, channels, search, and threads. Local-first with your existing Slack session.",
4
+ "version": "3.2.0",
5
+ "description": "Session-based Slack MCP for Claude and MCP clients: local-first workflows, secure-default HTTP.",
6
6
  "type": "module",
7
7
  "main": "src/server.js",
8
8
  "bin": {
@@ -24,56 +24,52 @@
24
24
  "tokens:auto": "node scripts/token-cli.js auto",
25
25
  "tokens:clear": "node scripts/token-cli.js clear",
26
26
  "screenshot": "node scripts/capture-screenshots.js",
27
+ "build:social-preview": "node scripts/build-social-preview.js",
28
+ "build:demo-mobile": "node scripts/build-mobile-demo.js",
29
+ "build:demo-mobile:gif": "node scripts/build-mobile-demo.js --gif",
27
30
  "record-demo": "node scripts/record-demo.js",
31
+ "social-preview:update": "node scripts/update-github-social-preview.js --headed",
28
32
  "cf:browser": "node scripts/cloudflare-browser-tool.js",
29
33
  "metrics:release-health": "node scripts/collect-release-health.js",
30
34
  "metrics:release-health:delta": "node scripts/build-release-health-delta.js",
35
+ "impact:push:v3": "node scripts/impact-push-v3.js --dry-run",
36
+ "impact:push:v3:apply": "node scripts/impact-push-v3.js --apply",
31
37
  "verify:version-parity": "node scripts/check-version-parity.js",
32
38
  "verify:release-dry-run": "node scripts/release-preflight.js"
33
39
  },
34
40
  "keywords": [
41
+ "claude",
35
42
  "mcp",
36
- "mcp-server",
37
43
  "model-context-protocol",
38
44
  "slack",
39
45
  "slack-api",
40
- "slack-mcp",
41
- "slack-integration",
42
- "claude",
43
46
  "claude-desktop",
44
- "claude-code",
45
- "claude-connectors",
46
- "anthropic",
47
- "cursor",
48
- "llm",
49
- "automation",
50
- "workflow-automation",
51
- "developer-tools",
52
47
  "cli",
53
- "productivity",
54
- "messaging",
55
- "message-search",
56
- "direct-messages",
57
- "channels",
58
- "workspace",
48
+ "developer-tools",
49
+ "mcp-server",
59
50
  "session-based",
51
+ "claude-code",
52
+ "local-first",
60
53
  "session-mirroring",
61
- "slack-dm",
62
- "slack-threads",
63
- "workspace-search",
64
- "mcp-tools",
65
- "mcp-stdio",
66
- "mcp-http",
67
- "remote-mcp",
68
- "open-source"
54
+ "slack-mcp",
55
+ "secure-by-default",
56
+ "llm",
57
+ "slack-integration",
58
+ "ai-agents",
59
+ "automation",
60
+ "productivity"
69
61
  ],
70
- "author": "jtalk22",
62
+ "author": {
63
+ "name": "James Lambert",
64
+ "email": "james@revasser.nyc",
65
+ "url": "https://github.com/jtalk22"
66
+ },
71
67
  "license": "MIT",
72
68
  "repository": {
73
69
  "type": "git",
74
70
  "url": "git+https://github.com/jtalk22/slack-mcp-server.git"
75
71
  },
76
- "homepage": "https://jtalk22.github.io/slack-mcp-server/public/demo.html",
72
+ "homepage": "https://jtalk22.github.io/slack-mcp-server/",
77
73
  "bugs": {
78
74
  "url": "https://github.com/jtalk22/slack-mcp-server/issues"
79
75
  },
@@ -87,12 +83,15 @@
87
83
  "files": [
88
84
  "src/",
89
85
  "lib/",
90
- "public/",
91
- "scripts/",
92
- "docs/*.md",
93
- "docs/assets/",
94
- "docs/images/*.png",
95
- "docs/images/*.svg",
86
+ "public/index.html",
87
+ "public/share.html",
88
+ "scripts/setup-wizard.js",
89
+ "scripts/token-cli.js",
90
+ "docs/SETUP.md",
91
+ "docs/API.md",
92
+ "docs/TROUBLESHOOTING.md",
93
+ "docs/assets/icon.svg",
94
+ "docs/assets/icon-512.png",
96
95
  "README.md",
97
96
  "LICENSE",
98
97
  "server.json",
package/public/index.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Slack Web API</title>
6
+ <title>Slack MCP Server — Web Dashboard</title>
7
7
  <style>
8
8
  @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=Space+Grotesk:wght@500;600;700&display=swap');
9
9
 
@@ -253,7 +253,11 @@
253
253
  </div>
254
254
 
255
255
  <div class="container">
256
- <h1>Slack Web API <span id="status" class="status"></span></h1>
256
+ <h1>Slack Web API <span style="font-size:0.55em;opacity:0.5;font-weight:400;vertical-align:middle">v3.2.0</span> <span id="status" class="status"></span></h1>
257
+ <div style="background:rgba(240,194,70,0.08);border:1px solid rgba(240,194,70,0.2);border-radius:8px;padding:8px 14px;margin-bottom:16px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;font-size:13px;color:#d4c48a">
258
+ <span>Skip local setup? <strong style="color:#f0c246">Slack MCP Cloud</strong> gives you 16 tools with one URL — no tokens to manage.</span>
259
+ <a href="https://jtalk22.github.io/slack-mcp-server/cloud.html" style="color:#f0c246;font-weight:600;text-decoration:none;white-space:nowrap" target="_blank">Learn more &rarr;</a>
260
+ </div>
257
261
  <div class="grid">
258
262
  <div class="sidebar">
259
263
  <h3>CONVERSATIONS</h3>
@@ -267,7 +271,7 @@
267
271
  </div>
268
272
  <div class="main-panel">
269
273
  <div class="search-section">
270
- <input type="text" id="searchQuery" placeholder="Search messages...">
274
+ <input type="text" id="searchQuery" placeholder="Search messages..." onkeypress="if(event.key==='Enter')searchMessages()">
271
275
  <button onclick="searchMessages()">Search</button>
272
276
  </div>
273
277
  <h2 id="channelName">Select a conversation</h2>
@@ -377,7 +381,7 @@
377
381
  try {
378
382
  const data = await api('/conversations?types=' + types);
379
383
  list.innerHTML = data.conversations.map(c =>
380
- '<li onclick="loadHistory(\'' + c.id + '\', \'' + c.name.replace(/'/g, "\\'") + '\', this)"><div>' + c.name + '</div><div class="type">' + c.type + '</div></li>'
384
+ '<li onclick="loadHistory(\'' + c.id + '\', \'' + escapeHtml(c.name).replace(/'/g, "&#39;") + '\', this)"><div>' + escapeHtml(c.name) + '</div><div class="type">' + escapeHtml(c.type) + '</div></li>'
381
385
  ).join('');
382
386
  } catch (e) { list.innerHTML = '<li class="error-msg">' + e.message + '</li>'; }
383
387
  }
@@ -397,7 +401,7 @@
397
401
  const container = document.getElementById('messages');
398
402
  if (!messages || messages.length === 0) { container.innerHTML = '<div class="loading">No messages</div>'; return; }
399
403
  container.innerHTML = messages.map(m =>
400
- '<div class="message"><div class="header"><span class="user">' + (m.user || m.user_id || 'Unknown') + '</span><span class="time">' + new Date(m.datetime).toLocaleString() + '</span></div><div class="text">' + escapeHtml(m.text || '') + '</div></div>'
404
+ '<div class="message"><div class="header"><span class="user">' + escapeHtml(m.user || m.user_id || 'Unknown') + '</span><span class="time">' + new Date(m.datetime).toLocaleString() + '</span></div><div class="text">' + escapeHtml(m.text || '') + '</div></div>'
401
405
  ).join('');
402
406
  container.scrollTop = container.scrollHeight;
403
407
  }
@@ -423,7 +427,7 @@
423
427
  const data = await api('/search?q=' + encodeURIComponent(query));
424
428
  if (data.matches && data.matches.length > 0) {
425
429
  container.innerHTML = data.matches.map(m =>
426
- '<div class="message"><div class="header"><span class="user">' + (m.user || 'Unknown') + ' in #' + m.channel + '</span><span class="time">' + new Date(m.datetime).toLocaleString() + '</span></div><div class="text">' + escapeHtml(m.text || '') + '</div></div>'
430
+ '<div class="message"><div class="header"><span class="user">' + escapeHtml(m.user || 'Unknown') + ' in #' + escapeHtml(m.channel || '') + '</span><span class="time">' + new Date(m.datetime).toLocaleString() + '</span></div><div class="text">' + escapeHtml(m.text || '') + '</div></div>'
427
431
  ).join('');
428
432
  } else { container.innerHTML = '<div class="loading">No results found</div>'; }
429
433
  } catch (e) { container.innerHTML = '<div class="error-msg">' + e.message + '</div>'; }
@@ -0,0 +1,128 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Slack MCP Server v3.2.0</title>
7
+ <meta name="description" content="Session-based Slack MCP for Claude. Local-first stdio/web with secure-default hosted HTTP in v3.">
8
+ <meta property="og:type" content="website">
9
+ <meta property="og:title" content="Slack MCP Server v3.2.0">
10
+ <meta property="og:description" content="Session-based Slack MCP for Claude. Local-first stdio/web with secure-default hosted HTTP in v3.">
11
+ <meta property="og:url" content="https://jtalk22.github.io/slack-mcp-server/public/share.html">
12
+ <meta property="og:image" content="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png">
13
+ <meta property="og:image:width" content="1280">
14
+ <meta property="og:image:height" content="640">
15
+ <meta name="twitter:card" content="summary_large_image">
16
+ <meta name="twitter:title" content="Slack MCP Server v3.2.0">
17
+ <meta name="twitter:description" content="Session-based Slack MCP for Claude. Local-first stdio/web with secure-default hosted HTTP in v3.">
18
+ <meta name="twitter:image" content="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png">
19
+ <style>
20
+ :root {
21
+ --bg-1: #0b1436;
22
+ --bg-2: #0e1d49;
23
+ --line: rgba(131, 161, 224, 0.36);
24
+ --text: #edf4ff;
25
+ --muted: #b4c4e8;
26
+ --link-bg: rgba(17, 57, 120, 0.7);
27
+ --link-bg-hover: rgba(22, 71, 148, 0.85);
28
+ --accent: #54d8cf;
29
+ }
30
+ * { box-sizing: border-box; }
31
+ body {
32
+ margin: 0;
33
+ min-height: 100vh;
34
+ color: var(--text);
35
+ background:
36
+ radial-gradient(900px 430px at 12% 0%, #2b4f98 0%, transparent 60%),
37
+ radial-gradient(980px 480px at 100% 100%, #124b8c 0%, transparent 64%),
38
+ linear-gradient(145deg, var(--bg-1), var(--bg-2));
39
+ font-family: "Space Grotesk", "IBM Plex Sans", "Segoe UI", Arial, sans-serif;
40
+ display: grid;
41
+ place-items: center;
42
+ padding: 20px;
43
+ }
44
+ .wrap {
45
+ width: min(980px, 100%);
46
+ border: 1px solid var(--line);
47
+ border-radius: 16px;
48
+ background: linear-gradient(165deg, rgba(17, 41, 92, 0.72), rgba(10, 22, 56, 0.9));
49
+ box-shadow: 0 18px 38px rgba(0, 0, 0, 0.28);
50
+ padding: 16px;
51
+ }
52
+ h1 {
53
+ margin: 0;
54
+ line-height: 1.08;
55
+ letter-spacing: -0.02em;
56
+ font-size: clamp(30px, 5vw, 48px);
57
+ }
58
+ .sub {
59
+ margin: 8px 0 14px;
60
+ color: var(--muted);
61
+ font-size: clamp(16px, 2.4vw, 22px);
62
+ line-height: 1.25;
63
+ }
64
+ .preview {
65
+ display: block;
66
+ border-radius: 12px;
67
+ overflow: hidden;
68
+ border: 1px solid rgba(135, 163, 225, 0.4);
69
+ text-decoration: none;
70
+ margin-bottom: 14px;
71
+ }
72
+ .preview img {
73
+ width: 100%;
74
+ display: block;
75
+ }
76
+ .links {
77
+ display: flex;
78
+ flex-wrap: wrap;
79
+ gap: 10px;
80
+ margin-bottom: 8px;
81
+ }
82
+ .links a {
83
+ display: inline-block;
84
+ text-decoration: none;
85
+ border: 1px solid rgba(131, 161, 224, 0.5);
86
+ border-radius: 10px;
87
+ padding: 9px 12px;
88
+ color: var(--text);
89
+ background: var(--link-bg);
90
+ font-weight: 600;
91
+ font-size: 14px;
92
+ }
93
+ .links a:hover { background: var(--link-bg-hover); }
94
+ .note {
95
+ color: #9fb4de;
96
+ font-size: 13px;
97
+ line-height: 1.45;
98
+ }
99
+ .note strong { color: var(--accent); }
100
+ @media (max-width: 640px) {
101
+ body { padding: 10px; }
102
+ .wrap { padding: 12px; }
103
+ }
104
+ </style>
105
+ </head>
106
+ <body>
107
+ <main class="wrap">
108
+ <h1>Slack MCP Server v3.2.0</h1>
109
+ <p class="sub">Give Claude full access to your Slack. Read channels, search messages, send replies, get AI summaries. Self-host free or Cloud from $19/mo.</p>
110
+
111
+ <a class="preview" href="https://github.com/jtalk22/slack-mcp-server" rel="noopener">
112
+ <img src="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png" alt="Slack MCP Server social preview card">
113
+ </a>
114
+
115
+ <div class="links">
116
+ <a href="https://github.com/jtalk22/slack-mcp-server/blob/main/docs/SETUP.md" rel="noopener">Install (`--setup`)</a>
117
+ <a href="https://github.com/jtalk22/slack-mcp-server/blob/main/README.md#install--verify" rel="noopener">Verify (`--version/--doctor/--status`)</a>
118
+ <a href="https://github.com/jtalk22/slack-mcp-server/releases/latest" rel="noopener">Latest Release</a>
119
+ <a href="https://jtalk22.github.io/slack-mcp-server/" rel="noopener">Autoplay Demo Landing</a>
120
+ <a href="https://jtalk22.github.io/slack-mcp-server/docs/videos/demo-claude-mobile-20s.mp4" rel="noopener">20s Mobile Clip</a>
121
+ <a href="https://www.npmjs.com/package/@jtalk22/slack-mcp" rel="noopener">npm Package</a>
122
+ <a href="https://jtalk22.github.io/slack-mcp-server/cloud.html" rel="noopener" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">Cloud ($19/mo)</a>
123
+ </div>
124
+
125
+ <p class="note"><strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Maintainer/operator: <code>jtalk22</code> (<code>james@revasser.nyc</code>).</p>
126
+ </main>
127
+ </body>
128
+ </html>
@@ -23,7 +23,7 @@ import {
23
23
  } from "../lib/token-store.js";
24
24
 
25
25
  const IS_MACOS = platform() === 'darwin';
26
- const VERSION = "3.0.0";
26
+ const VERSION = "3.2.0";
27
27
  const MIN_NODE_MAJOR = 20;
28
28
  const AUTH_TEST_URL = process.env.SLACK_MCP_AUTH_TEST_URL || "https://slack.com/api/auth.test";
29
29
 
package/server.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.jtalk22/slack-mcp-server",
4
4
  "title": "Slack MCP Server",
5
- "description": "Session-based Slack access for Claude: DMs, channels, search, and threads via your Slack session.",
6
- "websiteUrl": "https://jtalk22.github.io/slack-mcp-server/public/demo.html",
5
+ "description": "Session-based Slack MCP for Claude and MCP clients: local-first workflows, secure-default HTTP.",
6
+ "websiteUrl": "https://jtalk22.github.io/slack-mcp-server/",
7
7
  "icons": [
8
8
  {
9
9
  "src": "https://raw.githubusercontent.com/jtalk22/slack-mcp-server/main/docs/assets/icon-512.png",
@@ -17,12 +17,18 @@
17
17
  "url": "https://github.com/jtalk22/slack-mcp-server",
18
18
  "source": "github"
19
19
  },
20
- "version": "3.0.0",
20
+ "version": "3.2.0",
21
+ "remotes": [
22
+ {
23
+ "type": "streamable-http",
24
+ "url": "https://mcp.revasserlabs.com/oauth/mcp"
25
+ }
26
+ ],
21
27
  "packages": [
22
28
  {
23
29
  "registryType": "npm",
24
30
  "identifier": "@jtalk22/slack-mcp",
25
- "version": "3.0.0",
31
+ "version": "3.2.0",
26
32
  "transport": {
27
33
  "type": "stdio"
28
34
  },
@@ -27,10 +27,15 @@ import {
27
27
  handleSendMessage,
28
28
  handleGetThread,
29
29
  handleListUsers,
30
+ handleAddReaction,
31
+ handleRemoveReaction,
32
+ handleConversationsMark,
33
+ handleConversationsUnreads,
34
+ handleUsersSearch,
30
35
  } from "../lib/handlers.js";
31
36
 
32
37
  const SERVER_NAME = "slack-mcp-server";
33
- const SERVER_VERSION = "3.0.0";
38
+ const SERVER_VERSION = "3.2.0";
34
39
  const PORT = process.env.PORT || 3000;
35
40
  const HTTP_INSECURE = process.env.SLACK_MCP_HTTP_INSECURE === "1";
36
41
  const HTTP_AUTH_TOKEN = process.env.SLACK_MCP_HTTP_AUTH_TOKEN || process.env.SLACK_API_KEY || null;
@@ -115,6 +120,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
115
120
  return await handleGetThread(args);
116
121
  case "slack_list_users":
117
122
  return await handleListUsers(args);
123
+ case "slack_add_reaction":
124
+ return await handleAddReaction(args);
125
+ case "slack_remove_reaction":
126
+ return await handleRemoveReaction(args);
127
+ case "slack_conversations_mark":
128
+ return await handleConversationsMark(args);
129
+ case "slack_conversations_unreads":
130
+ return await handleConversationsUnreads(args);
131
+ case "slack_users_search":
132
+ return await handleUsersSearch(args);
118
133
  default:
119
134
  return {
120
135
  content: [{
package/src/server.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * - Network error retry with exponential backoff
12
12
  * - Background token health monitoring
13
13
  *
14
- * @version 3.0.0
14
+ * @version 3.2.0
15
15
  */
16
16
 
17
17
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -41,6 +41,11 @@ import {
41
41
  handleSendMessage,
42
42
  handleGetThread,
43
43
  handleListUsers,
44
+ handleAddReaction,
45
+ handleRemoveReaction,
46
+ handleConversationsMark,
47
+ handleConversationsUnreads,
48
+ handleUsersSearch,
44
49
  } from "../lib/handlers.js";
45
50
 
46
51
  // Background refresh interval (4 hours)
@@ -48,7 +53,7 @@ const BACKGROUND_REFRESH_INTERVAL = 4 * 60 * 60 * 1000;
48
53
 
49
54
  // Package info
50
55
  const SERVER_NAME = "slack-mcp-server";
51
- const SERVER_VERSION = "3.0.0";
56
+ const SERVER_VERSION = "3.2.0";
52
57
 
53
58
  // MCP Prompts - predefined prompt templates for common Slack operations
54
59
  const PROMPTS = [
@@ -255,6 +260,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
255
260
  case "slack_list_users":
256
261
  return await handleListUsers(args);
257
262
 
263
+ case "slack_add_reaction":
264
+ return await handleAddReaction(args);
265
+
266
+ case "slack_remove_reaction":
267
+ return await handleRemoveReaction(args);
268
+
269
+ case "slack_conversations_mark":
270
+ return await handleConversationsMark(args);
271
+
272
+ case "slack_conversations_unreads":
273
+ return await handleConversationsUnreads(args);
274
+
275
+ case "slack_users_search":
276
+ return await handleUsersSearch(args);
277
+
258
278
  default:
259
279
  return {
260
280
  content: [{
@@ -306,11 +326,15 @@ async function main() {
306
326
  // Use unref() so this timer doesn't prevent the process from exiting
307
327
  // when the MCP transport closes (prevents zombie processes)
308
328
  const backgroundTimer = setInterval(async () => {
309
- const health = await checkTokenHealth(console);
310
- if (health.refreshed) {
311
- console.error("Background: tokens refreshed successfully");
312
- } else if (health.critical) {
313
- console.error("Background: tokens critical - open Slack in Chrome");
329
+ try {
330
+ const health = await checkTokenHealth(console);
331
+ if (health.refreshed) {
332
+ console.error("Background: tokens refreshed successfully");
333
+ } else if (health.critical) {
334
+ console.error("Background: tokens critical - open Slack in Chrome");
335
+ }
336
+ } catch (err) {
337
+ console.error(`Background health check failed: ${err.message}`);
314
338
  }
315
339
  }, BACKGROUND_REFRESH_INTERVAL);
316
340
  backgroundTimer.unref();