@jtalk22/slack-mcp 4.2.1 → 4.3.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/README.md +8 -5
- package/docs/SETUP.md +49 -1
- package/lib/handlers.js +2 -3
- package/package.json +1 -1
- package/scripts/token-cli.js +6 -5
- package/server.json +2 -2
- package/src/cli.js +3 -0
package/README.md
CHANGED
|
@@ -42,9 +42,9 @@ This server uses your browser's session tokens instead. If you can see it in Sla
|
|
|
42
42
|
| Tools | Limited | **21** |
|
|
43
43
|
| Visible to admins | Yes | **No — session-token transport** |
|
|
44
44
|
|
|
45
|
-
## Workflow Primitives
|
|
45
|
+
## Workflow Primitives
|
|
46
46
|
|
|
47
|
-
Save a workflow profile that binds a `workflow_kind` to channels + priority people + retention + cadence. Stored locally at `~/.slack-mcp-workflows.json`. The hosted brain at [mcp.revasserlabs.com](https://mcp.revasserlabs.com) reads these profiles and returns **structured JSON per workflow_kind** — downstream automation (Linear, Notion, status dashboards) consumes the JSON directly.
|
|
47
|
+
Introduced in 4.2. Save a workflow profile that binds a `workflow_kind` to channels + priority people + retention + cadence. Stored locally at `~/.slack-mcp-workflows.json`. The hosted brain at [mcp.revasserlabs.com](https://mcp.revasserlabs.com) reads these profiles and returns **structured JSON per workflow_kind** — downstream automation (Linear, Notion, status dashboards) consumes the JSON directly.
|
|
48
48
|
|
|
49
49
|
| `workflow_kind` | Returns (structured JSON) |
|
|
50
50
|
|---|---|
|
|
@@ -305,7 +305,8 @@ Session tokens (`xoxc-` + `xoxd-`) from your browser. If you can see it in Slack
|
|
|
305
305
|
|
|
306
306
|
Tokens expire. The server notices before you do — proactive health monitoring, automatic refresh on macOS, warnings when tokens age out. File writes are atomic (temp file → chmod → rename) to prevent corruption. Concurrent refresh attempts are mutex-locked.
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
<details>
|
|
309
|
+
<summary><strong>What's New in 4.2.0</strong></summary>
|
|
309
310
|
|
|
310
311
|
- **Workflow primitives** — `slack_workflow_save` + `slack_workflows` bind a `workflow_kind` (`incident_room`, `exec_brief`, `support_inbox`, `product_launch_watch`, `custom`) to channels, priority people, retention, and cadence. The hosted brain returns structured JSON per kind — `incident_room` returns `{incident_summary, timeline, open_risks, owner_gaps, next_actions}`, `exec_brief` returns `{summary, decisions, risks, asks, action_items}`. Downstream automation (Linear, Notion, dashboards) consumes the JSON directly.
|
|
311
312
|
- **Discoverable upgrade stubs** — `slack_smart_search`, `slack_catch_me_up`, `slack_triage` appear in OSS as upgrade payloads pointing at the hosted brain. Response shape is `{signup_url, free_tier_quota, pro_value_prop}` — no interruptions, the AI routes the user cleanly.
|
|
@@ -315,6 +316,8 @@ Tokens expire. The server notices before you do — proactive health monitoring,
|
|
|
315
316
|
|
|
316
317
|
Full release notes on [GitHub releases/latest](https://github.com/jtalk22/slack-mcp-server/releases/latest).
|
|
317
318
|
|
|
319
|
+
</details>
|
|
320
|
+
|
|
318
321
|
## Hosted HTTP Mode
|
|
319
322
|
|
|
320
323
|
For remote MCP endpoints (Cloudflare Worker, VPS, etc.):
|
|
@@ -331,7 +334,7 @@ Details: [docs/DEPLOYMENT-MODES.md](docs/DEPLOYMENT-MODES.md)
|
|
|
331
334
|
|
|
332
335
|
## Troubleshooting
|
|
333
336
|
|
|
334
|
-
**Tokens expired:** Run `npx -y @jtalk22/slack-mcp --setup` or use `slack_refresh_tokens` (macOS).
|
|
337
|
+
**Tokens expired:** Run `npx -y @jtalk22/slack-mcp --setup` or use `slack_refresh_tokens` (macOS). To prevent silent expiration during long Claude-idle windows, set up the optional [token-refresh LaunchAgent](docs/SETUP.md#keep-tokens-fresh-while-claude-is-closed-macos-optional).
|
|
335
338
|
|
|
336
339
|
**DMs not showing:** Use `slack_list_conversations` with `discover_dms=true`.
|
|
337
340
|
|
|
@@ -371,4 +374,4 @@ Not affiliated with Slack Technologies, Inc. Uses browser session credentials
|
|
|
371
374
|
|
|
372
375
|
---
|
|
373
376
|
|
|
374
|
-
Hosted version live at [mcp.revasserlabs.com](https://mcp.revasserlabs.com): Free tier (no card), $9/mo Pro, $49/mo Team flat, Ops from $199/mo. Hosted owns the AI brain (smart_search, catch_me_up, triage), the scheduled morning catch-up DM at 8am workspace time *(rolling out Q2 2026)*, permanent OAuth (no 2-week token rotation), 90-day Vectorize retention, and shared workflow profiles. The OSS package owns local stdio +
|
|
377
|
+
Hosted version live at [mcp.revasserlabs.com](https://mcp.revasserlabs.com): Free tier (no card), $9/mo Pro, $49/mo Team flat, Ops from $199/mo. Hosted owns the AI brain (smart_search, catch_me_up, triage), the scheduled morning catch-up DM at 8am workspace time *(rolling out Q2 2026)*, permanent OAuth (no 2-week token rotation), 90-day Vectorize retention, and shared workflow profiles. The OSS package owns local stdio + the 16 Slack tools (12 read, 4 write) + workflow profile primitives (slack_workflow_save, slack_workflows). The 3 paid stubs (slack_smart_search, slack_catch_me_up, slack_triage) appear in OSS as discoverable upgrade prompts.
|
package/docs/SETUP.md
CHANGED
|
@@ -138,6 +138,54 @@ slack_health_check
|
|
|
138
138
|
|
|
139
139
|
You should see your username and team name.
|
|
140
140
|
|
|
141
|
+
## Keep Tokens Fresh While Claude Is Closed (macOS, Optional)
|
|
142
|
+
|
|
143
|
+
The MCP server auto-refreshes tokens every 4 hours while Claude is running. But if you keep Claude closed for a couple weeks, tokens expire silently — your next session opens with `invalid_auth`.
|
|
144
|
+
|
|
145
|
+
A LaunchAgent fixes this. It runs token refresh twice a day regardless of whether Claude is open, as long as Chrome is running with a Slack tab somewhere.
|
|
146
|
+
|
|
147
|
+
Create `~/Library/LaunchAgents/com.yourname.slack-token-refresh.plist`:
|
|
148
|
+
|
|
149
|
+
```xml
|
|
150
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
151
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
152
|
+
<plist version="1.0">
|
|
153
|
+
<dict>
|
|
154
|
+
<key>Label</key>
|
|
155
|
+
<string>com.yourname.slack-token-refresh</string>
|
|
156
|
+
<key>ProgramArguments</key>
|
|
157
|
+
<array>
|
|
158
|
+
<string>/bin/bash</string>
|
|
159
|
+
<string>-c</string>
|
|
160
|
+
<string>export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && exec npx -y @jtalk22/slack-mcp --refresh-tokens</string>
|
|
161
|
+
</array>
|
|
162
|
+
<key>StartCalendarInterval</key>
|
|
163
|
+
<array>
|
|
164
|
+
<dict><key>Hour</key><integer>6</integer><key>Minute</key><integer>17</integer></dict>
|
|
165
|
+
<dict><key>Hour</key><integer>18</integer><key>Minute</key><integer>17</integer></dict>
|
|
166
|
+
</array>
|
|
167
|
+
<key>RunAtLoad</key><true/>
|
|
168
|
+
<key>StandardErrorPath</key><string>/tmp/slack-token-refresh.log</string>
|
|
169
|
+
</dict>
|
|
170
|
+
</plist>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Load it:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.yourname.slack-token-refresh.plist
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Check it ran:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
tail /tmp/slack-token-refresh.log
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Why the `bash -c` wrapper:** LaunchAgents start without a TTY, so a bare `node` won't be on PATH if you use nvm. The wrapper sources `nvm.sh` first, then runs the refresher. (If you installed node via Homebrew, replace the whole inner command with `/opt/homebrew/bin/node /opt/homebrew/bin/npx -y @jtalk22/slack-mcp --refresh-tokens`.)
|
|
186
|
+
|
|
187
|
+
**Trade-off:** Chrome must be running for extraction to succeed. If it's not, the LaunchAgent logs "Failed to extract" and tokens stay where they are — which is fine for another 12 hours.
|
|
188
|
+
|
|
141
189
|
## Troubleshooting
|
|
142
190
|
|
|
143
191
|
### "No credentials found"
|
|
@@ -151,7 +199,7 @@ Tokens have expired. Run `npx -y @jtalk22/slack-mcp --doctor` and follow the sug
|
|
|
151
199
|
### MCP Server Not Loading
|
|
152
200
|
|
|
153
201
|
1. Check `~/.claude.json` syntax
|
|
154
|
-
2. Verify
|
|
202
|
+
2. Verify JSON syntax in your client's MCP config
|
|
155
203
|
3. Restart Claude Code
|
|
156
204
|
|
|
157
205
|
### Chrome Extraction Fails
|
package/lib/handlers.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Implementation of all MCP tool handlers.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { writeFileSync, readFileSync, existsSync, renameSync, unlinkSync, mkdirSync } from "fs";
|
|
8
|
-
import { execSync } from "child_process";
|
|
7
|
+
import { writeFileSync, readFileSync, existsSync, renameSync, unlinkSync, mkdirSync, chmodSync } from "fs";
|
|
9
8
|
import { homedir, platform } from "os";
|
|
10
9
|
import { join } from "path";
|
|
11
10
|
import {
|
|
@@ -55,7 +54,7 @@ function atomicWriteSync(filePath, content) {
|
|
|
55
54
|
try {
|
|
56
55
|
writeFileSync(tempPath, content);
|
|
57
56
|
if (platform() === 'darwin' || platform() === 'linux') {
|
|
58
|
-
try {
|
|
57
|
+
try { chmodSync(tempPath, 0o600); } catch {}
|
|
59
58
|
}
|
|
60
59
|
renameSync(tempPath, filePath);
|
|
61
60
|
} catch (e) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jtalk22/slack-mcp",
|
|
3
3
|
"mcpName": "io.github.jtalk22/slack-mcp-server",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.3.0",
|
|
5
5
|
"description": "Slack MCP without OAuth. 21 tools (16 read/write Slack + 2 workflow profile primitives + 3 hosted-brain upgrade stubs). Free OSS or hosted (free tier no card; $9/mo Pro = unlimited; morning DM rolling out Q2 2026).",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "src/server.js",
|
package/scripts/token-cli.js
CHANGED
|
@@ -133,7 +133,7 @@ async function autoExtract() {
|
|
|
133
133
|
|
|
134
134
|
async function clearTokens() {
|
|
135
135
|
const fs = await import("fs");
|
|
136
|
-
const {
|
|
136
|
+
const { spawnSync } = await import("child_process");
|
|
137
137
|
|
|
138
138
|
try {
|
|
139
139
|
fs.unlinkSync(TOKEN_FILE);
|
|
@@ -142,11 +142,12 @@ async function clearTokens() {
|
|
|
142
142
|
console.log("No token file to delete");
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
const securityArgs = (account) => ["delete-generic-password", "-s", KEYCHAIN_SERVICE, "-a", account];
|
|
146
|
+
const tokenResult = spawnSync("security", securityArgs("token"), { stdio: "ignore" });
|
|
147
|
+
const cookieResult = spawnSync("security", securityArgs("cookie"), { stdio: "ignore" });
|
|
148
|
+
if (tokenResult.status === 0 || cookieResult.status === 0) {
|
|
148
149
|
console.log("Deleted keychain entries");
|
|
149
|
-
}
|
|
150
|
+
} else {
|
|
150
151
|
console.log("No keychain entries to delete");
|
|
151
152
|
}
|
|
152
153
|
|
package/server.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"url": "https://github.com/jtalk22/slack-mcp-server",
|
|
18
18
|
"source": "github"
|
|
19
19
|
},
|
|
20
|
-
"version": "4.
|
|
20
|
+
"version": "4.3.0",
|
|
21
21
|
"remotes": [
|
|
22
22
|
{
|
|
23
23
|
"type": "streamable-http",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
{
|
|
29
29
|
"registryType": "npm",
|
|
30
30
|
"identifier": "@jtalk22/slack-mcp",
|
|
31
|
-
"version": "4.
|
|
31
|
+
"version": "4.3.0",
|
|
32
32
|
"transport": {
|
|
33
33
|
"type": "stdio"
|
|
34
34
|
},
|
package/src/cli.js
CHANGED
|
@@ -37,6 +37,9 @@ if (firstArg === "web") {
|
|
|
37
37
|
} else if (firstArg === "--apply-template" || firstArg === "apply-template") {
|
|
38
38
|
scriptPath = join(__dirname, "../scripts/apply-template.js");
|
|
39
39
|
scriptArgs = args.slice(1);
|
|
40
|
+
} else if (firstArg === "--refresh-tokens" || firstArg === "refresh-tokens") {
|
|
41
|
+
scriptPath = join(__dirname, "../scripts/token-cli.js");
|
|
42
|
+
scriptArgs = ["auto"];
|
|
40
43
|
} else if (WIZARD_ARGS.has(firstArg)) {
|
|
41
44
|
scriptPath = join(__dirname, "../scripts/setup-wizard.js");
|
|
42
45
|
scriptArgs = args;
|