@jtalk22/slack-mcp 1.1.9 → 1.2.1
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/LICENSE +1 -1
- package/README.md +71 -79
- package/docs/API.md +1 -1
- package/docs/SETUP.md +1 -1
- package/docs/assets/icon-512.png +0 -0
- package/docs/assets/icon.svg +27 -0
- package/docs/images/demo-claude-v1.2.gif +0 -0
- package/docs/images/demo-poster.png +0 -0
- package/docs/images/demo-readme.gif +0 -0
- package/docs/images/diagram-oauth-comparison.svg +80 -0
- package/docs/images/diagram-session-flow.svg +105 -0
- package/docs/videos/.gitkeep +0 -0
- package/docs/videos/demo-claude-v1.2.webm +0 -0
- package/lib/slack-client.js +35 -6
- package/lib/tools.js +69 -0
- package/package.json +10 -5
- package/public/demo-claude.html +1838 -0
- package/public/demo-video.html +151 -0
- package/scripts/record-demo.js +149 -0
- package/scripts/setup-wizard.js +363 -0
- package/src/cli.js +57 -0
- package/src/server-http.js +1 -1
- package/src/server.js +170 -3
- package/src/web-server.js +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://jtalk22.github.io/slack-mcp-server/public/demo.html"><img src="docs/assets/icon-512.png" alt="Slack MCP Server" width="80"></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Slack MCP Server</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<em>Give Claude the same Slack access you have.<br>
|
|
9
|
+
DMs, threads, history—no admin approval.</em>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://jtalk22.github.io/slack-mcp-server/public/demo-video.html">
|
|
14
|
+
<img src="docs/images/demo-readme.gif" alt="Slack MCP tools in action" width="640">
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://www.npmjs.com/package/@jtalk22/slack-mcp"><img src="https://img.shields.io/badge/npm-Install-blue?style=for-the-badge&logo=npm&logoColor=white" alt="npm"></a>
|
|
20
|
+
<a href="https://github.com/jtalk22/slack-mcp-server/pkgs/container/slack-mcp-server"><img src="https://img.shields.io/badge/Docker-Pull-2496ED?style=for-the-badge&logo=docker&logoColor=white" alt="Docker"></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://jtalk22.github.io/slack-mcp-server/public/demo.html"><img src="https://img.shields.io/badge/LIVE%20DEMO-Try%20It%20Now-00C853?style=for-the-badge&logo=slack&logoColor=white" alt="Live Demo"></a>
|
|
25
|
+
<a href="https://jtalk22.github.io/slack-mcp-server/public/demo-claude.html"><img src="https://img.shields.io/badge/CLAUDE%20DEMO-See%20MCP%20Tools-da7756?style=for-the-badge" alt="Claude Demo"></a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<br>
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://www.npmjs.com/package/@jtalk22/slack-mcp"><img src="https://img.shields.io/npm/dm/@jtalk22/slack-mcp?label=downloads&color=CB3837" alt="npm downloads"></a>
|
|
32
|
+
<a href="https://github.com/jtalk22/slack-mcp-server/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/jtalk22/slack-mcp-server/ci.yml?label=build" alt="Build Status"></a>
|
|
33
|
+
<a href="https://smithery.ai/server/jtalk22/slack-mcp-server"><img src="https://img.shields.io/badge/Smithery-Registry-4A154B" alt="Smithery"></a>
|
|
34
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
35
|
+
<a href="https://github.com/sponsors/jtalk22"><img src="https://img.shields.io/badge/Sponsor-♡-ea4aaa?logo=github" alt="Sponsor"></a>
|
|
36
|
+
</p>
|
|
12
37
|
|
|
13
38
|
---
|
|
14
39
|
|
|
@@ -22,57 +47,17 @@ This server bridges the gap. It creates a secure, local bridge between Claude an
|
|
|
22
47
|
|
|
23
48
|

