@jtalk22/slack-mcp 4.0.0 → 4.1.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 +91 -12
- package/docs/SETUP.md +2 -34
- package/docs/TROUBLESHOOTING.md +2 -24
- package/lib/handlers.js +1 -1
- package/lib/public-pages.js +11 -11
- package/lib/token-store.js +179 -68
- package/package.json +11 -3
- package/public/index.html +1 -1
- package/public/share.html +9 -9
- package/scripts/setup-wizard.js +74 -25
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -10,11 +10,13 @@ Give your AI agent full Slack access. No app registration, no admin approval, no
|
|
|
10
10
|
npx -y @jtalk22/slack-mcp --setup
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
](https://jtalk22.github.io/slack-mcp-server/public/demo-video.html)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**[▶ Watch the demo](https://jtalk22.github.io/slack-mcp-server/public/demo-video.html)** — 7 scenarios, from 47 unreads to inbox zero, without opening Slack.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
> **Ask your AI to catch you up on #engineering from the last 24 hours.** Search for that deployment thread from last week. Find the printer admin PIN nobody can remember. Send a reply. All from your editor.
|
|
18
|
+
|
|
19
|
+
[Interactive demo](https://jtalk22.github.io/slack-mcp-server/public/demo-slack-mcp.html) · [Latest release](https://github.com/jtalk22/slack-mcp-server/releases/latest)
|
|
18
20
|
|
|
19
21
|
## Why This Exists
|
|
20
22
|
|
|
@@ -22,7 +24,90 @@ Slack's official MCP server requires a registered app, admin approval, and [does
|
|
|
22
24
|
|
|
23
25
|
This server uses your browser's session tokens instead. If you can see it in Slack, your AI agent can see it too. No app install, no scopes, no admin.
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
**Stealth Mode:** Session tokens leave zero footprint in your workspace admin panel. No bot user appears, no app install shows up, no audit trail. Your AI agent operates with the same invisibility as your browser tab.
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
| | Slack Official MCP | This Server |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| OAuth app required | Yes | **No** |
|
|
34
|
+
| Admin approval | Yes | **No** |
|
|
35
|
+
| Works with Claude Code | No (DCR incompatible) | **Yes** |
|
|
36
|
+
| Works with Cursor | No | **Yes** |
|
|
37
|
+
| Works with Copilot | No | **Yes** |
|
|
38
|
+
| Works with Windsurf | No | **Yes** |
|
|
39
|
+
| Works with Gemini CLI | No | **Yes** |
|
|
40
|
+
| Works with Codex CLI | No | **Yes** |
|
|
41
|
+
| Setup time | ~30 min | **~2 min** |
|
|
42
|
+
| Tools | Limited | **16** |
|
|
43
|
+
| Visible to admins | Yes | **No — Stealth Mode** |
|
|
44
|
+
|
|
45
|
+
## Quick Start per Client
|
|
46
|
+
|
|
47
|
+
<details>
|
|
48
|
+
<summary><strong>Claude Desktop / Claude Code</strong></summary>
|
|
49
|
+
|
|
50
|
+
Add to `~/.claude.json` or Claude Desktop settings:
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
</details>
|
|
59
|
+
|
|
60
|
+
<details>
|
|
61
|
+
<summary><strong>Cursor</strong></summary>
|
|
62
|
+
|
|
63
|
+
Add to `.cursor/mcp.json`:
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
</details>
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary><strong>Windsurf</strong></summary>
|
|
75
|
+
|
|
76
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"mcpServers": {
|
|
80
|
+
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
</details>
|
|
85
|
+
|
|
86
|
+
<details>
|
|
87
|
+
<summary><strong>Gemini CLI</strong></summary>
|
|
88
|
+
|
|
89
|
+
Add to `~/.gemini/settings.json`:
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
</details>
|
|
98
|
+
|
|
99
|
+
<details>
|
|
100
|
+
<summary><strong>Codex CLI</strong></summary>
|
|
101
|
+
|
|
102
|
+
Add to `~/.codex/config.toml`:
|
|
103
|
+
```toml
|
|
104
|
+
[mcp_servers.slack]
|
|
105
|
+
command = "npx"
|
|
106
|
+
args = ["-y", "@jtalk22/slack-mcp"]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or via CLI: `codex mcp add slack -- npx -y @jtalk22/slack-mcp`
|
|
110
|
+
</details>
|
|
26
111
|
|
|
27
112
|
## Tools
|
|
28
113
|
|
|
@@ -145,13 +230,7 @@ On macOS, tokens are auto-extracted from Chrome — `env` block is optional.
|
|
|
145
230
|
<details>
|
|
146
231
|
<summary><strong>Claude Web / Remote MCP</strong></summary>
|
|
147
232
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
https://mcp.revasserlabs.com/oauth/mcp
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
Add this as a remote MCP server in your client's settings. Transport: Streamable HTTP. Auth: OAuth 2.1 + PKCE.
|
|
233
|
+
Hosted version with permanent OAuth tokens coming soon. See [mcp.revasserlabs.com](https://mcp.revasserlabs.com) for updates.
|
|
155
234
|
|
|
156
235
|
</details>
|
|
157
236
|
|
|
@@ -247,4 +326,4 @@ Not affiliated with Slack Technologies, Inc. Uses browser session credentials
|
|
|
247
326
|
|
|
248
327
|
---
|
|
249
328
|
|
|
250
|
-
|
|
329
|
+
Hosted version with semantic search, AI summaries, and permanent OAuth — coming soon at [mcp.revasserlabs.com](https://mcp.revasserlabs.com)
|
package/docs/SETUP.md
CHANGED
|
@@ -1,40 +1,8 @@
|
|
|
1
1
|
# Setup Guide
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Hosted (Coming Soon)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
1. Go to [Slack MCP Cloud](https://mcp.revasserlabs.com) and purchase a plan ($19/mo Solo, $49/mo Team)
|
|
8
|
-
2. After checkout, you'll receive an API key and ready-to-paste config for Claude Desktop / Claude Code
|
|
9
|
-
3. Use the hosted endpoint and API key — one URL, 15 managed tools. Team adds 3 AI workflows.
|
|
10
|
-
|
|
11
|
-
**Claude Desktop config (Cloud):**
|
|
12
|
-
```json
|
|
13
|
-
{
|
|
14
|
-
"mcpServers": {
|
|
15
|
-
"slack": {
|
|
16
|
-
"url": "https://mcp.revasserlabs.com/oauth/mcp"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Claude Code config (Cloud):**
|
|
23
|
-
```json
|
|
24
|
-
{
|
|
25
|
-
"mcpServers": {
|
|
26
|
-
"slack": {
|
|
27
|
-
"type": "sse",
|
|
28
|
-
"url": "https://mcp.revasserlabs.com/mcp",
|
|
29
|
-
"headers": {
|
|
30
|
-
"Authorization": "Bearer YOUR_API_KEY"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
If you prefer self-hosting, continue below.
|
|
5
|
+
A hosted version with permanent OAuth tokens, semantic search, and AI summaries is in development at [mcp.revasserlabs.com](https://mcp.revasserlabs.com). The current release is self-hosted only — continue below.
|
|
38
6
|
|
|
39
7
|
---
|
|
40
8
|
|
package/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -29,31 +29,9 @@ If `--version` fails here, the issue is install/runtime path, not Slack credenti
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Hosted Version
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
**Symptom:** `401 Unauthorized` or `403 Forbidden` when using Cloud endpoint.
|
|
37
|
-
|
|
38
|
-
**Solutions:**
|
|
39
|
-
1. Verify your API key starts with `stmh_` (team) or `smsh_` (solo)
|
|
40
|
-
2. Check the key hasn't been revoked — contact support@revasserlabs.com for key issues
|
|
41
|
-
3. Ensure you're using the correct endpoint: `https://mcp.revasserlabs.com/mcp`
|
|
42
|
-
|
|
43
|
-
### Cloud Tools Not Available
|
|
44
|
-
|
|
45
|
-
**Symptom:** Only seeing fewer tools than expected.
|
|
46
|
-
|
|
47
|
-
**Cause:** AI compound tools (`slack_channel_summary`, `slack_extract_action_items`, `slack_find_decisions`) are Team plan only ($49/mo).
|
|
48
|
-
|
|
49
|
-
**Solution:** Upgrade to Team plan for AI compound tools, or use the 15 standard managed tools available on all Cloud plans.
|
|
50
|
-
|
|
51
|
-
### Cloud Endpoint Health Check
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
curl -s https://mcp.revasserlabs.com/health | jq .
|
|
55
|
-
# Expected: {"status":"healthy","server":"slack-mcp-hosted","version":"0.5.0"}
|
|
56
|
-
```
|
|
34
|
+
A hosted version with permanent OAuth tokens, semantic search, and AI summaries is coming soon at [mcp.revasserlabs.com](https://mcp.revasserlabs.com). The current release is self-hosted only.
|
|
57
35
|
|
|
58
36
|
---
|
|
59
37
|
|
package/lib/handlers.js
CHANGED
|
@@ -216,7 +216,7 @@ export async function handleRefreshTokens() {
|
|
|
216
216
|
code: extractionError.code,
|
|
217
217
|
message: extractionError.message,
|
|
218
218
|
detail: extractionError.detail,
|
|
219
|
-
next_action: "In Chrome: View > Developer > Allow JavaScript from Apple Events, then retry."
|
|
219
|
+
next_action: "In Chrome: View > Developer > Allow JavaScript from Apple Events, then retry. (Only needed for token — cookie is extracted from Chrome's database automatically.)"
|
|
220
220
|
}, true);
|
|
221
221
|
}
|
|
222
222
|
|
package/lib/public-pages.js
CHANGED
|
@@ -15,7 +15,7 @@ const ICON_URL = `${GITHUB_PAGES_ROOT}/docs/assets/icon-512.png`;
|
|
|
15
15
|
const NPM_URL = "https://www.npmjs.com/package/@jtalk22/slack-mcp";
|
|
16
16
|
const RELEASES_URL = `${PUBLIC_METADATA.canonicalRepoUrl}/releases/latest`;
|
|
17
17
|
const SETUP_URL = `${PUBLIC_METADATA.canonicalRepoUrl}/blob/main/docs/SETUP.md`;
|
|
18
|
-
const DEMO_VIDEO_URL = `${GITHUB_PAGES_ROOT}/docs/videos/demo-
|
|
18
|
+
const DEMO_VIDEO_URL = `${GITHUB_PAGES_ROOT}/docs/videos/demo-slack-mcp-mobile-20s.mp4`;
|
|
19
19
|
|
|
20
20
|
function template(name) {
|
|
21
21
|
return readFileSync(resolve(TEMPLATE_DIR, name), "utf8");
|
|
@@ -58,28 +58,28 @@ function shareLinks() {
|
|
|
58
58
|
<a href="${GITHUB_PAGES_ROOT}/" rel="noopener">Autoplay Demo Landing</a>
|
|
59
59
|
<a href="${DEMO_VIDEO_URL}" rel="noopener">20s Mobile Clip</a>
|
|
60
60
|
<a href="${NPM_URL}" rel="noopener">npm Package</a>
|
|
61
|
-
<a href="${PUBLIC_METADATA.canonicalSiteUrl}" rel="noopener" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">
|
|
61
|
+
<a href="${PUBLIC_METADATA.canonicalSiteUrl}" rel="noopener" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">Hosted</a>
|
|
62
62
|
`.trim();
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function shareNote() {
|
|
66
|
-
return `<strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives ${PUBLIC_METADATA.selfHostedToolCount} tools with session-based auth. Works with any MCP client — Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf.
|
|
66
|
+
return `<strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives ${PUBLIC_METADATA.selfHostedToolCount} tools with session-based auth. Works with any MCP client — Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf. Hosted version coming soon at <a href="${PUBLIC_METADATA.canonicalSiteUrl}">mcp.revasserlabs.com</a>.`;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function demoLinks() {
|
|
70
70
|
return `
|
|
71
|
-
<a href="${PUBLIC_METADATA.canonicalSiteUrl}" target="_blank" rel="noopener noreferrer" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">
|
|
71
|
+
<a href="${PUBLIC_METADATA.canonicalSiteUrl}" target="_blank" rel="noopener noreferrer" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">Hosted</a>
|
|
72
72
|
<a href="${NPM_URL}" target="_blank" rel="noopener noreferrer">npm Install</a>
|
|
73
73
|
<a href="${SETUP_URL}" target="_blank" rel="noopener noreferrer">Setup Guide</a>
|
|
74
74
|
`.trim();
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function demoNote() {
|
|
78
|
-
return `Self-host free for ${PUBLIC_METADATA.selfHostedToolCount} tools with session-based auth. Works with Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf, and any other MCP client. No OAuth app, no admin approval.
|
|
78
|
+
return `Self-host free for ${PUBLIC_METADATA.selfHostedToolCount} tools with session-based auth. Works with Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf, and any other MCP client. No OAuth app, no admin approval. Hosted version coming soon at <a href="${PUBLIC_METADATA.canonicalSiteUrl}" target="_blank" rel="noopener noreferrer">mcp.revasserlabs.com</a>.`;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function demoFooterLinks() {
|
|
82
|
-
return `<a href="${PUBLIC_METADATA.canonicalRepoUrl}">GitHub</a> · <a href="${NPM_URL}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">npm</a> · <a href="${PUBLIC_METADATA.canonicalSiteUrl}" style="color:#f0c246;text-decoration:none;font-size:0.875rem">
|
|
82
|
+
return `<a href="${PUBLIC_METADATA.canonicalRepoUrl}">GitHub</a> · <a href="${NPM_URL}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">npm</a> · <a href="${PUBLIC_METADATA.canonicalSiteUrl}" style="color:#f0c246;text-decoration:none;font-size:0.875rem">Hosted</a>`;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function commonTokens() {
|
|
@@ -113,10 +113,10 @@ function commonTokens() {
|
|
|
113
113
|
SELF_HOSTED_TOOL_COUNT: String(PUBLIC_METADATA.selfHostedToolCount),
|
|
114
114
|
CLOUD_MANAGED_TOOL_COUNT: "15",
|
|
115
115
|
TEAM_AI_WORKFLOW_COUNT: "3",
|
|
116
|
-
CLOUD_SOLO_PRICE: "
|
|
117
|
-
CLOUD_TEAM_PRICE: "
|
|
118
|
-
CLOUD_TURNKEY_LAUNCH_PRICE: "
|
|
119
|
-
CLOUD_MANAGED_RELIABILITY_PRICE: "
|
|
116
|
+
CLOUD_SOLO_PRICE: "coming soon",
|
|
117
|
+
CLOUD_TEAM_PRICE: "coming soon",
|
|
118
|
+
CLOUD_TURNKEY_LAUNCH_PRICE: "contact us",
|
|
119
|
+
CLOUD_MANAGED_RELIABILITY_PRICE: "contact us",
|
|
120
120
|
SUPPORT_EMAIL: PUBLIC_METADATA.supportEmail,
|
|
121
121
|
ROOT_DECISION_PANEL: rootDecisionPanel(),
|
|
122
122
|
SHARE_LINKS: shareLinks(),
|
|
@@ -134,6 +134,6 @@ export function buildPublicPages() {
|
|
|
134
134
|
"public/share.html": replaceTokens(template("share.html.tpl"), tokens),
|
|
135
135
|
"public/demo.html": replaceTokens(template("demo.html.tpl"), tokens),
|
|
136
136
|
"public/demo-video.html": replaceTokens(template("demo-video.html.tpl"), tokens),
|
|
137
|
-
"public/demo-
|
|
137
|
+
"public/demo-slack-mcp.html": replaceTokens(template("demo-slack-mcp.html.tpl"), tokens),
|
|
138
138
|
};
|
|
139
139
|
}
|
package/lib/token-store.js
CHANGED
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
* 4. Chrome auto-extraction (fallback)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { readFileSync, writeFileSync, existsSync, renameSync, unlinkSync, chmodSync } from "fs";
|
|
12
|
-
import { homedir, platform } from "os";
|
|
11
|
+
import { readFileSync, writeFileSync, existsSync, renameSync, unlinkSync, chmodSync, copyFileSync, mkdtempSync } from "fs";
|
|
12
|
+
import { homedir, platform, tmpdir } from "os";
|
|
13
13
|
import { join } from "path";
|
|
14
|
-
import {
|
|
14
|
+
import { execFileSync } from "child_process";
|
|
15
|
+
import { pbkdf2Sync, createDecipheriv } from "crypto";
|
|
15
16
|
|
|
16
17
|
const TOKEN_FILE = join(homedir(), ".slack-mcp-tokens.json");
|
|
17
18
|
const KEYCHAIN_SERVICE = "slack-mcp-server";
|
|
@@ -102,32 +103,31 @@ export function saveToFile(token, cookie) {
|
|
|
102
103
|
|
|
103
104
|
// Multiple localStorage paths Slack might use (for robustness)
|
|
104
105
|
const SLACK_TOKEN_PATHS = [
|
|
105
|
-
// Current known path
|
|
106
106
|
`JSON.parse(localStorage.localConfig_v2).teams[Object.keys(JSON.parse(localStorage.localConfig_v2).teams)[0]].token`,
|
|
107
|
-
// Potential future paths
|
|
108
107
|
`JSON.parse(localStorage.localConfig_v3).teams[Object.keys(JSON.parse(localStorage.localConfig_v3).teams)[0]].token`,
|
|
109
|
-
// Redux store path (older Slack)
|
|
110
108
|
`JSON.parse(localStorage.getItem('reduxPersist:localConfig'))?.teams?.[Object.keys(JSON.parse(localStorage.getItem('reduxPersist:localConfig'))?.teams || {})[0]]?.token`,
|
|
111
|
-
// Direct boot data
|
|
112
109
|
`window.boot_data?.api_token`,
|
|
113
110
|
];
|
|
114
111
|
|
|
112
|
+
// Chrome profile directories to search (in priority order)
|
|
113
|
+
const CHROME_PROFILES = ['Default', 'Profile 1', 'Profile 2', 'Profile 3'];
|
|
114
|
+
|
|
115
115
|
function normalizeExtractionError(error) {
|
|
116
116
|
const raw = String(error?.message || error || "");
|
|
117
117
|
|
|
118
118
|
if (raw.includes("Executing JavaScript through AppleScript is turned off")) {
|
|
119
119
|
return {
|
|
120
120
|
code: "apple_events_javascript_disabled",
|
|
121
|
-
message: "Chrome
|
|
122
|
-
detail: "
|
|
121
|
+
message: "Chrome needs one setting enabled for token extraction.",
|
|
122
|
+
detail: "In Chrome: View > Developer > Allow JavaScript from Apple Events. Cookie extraction works without this — only the token needs it."
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
if (raw.includes("Application isn't running") || raw.includes("Google Chrome got an error")) {
|
|
127
127
|
return {
|
|
128
128
|
code: "chrome_not_ready",
|
|
129
|
-
message: "Chrome is not
|
|
130
|
-
detail: "Open Google Chrome with
|
|
129
|
+
message: "Chrome is not running or has no windows open.",
|
|
130
|
+
detail: "Open Google Chrome with a Slack tab at app.slack.com."
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -139,6 +139,14 @@ function normalizeExtractionError(error) {
|
|
|
139
139
|
};
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
if (raw.includes("Chrome Safe Storage")) {
|
|
143
|
+
return {
|
|
144
|
+
code: "keychain_access_denied",
|
|
145
|
+
message: "Could not access Chrome's encryption key in Keychain.",
|
|
146
|
+
detail: "You may need to allow terminal access in System Settings > Privacy > Full Disk Access."
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
142
150
|
return {
|
|
143
151
|
code: "chrome_extraction_failed",
|
|
144
152
|
message: "Chrome token extraction failed.",
|
|
@@ -147,13 +155,133 @@ function normalizeExtractionError(error) {
|
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
/**
|
|
150
|
-
* Extract
|
|
151
|
-
*
|
|
158
|
+
* Extract the Slack session cookie from Chrome's encrypted cookie database.
|
|
159
|
+
* The `d` cookie is HttpOnly — JavaScript cannot access it via document.cookie.
|
|
160
|
+
* This reads Chrome's SQLite cookie store and decrypts using the Keychain-stored key.
|
|
161
|
+
*/
|
|
162
|
+
function extractCookieFromChromeDB() {
|
|
163
|
+
const chromeBase = join(homedir(), 'Library', 'Application Support', 'Google', 'Chrome');
|
|
164
|
+
|
|
165
|
+
// Find the first profile with a Slack d cookie
|
|
166
|
+
for (const profile of CHROME_PROFILES) {
|
|
167
|
+
const cookiesPath = join(chromeBase, profile, 'Cookies');
|
|
168
|
+
if (!existsSync(cookiesPath)) continue;
|
|
169
|
+
|
|
170
|
+
// Copy DB to temp location (Chrome holds a WAL lock on the original)
|
|
171
|
+
const tmpDir = mkdtempSync(join(tmpdir(), 'slack-mcp-'));
|
|
172
|
+
const tmpDb = join(tmpDir, 'Cookies');
|
|
173
|
+
try {
|
|
174
|
+
copyFileSync(cookiesPath, tmpDb);
|
|
175
|
+
|
|
176
|
+
// Query for the encrypted d cookie
|
|
177
|
+
const queryResult = execFileSync('sqlite3', [
|
|
178
|
+
tmpDb,
|
|
179
|
+
"SELECT hex(encrypted_value) FROM cookies WHERE host_key LIKE '%.slack.com%' AND name = 'd' LIMIT 1;"
|
|
180
|
+
], { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
181
|
+
|
|
182
|
+
// Clean up temp files
|
|
183
|
+
try { unlinkSync(tmpDb); unlinkSync(tmpDir); } catch {}
|
|
184
|
+
|
|
185
|
+
if (!queryResult) continue;
|
|
186
|
+
|
|
187
|
+
// Convert hex back to buffer
|
|
188
|
+
const encrypted = Buffer.from(queryResult, 'hex');
|
|
189
|
+
if (encrypted.length < 4) continue;
|
|
190
|
+
|
|
191
|
+
// Get Chrome Safe Storage password from Keychain
|
|
192
|
+
const safeStoragePassword = execFileSync('security', [
|
|
193
|
+
'find-generic-password', '-s', 'Chrome Safe Storage', '-w'
|
|
194
|
+
], { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
195
|
+
|
|
196
|
+
// Chrome macOS cookies: v10 prefix + AES-128-CBC
|
|
197
|
+
const prefix = encrypted.subarray(0, 3).toString('utf-8');
|
|
198
|
+
if (prefix !== 'v10') continue;
|
|
199
|
+
|
|
200
|
+
const ciphertext = encrypted.subarray(3);
|
|
201
|
+
|
|
202
|
+
// Derive key: PBKDF2-SHA1, 1003 iterations, salt 'saltysalt', 16-byte key
|
|
203
|
+
const key = pbkdf2Sync(safeStoragePassword, 'saltysalt', 1003, 16, 'sha1');
|
|
204
|
+
const iv = Buffer.alloc(16, ' '); // 16 space characters
|
|
205
|
+
|
|
206
|
+
const decipher = createDecipheriv('aes-128-cbc', key, iv);
|
|
207
|
+
let decrypted;
|
|
208
|
+
try {
|
|
209
|
+
decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
210
|
+
} catch {
|
|
211
|
+
continue; // Decryption failed for this profile, try next
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Find xoxd- in decrypted data (Chrome prepends internal metadata bytes)
|
|
215
|
+
const text = decrypted.toString('utf-8');
|
|
216
|
+
const xoxdIndex = text.indexOf('xoxd-');
|
|
217
|
+
if (xoxdIndex < 0) continue;
|
|
218
|
+
|
|
219
|
+
return text.substring(xoxdIndex);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// Clean up on error and try next profile
|
|
222
|
+
try { unlinkSync(tmpDb); } catch {}
|
|
223
|
+
try { unlinkSync(tmpDir); } catch {}
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Extract Slack token from Chrome via AppleScript (reads localStorage).
|
|
233
|
+
* Uses strict URL matching to avoid hitting non-Slack tabs.
|
|
234
|
+
*/
|
|
235
|
+
function extractTokenFromChrome() {
|
|
236
|
+
// Prefer /client URLs (active workspace), fall back to any app.slack.com
|
|
237
|
+
const urlChecks = [
|
|
238
|
+
'URL of t starts with "https://app.slack.com/client"',
|
|
239
|
+
'URL of t starts with "https://app.slack.com"',
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
const tokenPathsJS = SLACK_TOKEN_PATHS.map((path, i) =>
|
|
243
|
+
`try { var t${i} = ${path}; if (t${i} && t${i}.startsWith('xoxc-')) return t${i}; } catch(e) {}`
|
|
244
|
+
).join(' ');
|
|
245
|
+
|
|
246
|
+
for (const urlCheck of urlChecks) {
|
|
247
|
+
try {
|
|
248
|
+
const script = `tell application "Google Chrome"
|
|
249
|
+
repeat with w in windows
|
|
250
|
+
repeat with t in tabs of w
|
|
251
|
+
if ${urlCheck} then
|
|
252
|
+
return execute t javascript "(function() { ${tokenPathsJS} return ''; })()"
|
|
253
|
+
end if
|
|
254
|
+
end repeat
|
|
255
|
+
end repeat
|
|
256
|
+
return ""
|
|
257
|
+
end tell`;
|
|
258
|
+
|
|
259
|
+
const token = execFileSync('osascript', ['-e', script], {
|
|
260
|
+
encoding: 'utf-8', timeout: 8000
|
|
261
|
+
}).trim();
|
|
262
|
+
|
|
263
|
+
if (token && token.startsWith('xoxc-')) return token;
|
|
264
|
+
} catch {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Extract tokens from Chrome (macOS only).
|
|
274
|
+
*
|
|
275
|
+
* Token: AppleScript executes JS in Chrome to read localStorage (requires
|
|
276
|
+
* "Allow JavaScript from Apple Events" in Chrome > View > Developer).
|
|
277
|
+
* Cookie: Reads Chrome's encrypted SQLite cookie database directly. The `d`
|
|
278
|
+
* session cookie is HttpOnly and cannot be accessed via document.cookie.
|
|
279
|
+
* Decryption uses the Chrome Safe Storage key from macOS Keychain.
|
|
152
280
|
*/
|
|
153
281
|
function extractFromChromeInternal() {
|
|
154
282
|
lastExtractionError = null;
|
|
283
|
+
|
|
155
284
|
if (!IS_MACOS) {
|
|
156
|
-
// AppleScript/osascript is macOS-only
|
|
157
285
|
lastExtractionError = {
|
|
158
286
|
code: "unsupported_platform",
|
|
159
287
|
message: "Chrome auto-extraction is only available on macOS.",
|
|
@@ -162,68 +290,51 @@ function extractFromChromeInternal() {
|
|
|
162
290
|
return null;
|
|
163
291
|
}
|
|
164
292
|
|
|
293
|
+
// Extract cookie from Chrome's encrypted cookie database
|
|
294
|
+
let cookie;
|
|
165
295
|
try {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
encoding: 'utf-8', timeout: 5000
|
|
181
|
-
}).trim();
|
|
182
|
-
|
|
183
|
-
if (!cookie || !cookie.startsWith('xoxd-')) {
|
|
184
|
-
lastExtractionError = {
|
|
185
|
-
code: "cookie_not_found",
|
|
186
|
-
message: "Could not extract Slack cookie from Chrome.",
|
|
187
|
-
detail: "Ensure a logged-in Slack tab is open at app.slack.com."
|
|
188
|
-
};
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
296
|
+
cookie = extractCookieFromChromeDB();
|
|
297
|
+
} catch (e) {
|
|
298
|
+
lastExtractionError = normalizeExtractionError(e);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (!cookie) {
|
|
303
|
+
lastExtractionError = {
|
|
304
|
+
code: "cookie_not_found",
|
|
305
|
+
message: "Could not extract Slack session cookie from Chrome.",
|
|
306
|
+
detail: "Ensure you are logged into Slack at app.slack.com in Chrome."
|
|
307
|
+
};
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
191
310
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
repeat with t in tabs of w
|
|
201
|
-
if URL of t contains "slack.com" then
|
|
202
|
-
return execute t javascript "(function() { ${tokenPathsJS} return ''; })()"
|
|
203
|
-
end if
|
|
204
|
-
end repeat
|
|
205
|
-
end repeat
|
|
206
|
-
return ""
|
|
207
|
-
end tell
|
|
208
|
-
`;
|
|
209
|
-
const token = execSync(`osascript -e '${tokenScript.replace(/'/g, "'\"'\"'")}'`, {
|
|
210
|
-
encoding: 'utf-8', timeout: 5000
|
|
211
|
-
}).trim();
|
|
212
|
-
|
|
213
|
-
if (!token || !token.startsWith('xoxc-')) {
|
|
311
|
+
// Extract token via AppleScript (localStorage)
|
|
312
|
+
let token;
|
|
313
|
+
try {
|
|
314
|
+
token = extractTokenFromChrome();
|
|
315
|
+
} catch (e) {
|
|
316
|
+
lastExtractionError = normalizeExtractionError(e);
|
|
317
|
+
// If we got the cookie but not the token, give a specific error
|
|
318
|
+
if (cookie && !token) {
|
|
214
319
|
lastExtractionError = {
|
|
215
|
-
code: "
|
|
216
|
-
message: "
|
|
217
|
-
detail: "
|
|
320
|
+
code: "apple_events_javascript_disabled",
|
|
321
|
+
message: "Cookie extracted, but token extraction requires a Chrome setting.",
|
|
322
|
+
detail: "In Chrome: View > Developer > Allow JavaScript from Apple Events. Then retry."
|
|
218
323
|
};
|
|
219
|
-
return null;
|
|
220
324
|
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
221
327
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
328
|
+
if (!token) {
|
|
329
|
+
lastExtractionError = {
|
|
330
|
+
code: "token_not_found",
|
|
331
|
+
message: "Could not extract Slack token from Chrome.",
|
|
332
|
+
detail: "Ensure a Slack workspace is open in Chrome (not just the landing page). If Chrome blocks AppleScript, enable View > Developer > Allow JavaScript from Apple Events."
|
|
333
|
+
};
|
|
225
334
|
return null;
|
|
226
335
|
}
|
|
336
|
+
|
|
337
|
+
return { token, cookie };
|
|
227
338
|
}
|
|
228
339
|
|
|
229
340
|
/**
|
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": "4.
|
|
5
|
-
"description": "Slack MCP
|
|
4
|
+
"version": "4.1.0",
|
|
5
|
+
"description": "Slack MCP without OAuth — no app registration, no admin approval. Works with Claude Code, Cursor, Copilot (where the official server doesn't). 16 tools, one command.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "src/server.js",
|
|
8
8
|
"bin": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"build:demo-mobile:gif": "node scripts/build-mobile-demo.js --gif",
|
|
31
31
|
"record-demo": "node scripts/record-demo.js",
|
|
32
32
|
"social-preview:update": "node scripts/update-github-social-preview.js --headed",
|
|
33
|
+
"bookmarklet": "node scripts/generate-bookmarklet.js",
|
|
33
34
|
"cf:browser": "node scripts/cloudflare-browser-tool.js",
|
|
34
35
|
"verify:attribution-guardrail": "node scripts/verify-attribution-guardrail.js",
|
|
35
36
|
"verify:public-pages": "node scripts/verify-generated-public-pages.js",
|
|
@@ -61,7 +62,14 @@
|
|
|
61
62
|
"slack-integration",
|
|
62
63
|
"ai-agents",
|
|
63
64
|
"automation",
|
|
64
|
-
"productivity"
|
|
65
|
+
"productivity",
|
|
66
|
+
"oauth-free",
|
|
67
|
+
"no-admin-approval",
|
|
68
|
+
"cursor",
|
|
69
|
+
"copilot",
|
|
70
|
+
"windsurf",
|
|
71
|
+
"codex-cli",
|
|
72
|
+
"stealth-mode"
|
|
65
73
|
],
|
|
66
74
|
"author": {
|
|
67
75
|
"name": "Revasser",
|
package/public/index.html
CHANGED
|
@@ -255,7 +255,7 @@
|
|
|
255
255
|
<div class="container">
|
|
256
256
|
<h1>Slack Web API <span id="status" class="status"></span></h1>
|
|
257
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>
|
|
258
|
+
<span>Hosted version coming soon — <strong style="color:#f0c246">permanent OAuth, semantic search, AI summaries</strong></span>
|
|
259
259
|
<a href="https://mcp.revasserlabs.com" style="color:#f0c246;font-weight:600;text-decoration:none;white-space:nowrap" target="_blank">Learn more →</a>
|
|
260
260
|
</div>
|
|
261
261
|
<div class="grid">
|
package/public/share.html
CHANGED
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>Slack MCP Server</title>
|
|
7
|
-
<meta name="description" content="
|
|
7
|
+
<meta name="description" content="No OAuth. No admin. 16 Slack tools for Claude, Cursor, Copilot, Gemini, and any MCP client. One command: npx -y @jtalk22/slack-mcp --setup">
|
|
8
8
|
<meta property="og:type" content="website">
|
|
9
|
-
<meta property="og:title" content="Slack MCP Server">
|
|
10
|
-
<meta property="og:description" content="
|
|
9
|
+
<meta property="og:title" content="Slack MCP Server — No OAuth, no admin, just your browser session">
|
|
10
|
+
<meta property="og:description" content="Slack's official MCP needs OAuth + admin. This one uses your browser session. 16 tools, works with Claude, Cursor, Copilot, Gemini.">
|
|
11
11
|
<meta property="og:url" content="https://jtalk22.github.io/slack-mcp-server/public/share.html">
|
|
12
12
|
<meta property="og:image" content="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png">
|
|
13
13
|
<meta property="og:image:width" content="1280">
|
|
14
14
|
<meta property="og:image:height" content="640">
|
|
15
15
|
<meta name="twitter:card" content="summary_large_image">
|
|
16
|
-
<meta name="twitter:title" content="Slack MCP Server">
|
|
17
|
-
<meta name="twitter:description" content="
|
|
16
|
+
<meta name="twitter:title" content="Slack MCP Server — No OAuth, no admin, just your browser session">
|
|
17
|
+
<meta name="twitter:description" content="16 tools for Claude, Cursor, Copilot, Gemini. npx -y @jtalk22/slack-mcp --setup">
|
|
18
18
|
<meta name="twitter:image" content="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png">
|
|
19
19
|
<link rel="icon" href="https://jtalk22.github.io/slack-mcp-server/docs/assets/icon-512.png" type="image/png">
|
|
20
20
|
<style>
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
<body>
|
|
108
108
|
<main class="wrap">
|
|
109
109
|
<h1>Slack MCP Server</h1>
|
|
110
|
-
<p class="sub">Give Claude full access to your Slack. Self-host 16 tools for free
|
|
110
|
+
<p class="sub">Give Claude full access to your Slack. Self-host 16 tools for free. Hosted version with semantic search, AI summaries, and permanent OAuth coming soon.</p>
|
|
111
111
|
|
|
112
112
|
<a class="preview" href="https://github.com/jtalk22/slack-mcp-server" rel="noopener">
|
|
113
113
|
<img src="https://jtalk22.github.io/slack-mcp-server/docs/images/social-preview-v3.png" alt="Slack MCP Server social preview card">
|
|
@@ -118,12 +118,12 @@
|
|
|
118
118
|
<a href="https://github.com/jtalk22/slack-mcp-server/blob/main/docs/SETUP.md" rel="noopener">Verify (`--version/--doctor/--status`)</a>
|
|
119
119
|
<a href="https://github.com/jtalk22/slack-mcp-server/releases/latest" rel="noopener">Latest Release</a>
|
|
120
120
|
<a href="https://jtalk22.github.io/slack-mcp-server/" rel="noopener">Autoplay Demo Landing</a>
|
|
121
|
-
<a href="https://jtalk22.github.io/slack-mcp-server/docs/videos/demo-
|
|
121
|
+
<a href="https://jtalk22.github.io/slack-mcp-server/docs/videos/demo-slack-mcp-mobile-20s.mp4" rel="noopener">20s Mobile Clip</a>
|
|
122
122
|
<a href="https://www.npmjs.com/package/@jtalk22/slack-mcp" rel="noopener">npm Package</a>
|
|
123
|
-
<a href="https://mcp.revasserlabs.com" rel="noopener" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">
|
|
123
|
+
<a href="https://mcp.revasserlabs.com" rel="noopener" style="background:rgba(240,194,70,0.18);border-color:rgba(240,194,70,0.45);color:#f0c246">Hosted</a>
|
|
124
124
|
</div>
|
|
125
125
|
|
|
126
|
-
<p class="note"><strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives 16 tools with session-based auth. Works with any MCP client — Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf.
|
|
126
|
+
<p class="note"><strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives 16 tools with session-based auth. Works with any MCP client — Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf. Hosted version coming soon at <a href="https://mcp.revasserlabs.com">mcp.revasserlabs.com</a>.</p>
|
|
127
127
|
</main>
|
|
128
128
|
</body>
|
|
129
129
|
</html>
|
package/scripts/setup-wizard.js
CHANGED
|
@@ -131,10 +131,18 @@ async function runMacOSSetup(rl) {
|
|
|
131
131
|
}
|
|
132
132
|
print();
|
|
133
133
|
if (extractionError?.code === "apple_events_javascript_disabled") {
|
|
134
|
-
print(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
print();
|
|
135
|
+
printBox([
|
|
136
|
+
"Chrome needs one setting enabled (one-time only):",
|
|
137
|
+
"",
|
|
138
|
+
"1. Open Chrome",
|
|
139
|
+
"2. Menu bar: View → Developer → Allow JavaScript",
|
|
140
|
+
" from Apple Events ✓",
|
|
141
|
+
"3. Run this command again",
|
|
142
|
+
], 55);
|
|
143
|
+
print();
|
|
144
|
+
print("Once enabled, --setup extracts tokens automatically.");
|
|
145
|
+
print("No DevTools, no copy-paste, just one command.");
|
|
138
146
|
} else {
|
|
139
147
|
print("Make sure:");
|
|
140
148
|
print(" 1. Chrome is running");
|
|
@@ -180,42 +188,83 @@ async function runManualSetup(rl) {
|
|
|
180
188
|
print();
|
|
181
189
|
if (IS_MACOS) {
|
|
182
190
|
info("Switching to manual token entry...");
|
|
191
|
+
info("Note: On macOS, the session cookie can be extracted automatically.");
|
|
183
192
|
} else {
|
|
184
193
|
info(`Detected platform: ${platform()}`);
|
|
185
194
|
warn("Auto-extraction not available on this platform.");
|
|
186
195
|
}
|
|
196
|
+
|
|
197
|
+
const consoleHotkey = IS_MACOS ? "Cmd+Option+J" : "Ctrl+Shift+J";
|
|
198
|
+
// Token-only one-liner (cookie is HttpOnly and cannot be read via document.cookie)
|
|
199
|
+
const oneLiner = `copy(JSON.parse(localStorage.localConfig_v2).teams[Object.keys(JSON.parse(localStorage.localConfig_v2).teams)[0]].token)`;
|
|
200
|
+
|
|
187
201
|
print();
|
|
188
|
-
print(
|
|
189
|
-
print();
|
|
190
|
-
print(`${colors.bold}Step 1:${colors.reset} Open Chrome and navigate to your Slack workspace`);
|
|
191
|
-
print(" https://app.slack.com");
|
|
202
|
+
print(`${colors.bold}Quick extract (recommended):${colors.reset}`);
|
|
192
203
|
print();
|
|
193
|
-
print(
|
|
204
|
+
print(` 1. Open Chrome → ${colors.cyan}app.slack.com${colors.reset} (must be logged in)`);
|
|
205
|
+
print(` 2. Press ${colors.cyan}${consoleHotkey}${colors.reset} to open the Console`);
|
|
206
|
+
print(` 3. Paste this one-liner and press Enter:`);
|
|
194
207
|
print();
|
|
195
|
-
|
|
208
|
+
printBox([oneLiner], oneLiner.length + 4);
|
|
196
209
|
print();
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
], 55);
|
|
210
|
+
print(` 4. Your token is now on the clipboard. Paste below.`);
|
|
211
|
+
if (IS_MACOS) {
|
|
212
|
+
print(` ${colors.dim}(Cookie will be extracted automatically from Chrome)${colors.reset}`);
|
|
213
|
+
}
|
|
202
214
|
print();
|
|
203
|
-
print(
|
|
215
|
+
print(`${colors.dim}(Or paste a JSON object with token+cookie, or a raw xoxc- token)${colors.reset}`);
|
|
204
216
|
print();
|
|
205
217
|
|
|
206
|
-
const
|
|
218
|
+
const input = await question(rl, `${colors.bold}Paste token:${colors.reset} `);
|
|
219
|
+
const trimmed = input.trim();
|
|
207
220
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
221
|
+
let token, cookie;
|
|
222
|
+
|
|
223
|
+
// Try JSON parse first (legacy one-liner output or manual JSON)
|
|
224
|
+
if (trimmed.startsWith('{')) {
|
|
225
|
+
try {
|
|
226
|
+
const parsed = JSON.parse(trimmed);
|
|
227
|
+
if (parsed.token) token = parsed.token;
|
|
228
|
+
if (parsed.cookie) cookie = parsed.cookie;
|
|
229
|
+
} catch (_) {
|
|
230
|
+
// Not valid JSON — fall through to raw token
|
|
231
|
+
}
|
|
211
232
|
}
|
|
212
233
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
234
|
+
// Treat as raw token
|
|
235
|
+
if (!token) {
|
|
236
|
+
token = trimmed;
|
|
237
|
+
if (!token.startsWith('xoxc-')) {
|
|
238
|
+
error("Invalid input. Expected a token starting with 'xoxc-'");
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// On macOS, try to extract cookie from Chrome's cookie database automatically
|
|
244
|
+
if (!cookie && IS_MACOS) {
|
|
245
|
+
print();
|
|
246
|
+
print("Extracting session cookie from Chrome...");
|
|
247
|
+
const chromeTokens = extractFromChrome();
|
|
248
|
+
if (chromeTokens?.cookie) {
|
|
249
|
+
cookie = chromeTokens.cookie;
|
|
250
|
+
success("Cookie extracted from Chrome automatically");
|
|
251
|
+
} else {
|
|
252
|
+
warn("Could not extract cookie automatically.");
|
|
253
|
+
print(` Paste the cookie manually. In Chrome: ${colors.cyan}Application${colors.reset} tab → ${colors.cyan}Cookies${colors.reset} → find '${colors.cyan}d${colors.reset}'`);
|
|
254
|
+
print();
|
|
255
|
+
const cookieInput = await question(rl, `${colors.bold}Paste cookie (xoxd-...):${colors.reset} `);
|
|
256
|
+
cookie = cookieInput.trim();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
217
259
|
|
|
218
|
-
|
|
260
|
+
// Non-macOS: always ask for cookie
|
|
261
|
+
if (!cookie) {
|
|
262
|
+
print();
|
|
263
|
+
print(`Paste the cookie. In Chrome: ${colors.cyan}Application${colors.reset} tab → ${colors.cyan}Cookies${colors.reset} → find '${colors.cyan}d${colors.reset}'`);
|
|
264
|
+
print();
|
|
265
|
+
const cookieInput = await question(rl, `${colors.bold}Paste cookie (xoxd-...):${colors.reset} `);
|
|
266
|
+
cookie = cookieInput.trim();
|
|
267
|
+
}
|
|
219
268
|
|
|
220
269
|
if (!cookie.startsWith('xoxd-')) {
|
|
221
270
|
error("Invalid cookie. Cookie should start with 'xoxd-'");
|
package/server.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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": "Slack MCP
|
|
5
|
+
"description": "Slack MCP without OAuth — no app registration, no admin approval. Works with Claude Code, Cursor, Copilot (where the official server doesn't). 16 tools, one command.",
|
|
6
6
|
"websiteUrl": "https://mcp.revasserlabs.com",
|
|
7
7
|
"icons": [
|
|
8
8
|
{
|
|
@@ -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.1.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.1.0",
|
|
32
32
|
"transport": {
|
|
33
33
|
"type": "stdio"
|
|
34
34
|
},
|