|
|
24
49
|
|
|
25
|
-
> **[Try the Interactive Demo](https://jtalk22.github.io/slack-mcp-server/public/demo.html)** - See the Web UI in action
|
|
26
|
-
|
|
27
50
|
---
|
|
28
51
|
|
|
29
52
|
## Architecture: Local Session Mirroring
|
|
30
53
|
|
|
31
54
|
Instead of authenticating as a bot, this server leverages your existing Chrome session credentials (macOS) or manual token injection (Linux/Windows). It mirrors your user access exactly—if you can see it in Slack, Claude can see it too.
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
sequenceDiagram
|
|
35
|
-
participant Chrome as Chrome Browser
|
|
36
|
-
participant Script as AppleScript
|
|
37
|
-
participant Store as Token Store
|
|
38
|
-
participant MCP as MCP Server
|
|
39
|
-
participant Slack as Slack API
|
|
40
|
-
|
|
41
|
-
Note over Chrome: You're logged into Slack
|
|
42
|
-
Script->>Chrome: Execute JavaScript in Slack tab
|
|
43
|
-
Chrome-->>Script: xoxc- token + xoxd- cookie
|
|
44
|
-
Script->>Store: Save to ~/.slack-mcp-tokens.json
|
|
45
|
-
Store->>Store: Encrypt in macOS Keychain
|
|
46
|
-
|
|
47
|
-
Note over MCP: Claude asks for DMs
|
|
48
|
-
MCP->>Store: Load credentials
|
|
49
|
-
Store-->>MCP: Token + Cookie
|
|
50
|
-
MCP->>Slack: GET conversations.history
|
|
51
|
-
Slack-->>MCP: Full message history
|
|
52
|
-
MCP-->>MCP: Return to Claude
|
|
53
|
-
```
|
|
56
|
+

|
|
54
57
|
|
|
55
58
|
### Why Not OAuth?
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
flowchart LR
|
|
59
|
-
subgraph Traditional["Official Slack API (OAuth)"]
|
|
60
|
-
A[Create App] --> B[Request Scopes]
|
|
61
|
-
B --> C[Admin Approval]
|
|
62
|
-
C --> D[User Authorization]
|
|
63
|
-
D --> E[Limited Access]
|
|
64
|
-
E --> F["No DMs without<br/>per-conversation consent"]
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
subgraph ThisServer["Session Mirroring"]
|
|
68
|
-
G[Open Slack in Chrome] --> H[Mirror Session]
|
|
69
|
-
H --> I[Full Access]
|
|
70
|
-
I --> J["Your DMs, Channels,<br/>Search, History"]
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
style Traditional fill:#ffcccc
|
|
74
|
-
style ThisServer fill:#ccffcc
|
|
75
|
-
```
|
|
60
|
+

|
|
76
61
|
|
|
77
62
|
**Trade-off:** Session tokens expire every 1-2 weeks. Auto-refresh (macOS) or manual update keeps things running.
|
|
78
63
|
|
|
@@ -113,6 +98,8 @@ flowchart LR
|
|
|
113
98
|
|
|
114
99
|
## Quick Start
|
|
115
100
|
|
|
101
|
+
**Runtime:** Node.js 20+
|
|
102
|
+
|
|
116
103
|
### Option A: npm (Recommended)
|
|
117
104
|
|
|
118
105
|
```bash
|
|
@@ -139,32 +126,37 @@ docker pull ghcr.io/jtalk22/slack-mcp-server:latest
|
|
|
139
126
|
|
|
140
127
|
### Step 1: Get Your Tokens
|
|
141
128
|
|
|
142
|
-
####
|
|
129
|
+
#### Setup Wizard (Recommended)
|
|
130
|
+
|
|
131
|
+
The interactive setup wizard handles token extraction and validation automatically:
|
|
132
|
+
|
|
143
133
|
```bash
|
|
144
|
-
|
|
145
|
-
npx @jtalk22/slack-mcp tokens:auto
|
|
146
|
-
# Or if cloned: npm run tokens:auto
|
|
134
|
+
npx @jtalk22/slack-mcp --setup
|
|
147
135
|
```
|
|
148
136
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
137
|
+
- **macOS**: Auto-extracts tokens from Chrome (have Slack open in a tab)
|
|
138
|
+
- **Linux/Windows**: Guides you through manual extraction step-by-step
|
|
139
|
+
- Validates tokens against Slack API before saving
|
|
140
|
+
- Stores tokens securely at `~/.slack-mcp-tokens.json`
|
|
141
|
+
|
|
142
|
+
#### Check Token Status
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npx @jtalk22/slack-mcp --status
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Alternative: Manual Token Scripts
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# macOS auto-extraction
|
|
152
|
+
npm run tokens:auto
|
|
153
|
+
|
|
154
|
+
# Manual entry (all platforms)
|
|
155
|
+
npm run tokens:refresh
|
|
156
|
+
|
|
157
|
+
# Check health
|
|
158
|
+
npm run tokens:status
|
|
159
|
+
```
|
|
168
160
|
|
|
169
161
|
### Step 2: Configure Claude
|
|
170
162
|
|
|
@@ -285,9 +277,9 @@ finally { refreshInProgress = false; }
|
|
|
285
277
|
|
|
286
278
|
---
|
|
287
279
|
|
|
288
|
-
## Web UI (for claude.ai)
|
|
280
|
+
## Web UI (for claude.ai — no MCP support)
|
|
289
281
|
|
|
290
|
-
|
|
282
|
+
If you're using claude.ai in a browser (which doesn't support MCP), you can use the REST server instead:
|
|
291
283
|
|
|
292
284
|
```bash
|
|
293
285
|
npm run web
|
|
@@ -298,7 +290,7 @@ npm run web
|
|
|
298
290
|
|
|
299
291
|
```
|
|
300
292
|
════════════════════════════════════════════════════════════
|
|
301
|
-
Slack Web API Server v1.1
|
|
293
|
+
Slack Web API Server v1.2.1
|
|
302
294
|
════════════════════════════════════════════════════════════
|
|
303
295
|
|
|
304
296
|
Dashboard: http://localhost:3000/?key=smcp_xxxxxxxxxxxx
|
package/docs/API.md
CHANGED
|
@@ -199,7 +199,7 @@ Search messages across the workspace.
|
|
|
199
199
|
"ts": "1767368030.607599",
|
|
200
200
|
"channel": "general",
|
|
201
201
|
"channel_id": "C05GPEVH7J9",
|
|
202
|
-
"user": "
|
|
202
|
+
"user": "Example User",
|
|
203
203
|
"text": "Here's the project update...",
|
|
204
204
|
"datetime": "2026-01-02T15:33:50.000Z",
|
|
205
205
|
"permalink": "https://..."
|
package/docs/SETUP.md
CHANGED
|
Binary file
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#4A154B"/>
|
|
5
|
+
<stop offset="100%" style="stop-color:#3D1140"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
|
|
9
|
+
<!-- Background rounded square -->
|
|
10
|
+
<rect x="0" y="0" width="512" height="512" rx="96" ry="96" fill="url(#bg)"/>
|
|
11
|
+
|
|
12
|
+
<!-- Stylized hashtag/channel symbol -->
|
|
13
|
+
<g fill="none" stroke="#FFFFFF" stroke-width="36" stroke-linecap="round">
|
|
14
|
+
<!-- Vertical lines -->
|
|
15
|
+
<line x1="180" y1="140" x2="160" y2="372"/>
|
|
16
|
+
<line x1="352" y1="140" x2="332" y2="372"/>
|
|
17
|
+
<!-- Horizontal lines -->
|
|
18
|
+
<line x1="120" y1="200" x2="392" y2="200"/>
|
|
19
|
+
<line x1="120" y1="312" x2="392" y2="312"/>
|
|
20
|
+
</g>
|
|
21
|
+
|
|
22
|
+
<!-- Slack-colored connection dots (representing MCP bridge) -->
|
|
23
|
+
<circle cx="420" cy="92" r="28" fill="#36C5F0"/>
|
|
24
|
+
<circle cx="92" cy="420" r="28" fill="#2EB67D"/>
|
|
25
|
+
<circle cx="420" cy="420" r="28" fill="#ECB22E"/>
|
|
26
|
+
<circle cx="92" cy="92" r="28" fill="#E01E5A"/>
|
|
27
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 420">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bgGrad2" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#1a1a2e"/>
|
|
5
|
+
<stop offset="100%" style="stop-color:#16213e"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<marker id="arrowRed2" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
8
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#e94560"/>
|
|
9
|
+
</marker>
|
|
10
|
+
<marker id="arrowTeal2" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
11
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#4ecdc4"/>
|
|
12
|
+
</marker>
|
|
13
|
+
</defs>
|
|
14
|
+
|
|
15
|
+
<!-- Background -->
|
|
16
|
+
<rect width="900" height="420" fill="url(#bgGrad2)" rx="12"/>
|
|
17
|
+
|
|
18
|
+
<!-- Left Side: OAuth (Red-tinted) -->
|
|
19
|
+
<rect x="30" y="50" width="400" height="340" rx="12" fill="#e94560" opacity="0.1" stroke="#e94560" stroke-width="2"/>
|
|
20
|
+
<text x="230" y="85" text-anchor="middle" fill="#fca5a5" font-family="system-ui, -apple-system, sans-serif" font-size="16" font-weight="600">Official Slack API (OAuth)</text>
|
|
21
|
+
|
|
22
|
+
<!-- OAuth Flow - Row 1 -->
|
|
23
|
+
<rect x="45" y="110" width="120" height="45" rx="8" fill="#2d2d2d" stroke="#e94560" stroke-width="1"/>
|
|
24
|
+
<text x="105" y="138" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12">Create App</text>
|
|
25
|
+
|
|
26
|
+
<path d="M 170 132 L 190 132" stroke="#e94560" stroke-width="2" marker-end="url(#arrowRed2)"/>
|
|
27
|
+
|
|
28
|
+
<rect x="195" y="110" width="120" height="45" rx="8" fill="#2d2d2d" stroke="#e94560" stroke-width="1"/>
|
|
29
|
+
<text x="255" y="138" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12">Request Scopes</text>
|
|
30
|
+
|
|
31
|
+
<path d="M 320 132 L 340 132" stroke="#e94560" stroke-width="2" marker-end="url(#arrowRed2)"/>
|
|
32
|
+
|
|
33
|
+
<rect x="345" y="110" width="75" height="45" rx="8" fill="#e94560" opacity="0.4" stroke="#e94560" stroke-width="1"/>
|
|
34
|
+
<text x="382" y="128" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="600">Admin</text>
|
|
35
|
+
<text x="382" y="144" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="11" font-weight="600">Approval</text>
|
|
36
|
+
|
|
37
|
+
<!-- Arrow down from Admin Approval -->
|
|
38
|
+
<path d="M 382 160 L 382 195" stroke="#e94560" stroke-width="2" marker-end="url(#arrowRed2)"/>
|
|
39
|
+
|
|
40
|
+
<!-- OAuth Flow - Row 2 -->
|
|
41
|
+
<rect x="95" y="205" width="140" height="45" rx="8" fill="#2d2d2d" stroke="#e94560" stroke-width="1"/>
|
|
42
|
+
<text x="165" y="233" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12">User Authorization</text>
|
|
43
|
+
|
|
44
|
+
<path d="M 240 227 L 260 227" stroke="#e94560" stroke-width="2" marker-end="url(#arrowRed2)"/>
|
|
45
|
+
|
|
46
|
+
<rect x="265" y="205" width="140" height="45" rx="8" fill="#2d2d2d" stroke="#e94560" stroke-width="1"/>
|
|
47
|
+
<text x="335" y="233" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12">Limited Access</text>
|
|
48
|
+
|
|
49
|
+
<!-- OAuth Result (blocked) -->
|
|
50
|
+
<rect x="70" y="280" width="290" height="60" rx="8" fill="#e94560" opacity="0.15" stroke="#e94560" stroke-width="2" stroke-dasharray="4"/>
|
|
51
|
+
<text x="215" y="305" text-anchor="middle" fill="#fca5a5" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">No DMs without</text>
|
|
52
|
+
<text x="215" y="325" text-anchor="middle" fill="#fca5a5" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">per-conversation consent</text>
|
|
53
|
+
|
|
54
|
+
<!-- Right Side: Session Mirroring (Green-tinted) -->
|
|
55
|
+
<rect x="470" y="50" width="400" height="340" rx="12" fill="#4ecdc4" opacity="0.1" stroke="#4ecdc4" stroke-width="2"/>
|
|
56
|
+
<text x="670" y="85" text-anchor="middle" fill="#5eead4" font-family="system-ui, -apple-system, sans-serif" font-size="16" font-weight="600">Session Mirroring</text>
|
|
57
|
+
|
|
58
|
+
<!-- Session Mirroring Flow -->
|
|
59
|
+
<rect x="495" y="120" width="160" height="50" rx="8" fill="#3b82f6" opacity="0.9"/>
|
|
60
|
+
<text x="575" y="150" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="500">Open Slack in Chrome</text>
|
|
61
|
+
|
|
62
|
+
<path d="M 660 145 L 700 145" stroke="#4ecdc4" stroke-width="3" marker-end="url(#arrowTeal2)"/>
|
|
63
|
+
|
|
64
|
+
<rect x="705" y="120" width="140" height="50" rx="8" fill="#da7756" opacity="0.9"/>
|
|
65
|
+
<text x="775" y="150" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="500">Mirror Session</text>
|
|
66
|
+
|
|
67
|
+
<path d="M 775 175 L 775 210" stroke="#4ecdc4" stroke-width="3" marker-end="url(#arrowTeal2)"/>
|
|
68
|
+
|
|
69
|
+
<rect x="605" y="220" width="160" height="50" rx="8" fill="#4ecdc4" opacity="0.9"/>
|
|
70
|
+
<text x="685" y="250" text-anchor="middle" fill="#1a1a2e" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600">Full Access</text>
|
|
71
|
+
|
|
72
|
+
<!-- Session Mirroring Result (success) -->
|
|
73
|
+
<rect x="510" y="295" width="340" height="60" rx="8" fill="#4ecdc4" opacity="0.2" stroke="#4ecdc4" stroke-width="2"/>
|
|
74
|
+
<text x="680" y="320" text-anchor="middle" fill="#5eead4" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">Your DMs, Channels, Search, History</text>
|
|
75
|
+
<text x="680" y="340" text-anchor="middle" fill="#5eead4" font-family="system-ui, -apple-system, sans-serif" font-size="11">✓ Same access as your browser</text>
|
|
76
|
+
|
|
77
|
+
<!-- VS divider -->
|
|
78
|
+
<circle cx="450" cy="210" r="24" fill="#1a1a2e" stroke="#ffffff" stroke-width="2" opacity="0.9"/>
|
|
79
|
+
<text x="450" y="216" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="700">vs</text>
|
|
80
|
+
</svg>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 400">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#1a1a2e"/>
|
|
5
|
+
<stop offset="100%" style="stop-color:#16213e"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<filter id="glow">
|
|
8
|
+
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
|
9
|
+
<feMerge>
|
|
10
|
+
<feMergeNode in="coloredBlur"/>
|
|
11
|
+
<feMergeNode in="SourceGraphic"/>
|
|
12
|
+
</feMerge>
|
|
13
|
+
</filter>
|
|
14
|
+
</defs>
|
|
15
|
+
|
|
16
|
+
<!-- Background -->
|
|
17
|
+
<rect width="900" height="400" fill="url(#bgGrad)" rx="12"/>
|
|
18
|
+
|
|
19
|
+
<!-- Title -->
|
|
20
|
+
<text x="450" y="35" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="18" font-weight="600">Session Mirroring Flow</text>
|
|
21
|
+
|
|
22
|
+
<!-- Participants -->
|
|
23
|
+
<!-- Chrome -->
|
|
24
|
+
<rect x="50" y="60" width="120" height="40" rx="8" fill="#3b82f6" opacity="0.9"/>
|
|
25
|
+
<text x="110" y="85" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">Chrome</text>
|
|
26
|
+
<line x1="110" y1="100" x2="110" y2="360" stroke="#3b82f6" stroke-width="2" stroke-dasharray="4"/>
|
|
27
|
+
|
|
28
|
+
<!-- AppleScript -->
|
|
29
|
+
<rect x="220" y="60" width="120" height="40" rx="8" fill="#8b5cf6" opacity="0.9"/>
|
|
30
|
+
<text x="280" y="85" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">AppleScript</text>
|
|
31
|
+
<line x1="280" y1="100" x2="280" y2="360" stroke="#8b5cf6" stroke-width="2" stroke-dasharray="4"/>
|
|
32
|
+
|
|
33
|
+
<!-- Token Store -->
|
|
34
|
+
<rect x="390" y="60" width="120" height="40" rx="8" fill="#4ecdc4" opacity="0.9"/>
|
|
35
|
+
<text x="450" y="85" text-anchor="middle" fill="#1a1a2e" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">Token Store</text>
|
|
36
|
+
<line x1="450" y1="100" x2="450" y2="360" stroke="#4ecdc4" stroke-width="2" stroke-dasharray="4"/>
|
|
37
|
+
|
|
38
|
+
<!-- MCP Server -->
|
|
39
|
+
<rect x="560" y="60" width="120" height="40" rx="8" fill="#da7756" opacity="0.9"/>
|
|
40
|
+
<text x="620" y="85" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">MCP Server</text>
|
|
41
|
+
<line x1="620" y1="100" x2="620" y2="360" stroke="#da7756" stroke-width="2" stroke-dasharray="4"/>
|
|
42
|
+
|
|
43
|
+
<!-- Slack API -->
|
|
44
|
+
<rect x="730" y="60" width="120" height="40" rx="8" fill="#e94560" opacity="0.9"/>
|
|
45
|
+
<text x="790" y="85" text-anchor="middle" fill="#ffffff" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500">Slack API</text>
|
|
46
|
+
<line x1="790" y1="100" x2="790" y2="360" stroke="#e94560" stroke-width="2" stroke-dasharray="4"/>
|
|
47
|
+
|
|
48
|
+
<!-- Note: Logged into Slack -->
|
|
49
|
+
<rect x="60" y="115" width="100" height="30" rx="4" fill="#3b82f6" opacity="0.2" stroke="#3b82f6" stroke-width="1"/>
|
|
50
|
+
<text x="110" y="135" text-anchor="middle" fill="#93c5fd" font-family="system-ui, -apple-system, sans-serif" font-size="10">Logged into Slack</text>
|
|
51
|
+
|
|
52
|
+
<!-- Arrow 1: Script → Chrome -->
|
|
53
|
+
<line x1="280" y1="160" x2="130" y2="160" stroke="#8b5cf6" stroke-width="2" marker-end="url(#arrowPurple)"/>
|
|
54
|
+
<text x="205" y="153" text-anchor="middle" fill="#c4b5fd" font-family="system-ui, -apple-system, sans-serif" font-size="10">Execute JS in tab</text>
|
|
55
|
+
|
|
56
|
+
<!-- Arrow 2: Chrome → Script (dashed return) -->
|
|
57
|
+
<line x1="130" y1="185" x2="260" y2="185" stroke="#3b82f6" stroke-width="2" stroke-dasharray="5" marker-end="url(#arrowBlue)"/>
|
|
58
|
+
<text x="195" y="200" text-anchor="middle" fill="#93c5fd" font-family="system-ui, -apple-system, sans-serif" font-size="10">xoxc- + xoxd- tokens</text>
|
|
59
|
+
|
|
60
|
+
<!-- Arrow 3: Script → Store -->
|
|
61
|
+
<line x1="300" y1="225" x2="430" y2="225" stroke="#8b5cf6" stroke-width="2" marker-end="url(#arrowPurple)"/>
|
|
62
|
+
<text x="365" y="218" text-anchor="middle" fill="#c4b5fd" font-family="system-ui, -apple-system, sans-serif" font-size="10">Save tokens</text>
|
|
63
|
+
|
|
64
|
+
<!-- Store self-arrow (Keychain) -->
|
|
65
|
+
<path d="M 470 245 Q 500 245 500 260 Q 500 275 470 275" fill="none" stroke="#4ecdc4" stroke-width="2"/>
|
|
66
|
+
<text x="515" y="265" fill="#5eead4" font-family="system-ui, -apple-system, sans-serif" font-size="10">Keychain encrypt</text>
|
|
67
|
+
|
|
68
|
+
<!-- Divider -->
|
|
69
|
+
<line x1="50" y1="300" x2="850" y2="300" stroke="#ffffff" stroke-width="1" opacity="0.2"/>
|
|
70
|
+
<text x="60" y="295" fill="#ffffff" opacity="0.5" font-family="system-ui, -apple-system, sans-serif" font-size="10">Claude requests data</text>
|
|
71
|
+
|
|
72
|
+
<!-- Arrow 4: MCP → Store -->
|
|
73
|
+
<line x1="600" y1="320" x2="470" y2="320" stroke="#da7756" stroke-width="2" marker-end="url(#arrowOrange)"/>
|
|
74
|
+
<text x="535" y="313" text-anchor="middle" fill="#fbbf8c" font-family="system-ui, -apple-system, sans-serif" font-size="10">Load creds</text>
|
|
75
|
+
|
|
76
|
+
<!-- Arrow 5: Store → MCP (return) -->
|
|
77
|
+
<line x1="470" y1="340" x2="600" y2="340" stroke="#4ecdc4" stroke-width="2" stroke-dasharray="5" marker-end="url(#arrowTeal)"/>
|
|
78
|
+
|
|
79
|
+
<!-- Arrow 6: MCP → Slack -->
|
|
80
|
+
<line x1="640" y1="355" x2="770" y2="355" stroke="#da7756" stroke-width="2" marker-end="url(#arrowOrange)"/>
|
|
81
|
+
<text x="705" y="348" text-anchor="middle" fill="#fbbf8c" font-family="system-ui, -apple-system, sans-serif" font-size="10">GET messages</text>
|
|
82
|
+
|
|
83
|
+
<!-- Arrow 7: Slack → MCP (return) -->
|
|
84
|
+
<line x1="770" y1="375" x2="640" y2="375" stroke="#e94560" stroke-width="2" stroke-dasharray="5" marker-end="url(#arrowRed)"/>
|
|
85
|
+
<text x="705" y="390" text-anchor="middle" fill="#fca5a5" font-family="system-ui, -apple-system, sans-serif" font-size="10">Full history</text>
|
|
86
|
+
|
|
87
|
+
<!-- Arrow markers -->
|
|
88
|
+
<defs>
|
|
89
|
+
<marker id="arrowPurple" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
90
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#8b5cf6"/>
|
|
91
|
+
</marker>
|
|
92
|
+
<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
93
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#3b82f6"/>
|
|
94
|
+
</marker>
|
|
95
|
+
<marker id="arrowTeal" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
96
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#4ecdc4"/>
|
|
97
|
+
</marker>
|
|
98
|
+
<marker id="arrowOrange" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
99
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#da7756"/>
|
|
100
|
+
</marker>
|
|
101
|
+
<marker id="arrowRed" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
102
|
+
<path d="M0,0 L0,6 L9,3 z" fill="#e94560"/>
|
|
103
|
+
</marker>
|
|
104
|
+
</defs>
|
|
105
|
+
</svg>
|
|
File without changes
|
|
Binary file
|
package/lib/slack-client.js
CHANGED
|
@@ -24,6 +24,15 @@ const RETRYABLE_NETWORK_ERRORS = [
|
|
|
24
24
|
'ECONNREFUSED', 'EPIPE', 'UND_ERR_CONNECT_TIMEOUT'
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
+
// Slack API methods that require form-encoded params instead of JSON
|
|
28
|
+
const FORM_ENCODED_METHODS = new Set([
|
|
29
|
+
"conversations.replies",
|
|
30
|
+
"search.messages",
|
|
31
|
+
"search.all",
|
|
32
|
+
"search.files",
|
|
33
|
+
"users.info",
|
|
34
|
+
]);
|
|
35
|
+
|
|
27
36
|
let lastRefreshAttempt = 0;
|
|
28
37
|
|
|
29
38
|
// ============ LRU Cache with TTL ============
|
|
@@ -149,16 +158,36 @@ export async function slackAPI(method, params = {}, options = {}) {
|
|
|
149
158
|
checkTokenHealth({ error: () => {} }).catch(() => {});
|
|
150
159
|
}
|
|
151
160
|
|
|
161
|
+
const useForm = FORM_ENCODED_METHODS.has(method);
|
|
162
|
+
|
|
152
163
|
let response;
|
|
153
164
|
try {
|
|
165
|
+
const headers = {
|
|
166
|
+
"Authorization": `Bearer ${creds.token}`,
|
|
167
|
+
"Cookie": `d=${creds.cookie}`,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
let body;
|
|
171
|
+
if (useForm) {
|
|
172
|
+
// URLSearchParams coerces non-primitives to "[object Object]",
|
|
173
|
+
// so stringify any arrays/objects before encoding.
|
|
174
|
+
const safeParams = {};
|
|
175
|
+
for (const [key, value] of Object.entries(params)) {
|
|
176
|
+
safeParams[key] = (typeof value === "object" && value !== null)
|
|
177
|
+
? JSON.stringify(value)
|
|
178
|
+
: String(value);
|
|
179
|
+
}
|
|
180
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8";
|
|
181
|
+
body = new URLSearchParams(safeParams).toString();
|
|
182
|
+
} else {
|
|
183
|
+
headers["Content-Type"] = "application/json; charset=utf-8";
|
|
184
|
+
body = JSON.stringify(params);
|
|
185
|
+
}
|
|
186
|
+
|
|
154
187
|
response = await fetch(`https://slack.com/api/${method}`, {
|
|
155
188
|
method: "POST",
|
|
156
|
-
headers
|
|
157
|
-
|
|
158
|
-
"Cookie": `d=${creds.cookie}`,
|
|
159
|
-
"Content-Type": "application/json; charset=utf-8",
|
|
160
|
-
},
|
|
161
|
-
body: JSON.stringify(params),
|
|
189
|
+
headers,
|
|
190
|
+
body,
|
|
162
191
|
});
|
|
163
192
|
} catch (networkError) {
|
|
164
193
|
// Retry on network errors with exponential backoff + jitter
|