@jtalk22/slack-mcp 3.2.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,24 +1,28 @@
1
1
  # Slack MCP Server
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@jtalk22/slack-mcp)](https://www.npmjs.com/package/@jtalk22/slack-mcp)
4
- [![npm downloads](https://img.shields.io/npm/dm/@jtalk22/slack-mcp)](https://www.npmjs.com/package/@jtalk22/slack-mcp)
5
4
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io)
6
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
7
6
 
8
- Give Claude your Slack. 16 self-hosted tools for channels, search, replies, reactions, unread triage, and user search. Self-host free or use Slack MCP Cloud for Claude-first managed transport, Gemini CLI support, hosted credential handling, deployment review, and procurement-ready security review.
9
-
10
- ## Verify & Proof
7
+ Give your AI agent full Slack access. No app registration, no admin approval, no OAuth. One command, 16 tools, works with any MCP client.
11
8
 
12
9
  ```bash
13
10
  npx -y @jtalk22/slack-mcp --setup
14
- npx -y @jtalk22/slack-mcp@latest --version
15
- npx -y @jtalk22/slack-mcp@latest --doctor
16
- npx -y @jtalk22/slack-mcp@latest --status
17
11
  ```
18
12
 
19
- [20-second demo](https://jtalk22.github.io/slack-mcp-server/public/demo-video.html) · [Interactive demo](https://jtalk22.github.io/slack-mcp-server/public/demo.html) · [Start here discussion](https://github.com/jtalk22/slack-mcp-server/discussions/12) · [Latest release notes](https://github.com/jtalk22/slack-mcp-server/releases/latest) · [Release-day runbook](docs/LAUNCH-OPS.md) · [Commercial surface map](docs/COMMERCIAL-SURFACE.md) · [Distribution ledger](docs/DISTRIBUTION-LEDGER.md) · [Release health snapshot](docs/release-health/latest.md) · [Version parity report](docs/release-health/version-parity.md) · [Cloud pricing](https://mcp.revasserlabs.com/pricing?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Workflows](https://mcp.revasserlabs.com/workflows?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Gemini CLI](https://mcp.revasserlabs.com/gemini-cli?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Readiness](https://mcp.revasserlabs.com/readiness?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Cloud deployment](https://mcp.revasserlabs.com/deployment?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Cloud security](https://mcp.revasserlabs.com/security?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Cloud support](https://mcp.revasserlabs.com/support?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud)
13
+ ![demo](docs/images/demo-readme.gif)
14
+
15
+ > **Ask Claude to catch you up on #engineering from the last 24 hours.** Search for that deployment thread from last week. Find every message mentioning the API key. Send a reply. All from your editor.
16
+
17
+ [Interactive demo](https://jtalk22.github.io/slack-mcp-server/public/demo.html) · [Latest release](https://github.com/jtalk22/slack-mcp-server/releases/latest)
18
+
19
+ ## Why This Exists
20
+
21
+ Slack's official MCP server requires a registered app, admin approval, and [doesn't work with Claude Code or GitHub Copilot](https://github.com/anthropics/claude-code/issues/30564) due to OAuth/DCR incompatibility. Screenshotting messages is not a workflow.
22
+
23
+ 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.
20
24
 
21
- [![Slack MCP proof surface](docs/images/demo-poster.png)](https://jtalk22.github.io/slack-mcp-server/public/demo-video.html)
25
+ ![OAuth vs Session](docs/images/diagram-oauth-comparison.svg)
22
26
 
23
27
  ## Tools
24
28
 
@@ -41,44 +45,19 @@ npx -y @jtalk22/slack-mcp@latest --status
41
45
  | `slack_remove_reaction` | Remove an emoji reaction from a message | **destructive** |
42
46
  | `slack_conversations_mark` | Mark a conversation as read | **destructive** |
43
47
 
44
- All tools carry [MCP safety annotations](https://modelcontextprotocol.io/specification/2025-03-26/server/tools#annotations): 12 read-only (`readOnlyHint: true`), 4 write-path (`destructiveHint: true`). Only `slack_send_message` is non-idempotent.
45
-
46
- \* `slack_refresh_tokens` modifies local token file only — no external Slack state.
47
-
48
- ## Cloud
49
-
50
- Slack MCP Cloud provides 15 managed tools with hosted credential handling. Team adds 3 AI compound workflows for summaries, action items, and decisions. Claude is the primary path; Gemini CLI is the second supported client path on the hosted endpoint.
51
-
52
- - Self-host if you want 16 tools, npm or Docker, and full operator control over runtime and tokens.
53
- - Use Cloud if you want one remote endpoint, hosted credential handling, deployment review, buyer-facing security review, support, and a hosted account surface.
54
- - Solo starts at `$19/mo`; Team is `$49/mo` and adds 3 AI workflows plus higher request capacity.
55
- - Turnkey Team Launch starts at `$2.5k+`; Managed Reliability starts at `$800/mo+` for teams where rollout and operational continuity matter more than raw seat count.
56
-
57
- | Plan | Price | Includes |
58
- |------|-------|----------|
59
- | Solo | $19/mo | 15 standard tools, AES-256-GCM encrypted storage, 5K requests/mo |
60
- | Team | $49/mo | 15 standard + 3 AI compound tools, 3 workspaces, 25K requests/mo |
61
- | Turnkey Team Launch | $2.5k+ | Deployment review, rollout sequencing, client setup guidance, first-production-use path |
62
- | Managed Reliability | $800/mo+ | Ongoing operating review, token-health follow-up, workflow continuity support |
48
+ 12 read-only, 4 write-path. All carry [MCP safety annotations](https://modelcontextprotocol.io/specification/2025-03-26/server/tools#annotations).
63
49
 
64
- [Pricing](https://mcp.revasserlabs.com/pricing?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Workflows](https://mcp.revasserlabs.com/workflows?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Gemini CLI](https://mcp.revasserlabs.com/gemini-cli?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Readiness](https://mcp.revasserlabs.com/readiness?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Cloud Docs](https://mcp.revasserlabs.com/docs?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Security & Procurement](https://mcp.revasserlabs.com/security?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Procurement Brief](https://mcp.revasserlabs.com/procurement?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Account](https://mcp.revasserlabs.com/account?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Deployment Review](https://mcp.revasserlabs.com/deployment?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Cloud Support](https://mcp.revasserlabs.com/support?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) · [Privacy Policy](https://mcp.revasserlabs.com/privacy?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud)
50
+ \* `slack_refresh_tokens` modifies local token file only.
65
51
 
66
- For rollout help or managed deployment review, use [Cloud deployment review](https://mcp.revasserlabs.com/deployment?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud). For buyer-facing controls, storage, analytics, and procurement questions, use [Cloud security](https://mcp.revasserlabs.com/security?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud) and the [procurement brief](https://mcp.revasserlabs.com/procurement?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud). Reproducible self-host bugs stay in standard issues; hosted operational questions belong on [Cloud support](https://mcp.revasserlabs.com/support?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud).
52
+ ## Install
67
53
 
68
- Operated by Revasser. Self-host support is best-effort; managed rollout and Cloud support stay on [mcp.revasserlabs.com](https://mcp.revasserlabs.com/?utm_source=github&utm_medium=readme&utm_campaign=slack_mcp_cloud).
69
-
70
- ## Install & Verify (Self-Hosted)
71
-
72
- **Runtime:** Node.js 20+
54
+ **Node.js 20+**
73
55
 
74
56
  ```bash
75
57
  npx -y @jtalk22/slack-mcp --setup
76
- npx -y @jtalk22/slack-mcp@latest --version
77
- npx -y @jtalk22/slack-mcp@latest --doctor
78
- npx -y @jtalk22/slack-mcp@latest --status
79
58
  ```
80
59
 
81
- The setup wizard handles token extraction and validation automatically.
60
+ The setup wizard handles token extraction and validation.
82
61
 
83
62
  <details>
84
63
  <summary><strong>Claude Desktop (macOS)</strong></summary>
@@ -123,7 +102,7 @@ Edit `%APPDATA%\Claude\claude_desktop_config.json`:
123
102
  </details>
124
103
 
125
104
  <details>
126
- <summary><strong>Claude Code CLI</strong></summary>
105
+ <summary><strong>Claude Code</strong></summary>
127
106
 
128
107
  Add to `~/.claude.json`:
129
108
 
@@ -141,6 +120,41 @@ Add to `~/.claude.json`:
141
120
 
142
121
  </details>
143
122
 
123
+ <details>
124
+ <summary><strong>Cursor / Copilot / Other MCP clients</strong></summary>
125
+
126
+ Any client that supports stdio MCP servers works. Add to your client's MCP config:
127
+
128
+ ```json
129
+ {
130
+ "slack": {
131
+ "command": "npx",
132
+ "args": ["-y", "@jtalk22/slack-mcp"],
133
+ "env": {
134
+ "SLACK_TOKEN": "xoxc-your-token",
135
+ "SLACK_COOKIE": "xoxd-your-cookie"
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ On macOS, tokens are auto-extracted from Chrome — `env` block is optional.
142
+
143
+ </details>
144
+
145
+ <details>
146
+ <summary><strong>Claude Web / Remote MCP</strong></summary>
147
+
148
+ For browser-based clients that can't run local processes, use the hosted HTTP endpoint:
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.
155
+
156
+ </details>
157
+
144
158
  <details>
145
159
  <summary><strong>Docker</strong></summary>
146
160
 
@@ -163,7 +177,19 @@ docker pull ghcr.io/jtalk22/slack-mcp-server:latest
163
177
 
164
178
  </details>
165
179
 
166
- Restart Claude after configuration. Full setup guide: [docs/SETUP.md](docs/SETUP.md)
180
+ Restart your client after configuration. Full setup: [docs/SETUP.md](docs/SETUP.md)
181
+
182
+ ## How It Works
183
+
184
+ Session tokens (`xoxc-` + `xoxd-`) from your browser. If you can see it in Slack, this server can see it too.
185
+
186
+ **Token persistence** — four-layer fallback:
187
+ 1. Environment variables (`SLACK_TOKEN`, `SLACK_COOKIE`)
188
+ 2. Token file (`~/.slack-mcp-tokens.json`, chmod 600)
189
+ 3. macOS Keychain (encrypted)
190
+ 4. Chrome auto-extraction (macOS)
191
+
192
+ 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.
167
193
 
168
194
  ## Hosted HTTP Mode
169
195
 
@@ -181,32 +207,31 @@ Details: [docs/DEPLOYMENT-MODES.md](docs/DEPLOYMENT-MODES.md)
181
207
 
182
208
  ## Troubleshooting
183
209
 
184
- **Tokens expired:** Run `npx -y @jtalk22/slack-mcp --setup` or use `slack_refresh_tokens` in Claude (macOS).
210
+ **Tokens expired:** Run `npx -y @jtalk22/slack-mcp --setup` or use `slack_refresh_tokens` (macOS).
185
211
 
186
- **DMs not showing:** Use `slack_list_conversations` with `discover_dms=true` to force discovery.
212
+ **DMs not showing:** Use `slack_list_conversations` with `discover_dms=true`.
187
213
 
188
- **Claude not seeing tools:** Verify JSON syntax in config, check logs at `~/Library/Logs/Claude/mcp*.log`, fully restart Claude (Cmd+Q).
214
+ **Client not seeing tools:** Check JSON syntax in config, restart client fully.
189
215
 
190
216
  More: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)
191
217
 
192
218
  ## Docs
193
219
 
194
- - [Setup Guide](docs/SETUP.md) — Token extraction and configuration
195
- - [API Reference](docs/API.md) — All 16 tools with parameters and examples
196
- - [Deployment Modes](docs/DEPLOYMENT-MODES.md) — stdio, web, hosted HTTP, Cloudflare Worker
197
- - [Use Case Recipes](docs/USE_CASE_RECIPES.md) — 12 copy-paste prompts
198
- - [Troubleshooting](docs/TROUBLESHOOTING.md) — Common issues and fixes
199
- - [Compatibility](docs/COMPATIBILITY.md) — Client compatibility matrix
200
- - [Support Boundaries](docs/SUPPORT-BOUNDARIES.md) — Scope and response targets
201
- - [Docs Index](docs/INDEX.md) — Full documentation index
220
+ - [Setup Guide](docs/SETUP.md)
221
+ - [API Reference](docs/API.md)
222
+ - [Architecture](docs/ARCHITECTURE.md)
223
+ - [Deployment Modes](docs/DEPLOYMENT-MODES.md)
224
+ - [Use Case Recipes](docs/USE_CASE_RECIPES.md)
225
+ - [Troubleshooting](docs/TROUBLESHOOTING.md)
226
+ - [Compatibility](docs/COMPATIBILITY.md)
202
227
 
203
228
  ## Security
204
229
 
205
- - Token files stored with `chmod 600` (owner-only)
206
- - macOS Keychain provides encrypted backup
230
+ - Token files: `chmod 600` (owner-only)
231
+ - macOS Keychain encrypted backup
207
232
  - Web server binds to localhost only
208
- - API keys are cryptographically random (`crypto.randomBytes`)
209
- - See [SECURITY.md](SECURITY.md) for vulnerability reporting
233
+ - API keys: `crypto.randomBytes`
234
+ - See [SECURITY.md](SECURITY.md)
210
235
 
211
236
  ## Contributing
212
237
 
@@ -218,4 +243,8 @@ MIT — See [LICENSE](LICENSE)
218
243
 
219
244
  ## Disclaimer
220
245
 
221
- This project accesses Slack's Web API using browser session credentials. It is not affiliated with or endorsed by Slack Technologies, Inc. Slack workspace administrators should review their acceptable use policies.
246
+ Not affiliated with Slack Technologies, Inc. Uses browser session credentials check your workspace's acceptable use policy.
247
+
248
+ ---
249
+
250
+ Managed hosting available — [mcp.revasserlabs.com](https://mcp.revasserlabs.com)
@@ -6,14 +6,6 @@ const packageJson = JSON.parse(
6
6
 
7
7
  export const RELEASE_VERSION = packageJson.version;
8
8
 
9
- function withTrackedUrl(url, medium) {
10
- const tracked = new URL(url);
11
- tracked.searchParams.set("utm_source", "github");
12
- tracked.searchParams.set("utm_medium", medium);
13
- tracked.searchParams.set("utm_campaign", "slack_mcp_cloud");
14
- return tracked.toString();
15
- }
16
-
17
9
  export const PUBLIC_METADATA = Object.freeze({
18
10
  projectName: "slack-mcp-server",
19
11
  packageName: packageJson.name,
@@ -21,67 +13,10 @@ export const PUBLIC_METADATA = Object.freeze({
21
13
  canonicalRepoUrl: "https://github.com/jtalk22/slack-mcp-server",
22
14
  canonicalSiteUrl: "https://mcp.revasserlabs.com",
23
15
  cloudPricingUrl: "https://mcp.revasserlabs.com/pricing",
24
- cloudWorkflowsUrl: "https://mcp.revasserlabs.com/workflows",
25
- cloudGeminiCliUrl: "https://mcp.revasserlabs.com/gemini-cli",
26
- cloudReadinessUrl: "https://mcp.revasserlabs.com/readiness",
27
16
  cloudDocsUrl: "https://mcp.revasserlabs.com/docs",
28
17
  cloudSecurityUrl: "https://mcp.revasserlabs.com/security",
29
- cloudProcurementUrl: "https://mcp.revasserlabs.com/procurement",
30
18
  cloudSupportUrl: "https://mcp.revasserlabs.com/support",
31
- cloudDeploymentUrl: "https://mcp.revasserlabs.com/deployment",
32
- cloudSelfHostUrl: "https://mcp.revasserlabs.com/self-host",
33
- cloudAccountUrl: "https://mcp.revasserlabs.com/account",
34
- cloudUseCasesRootUrl: "https://mcp.revasserlabs.com/use-cases",
35
19
  cloudStatusUrl: "https://mcp.revasserlabs.com/status",
36
20
  supportEmail: "support@revasserlabs.com",
37
- privacyEmail: "privacy@revasserlabs.com",
38
- primaryClient: "Claude",
39
- secondaryClient: "Gemini CLI",
40
21
  selfHostedToolCount: 16,
41
- cloudManagedToolCount: 15,
42
- teamAiWorkflowCount: 3,
43
- cloudSoloPrice: "$19/mo",
44
- cloudTeamPrice: "$49/mo",
45
- cloudTurnkeyLaunchPrice: "$2.5k+",
46
- cloudManagedReliabilityPrice: "$800/mo+",
47
- tracked: Object.freeze({
48
- pages: Object.freeze({
49
- pricing: withTrackedUrl("https://mcp.revasserlabs.com/pricing", "pages"),
50
- workflows: withTrackedUrl("https://mcp.revasserlabs.com/workflows", "pages"),
51
- geminiCli: withTrackedUrl("https://mcp.revasserlabs.com/gemini-cli", "pages"),
52
- readiness: withTrackedUrl("https://mcp.revasserlabs.com/readiness", "pages"),
53
- docs: withTrackedUrl("https://mcp.revasserlabs.com/docs", "pages"),
54
- security: withTrackedUrl("https://mcp.revasserlabs.com/security", "pages"),
55
- procurement: withTrackedUrl("https://mcp.revasserlabs.com/procurement", "pages"),
56
- deployment: withTrackedUrl("https://mcp.revasserlabs.com/deployment", "pages"),
57
- support: withTrackedUrl("https://mcp.revasserlabs.com/support", "pages"),
58
- account: withTrackedUrl("https://mcp.revasserlabs.com/account", "pages"),
59
- privacy: withTrackedUrl("https://mcp.revasserlabs.com/privacy", "pages"),
60
- }),
61
- readme: Object.freeze({
62
- pricing: withTrackedUrl("https://mcp.revasserlabs.com/pricing", "readme"),
63
- workflows: withTrackedUrl("https://mcp.revasserlabs.com/workflows", "readme"),
64
- geminiCli: withTrackedUrl("https://mcp.revasserlabs.com/gemini-cli", "readme"),
65
- readiness: withTrackedUrl("https://mcp.revasserlabs.com/readiness", "readme"),
66
- docs: withTrackedUrl("https://mcp.revasserlabs.com/docs", "readme"),
67
- security: withTrackedUrl("https://mcp.revasserlabs.com/security", "readme"),
68
- procurement: withTrackedUrl("https://mcp.revasserlabs.com/procurement", "readme"),
69
- deployment: withTrackedUrl("https://mcp.revasserlabs.com/deployment", "readme"),
70
- support: withTrackedUrl("https://mcp.revasserlabs.com/support", "readme"),
71
- account: withTrackedUrl("https://mcp.revasserlabs.com/account", "readme"),
72
- privacy: withTrackedUrl("https://mcp.revasserlabs.com/privacy", "readme"),
73
- }),
74
- docs: Object.freeze({
75
- pricing: withTrackedUrl("https://mcp.revasserlabs.com/pricing", "docs"),
76
- workflows: withTrackedUrl("https://mcp.revasserlabs.com/workflows", "docs"),
77
- geminiCli: withTrackedUrl("https://mcp.revasserlabs.com/gemini-cli", "docs"),
78
- readiness: withTrackedUrl("https://mcp.revasserlabs.com/readiness", "docs"),
79
- security: withTrackedUrl("https://mcp.revasserlabs.com/security", "docs"),
80
- procurement: withTrackedUrl("https://mcp.revasserlabs.com/procurement", "docs"),
81
- deployment: withTrackedUrl("https://mcp.revasserlabs.com/deployment", "docs"),
82
- support: withTrackedUrl("https://mcp.revasserlabs.com/support", "docs"),
83
- account: withTrackedUrl("https://mcp.revasserlabs.com/account", "docs"),
84
- privacy: withTrackedUrl("https://mcp.revasserlabs.com/privacy", "docs"),
85
- }),
86
- }),
87
22
  });
@@ -15,9 +15,6 @@ 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 RELEASE_HEALTH_URL = `${GITHUB_DOCS_ROOT}/release-health/latest.md`;
19
- const VERSION_PARITY_URL = `${GITHUB_DOCS_ROOT}/release-health/version-parity.md`;
20
- const RUNBOOK_URL = `${GITHUB_DOCS_ROOT}/LAUNCH-OPS.md`;
21
18
  const DEMO_VIDEO_URL = `${GITHUB_PAGES_ROOT}/docs/videos/demo-claude-mobile-20s.mp4`;
22
19
 
23
20
  function template(name) {
@@ -36,39 +33,17 @@ function replaceTokens(source, replacements) {
36
33
  function rootDecisionPanel() {
37
34
  return `
38
35
  <section class="stage" style="padding-top:0">
39
- <div class="decision-grid" aria-label="Cloud versus self-host decision guide">
36
+ <div class="decision-grid" aria-label="Self-host info">
40
37
  <article class="decision-card">
41
38
  <span class="decision-label">Self-host</span>
42
- <h2>16 tools and full operator control.</h2>
43
- <p>Choose the open-source path if you want npm or Docker, local-first transport control, and direct ownership of token extraction, storage, and process management.</p>
39
+ <h2>${PUBLIC_METADATA.selfHostedToolCount} tools and full operator control.</h2>
40
+ <p>Session-based auth, stdio transport. Works with Claude, ChatGPT, Cursor, Copilot, Gemini, Windsurf, and any other MCP client.</p>
44
41
  <ul>
45
42
  <li>stdio, web, and Docker paths stay fully under your control</li>
46
- <li>Best fit for local development, custom transport, or internal operator ownership</li>
47
- <li>Proof surfaces: install guide, release health, and version parity remain public</li>
43
+ <li>No OAuth app registration or admin approval needed</li>
44
+ <li>Token persistence with automatic refresh on macOS</li>
48
45
  </ul>
49
- <p class="decision-links"><a href="${SETUP_URL}">Setup guide</a> · <a href="${VERSION_PARITY_URL}">Version parity</a> · <a href="${RELEASE_HEALTH_URL}">Release health</a></p>
50
- </article>
51
- <article class="decision-card accent">
52
- <span class="decision-label">Cloud</span>
53
- <h2>${PUBLIC_METADATA.cloudManagedToolCount} managed tools, ${PUBLIC_METADATA.teamAiWorkflowCount} Team AI workflows.</h2>
54
- <p>Choose Cloud if you want one remote endpoint, hosted credential handling, deployment review, and an operational support path instead of running the transport yourself. ${PUBLIC_METADATA.primaryClient} stays primary; ${PUBLIC_METADATA.secondaryClient} is supported as the second client path.</p>
55
- <ul>
56
- <li>Solo: ${PUBLIC_METADATA.cloudSoloPrice} for the managed endpoint and hosted credential handling</li>
57
- <li>Team: ${PUBLIC_METADATA.cloudTeamPrice} and adds ${PUBLIC_METADATA.teamAiWorkflowCount} AI workflows</li>
58
- <li>Turnkey Team Launch: from ${PUBLIC_METADATA.cloudTurnkeyLaunchPrice}; Managed Reliability: from ${PUBLIC_METADATA.cloudManagedReliabilityPrice}</li>
59
- </ul>
60
- <p class="decision-links"><a href="${PUBLIC_METADATA.tracked.pages.pricing}">Pricing</a> · <a href="${PUBLIC_METADATA.tracked.pages.workflows}">Workflows</a> · <a href="${PUBLIC_METADATA.tracked.pages.geminiCli}">Gemini CLI</a> · <a href="${PUBLIC_METADATA.tracked.pages.deployment}">Deployment review</a> · <a href="${PUBLIC_METADATA.tracked.pages.security}">Security</a></p>
61
- </article>
62
- <article class="decision-card">
63
- <span class="decision-label">Buyer proof</span>
64
- <h2>Technical trust surfaces stay public.</h2>
65
- <p>The static Pages root shows npm, GitHub release, and hosted status together. The hosted site publishes <code>/status</code>, <code>/pricing</code>, <code>/docs</code>, <code>/security</code>, <code>/deployment</code>, <code>/support</code>, and <code>/account</code> as the operator-facing Cloud surface.</p>
66
- <ul>
67
- <li>GitHub Pages reads the hosted <code>/status</code> contract live</li>
68
- <li>Registry, npm, runtime parity, and hosted funnel reporting are tracked in the public reports</li>
69
- <li>Rollout and security questions route to hosted review surfaces instead of ad hoc GitHub issues</li>
70
- </ul>
71
- <p class="decision-links"><a href="${RUNBOOK_URL}">Runbook</a> · <a href="${PUBLIC_METADATA.cloudStatusUrl}">Raw status JSON</a> · <a href="${PUBLIC_METADATA.tracked.pages.procurement}">Procurement</a> · <a href="${PUBLIC_METADATA.tracked.pages.readiness}">Readiness</a> · <a href="${PUBLIC_METADATA.tracked.pages.pricing}">Plans & offers</a></p>
46
+ <p class="decision-links"><a href="${SETUP_URL}">Setup guide</a> · <a href="${RELEASES_URL}">Latest release</a> · <a href="${NPM_URL}">npm</a></p>
72
47
  </article>
73
48
  </div>
74
49
  </section>
@@ -80,15 +55,6 @@ function shareLinks() {
80
55
  <a href="${SETUP_URL}" rel="noopener">Install (\`--setup\`)</a>
81
56
  <a href="${SETUP_URL}" rel="noopener">Verify (\`--version/--doctor/--status\`)</a>
82
57
  <a href="${RELEASES_URL}" rel="noopener">Latest Release</a>
83
- <a href="${PUBLIC_METADATA.tracked.pages.pricing}" rel="noopener">Pricing</a>
84
- <a href="${PUBLIC_METADATA.tracked.pages.workflows}" rel="noopener">Workflows</a>
85
- <a href="${PUBLIC_METADATA.tracked.pages.geminiCli}" rel="noopener">Gemini CLI</a>
86
- <a href="${PUBLIC_METADATA.tracked.pages.docs}" rel="noopener">Cloud Docs</a>
87
- <a href="${PUBLIC_METADATA.tracked.pages.security}" rel="noopener">Security</a>
88
- <a href="${PUBLIC_METADATA.tracked.pages.procurement}" rel="noopener">Procurement</a>
89
- <a href="${PUBLIC_METADATA.tracked.pages.deployment}" rel="noopener">Deployment Review</a>
90
- <a href="${PUBLIC_METADATA.tracked.pages.support}" rel="noopener">Cloud Support</a>
91
- <a href="${PUBLIC_METADATA.cloudUseCasesRootUrl}/support-triage?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Support Triage Use Case</a>
92
58
  <a href="${GITHUB_PAGES_ROOT}/" rel="noopener">Autoplay Demo Landing</a>
93
59
  <a href="${DEMO_VIDEO_URL}" rel="noopener">20s Mobile Clip</a>
94
60
  <a href="${NPM_URL}" rel="noopener">npm Package</a>
@@ -97,48 +63,42 @@ function shareLinks() {
97
63
  }
98
64
 
99
65
  function shareNote() {
100
- return `<strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives ${PUBLIC_METADATA.selfHostedToolCount} tools and full operator control. Cloud starts at ${PUBLIC_METADATA.cloudSoloPrice} for ${PUBLIC_METADATA.cloudManagedToolCount} managed tools, deployment review, procurement-ready security, readiness guidance, and support. Team at ${PUBLIC_METADATA.cloudTeamPrice} adds ${PUBLIC_METADATA.teamAiWorkflowCount} AI workflows. ${PUBLIC_METADATA.primaryClient} is the primary path; ${PUBLIC_METADATA.secondaryClient} is supported on the hosted endpoint.`;
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. Managed hosting available at <a href="${PUBLIC_METADATA.canonicalSiteUrl}">mcp.revasserlabs.com</a>.`;
101
67
  }
102
68
 
103
69
  function demoLinks() {
104
70
  return `
105
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">Cloud</a>
106
72
  <a href="${NPM_URL}" target="_blank" rel="noopener noreferrer">npm Install</a>
107
- <a href="${PUBLIC_METADATA.tracked.pages.pricing}" target="_blank" rel="noopener noreferrer">Pricing</a>
108
- <a href="${PUBLIC_METADATA.tracked.pages.workflows}" target="_blank" rel="noopener noreferrer">Workflows</a>
109
- <a href="${PUBLIC_METADATA.tracked.pages.geminiCli}" target="_blank" rel="noopener noreferrer">Gemini CLI</a>
110
73
  <a href="${SETUP_URL}" target="_blank" rel="noopener noreferrer">Setup Guide</a>
111
- <a href="${PUBLIC_METADATA.tracked.pages.docs}" target="_blank" rel="noopener noreferrer">Cloud Docs</a>
112
- <a href="${PUBLIC_METADATA.tracked.pages.security}" target="_blank" rel="noopener noreferrer">Security</a>
113
- <a href="${PUBLIC_METADATA.tracked.pages.procurement}" target="_blank" rel="noopener noreferrer">Procurement</a>
114
- <a href="${PUBLIC_METADATA.tracked.pages.deployment}" target="_blank" rel="noopener noreferrer">Deployment Review</a>
115
- <a href="${PUBLIC_METADATA.tracked.pages.support}" target="_blank" rel="noopener noreferrer">Cloud Support</a>
116
74
  `.trim();
117
75
  }
118
76
 
119
77
  function demoNote() {
120
- return `Self-host free for ${PUBLIC_METADATA.selfHostedToolCount} tools and full transport control, or use <a href="${PUBLIC_METADATA.tracked.pages.pricing}" target="_blank" rel="noopener noreferrer">Cloud</a> for ${PUBLIC_METADATA.cloudManagedToolCount} managed tools, deployment review, procurement-ready security, and support. Solo starts at ${PUBLIC_METADATA.cloudSoloPrice}; Team at ${PUBLIC_METADATA.cloudTeamPrice} adds ${PUBLIC_METADATA.teamAiWorkflowCount} AI workflows. Turnkey Team Launch starts at ${PUBLIC_METADATA.cloudTurnkeyLaunchPrice}; Managed Reliability starts at ${PUBLIC_METADATA.cloudManagedReliabilityPrice}.`;
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. Managed hosting available at <a href="${PUBLIC_METADATA.canonicalSiteUrl}" target="_blank" rel="noopener noreferrer">mcp.revasserlabs.com</a>.`;
121
79
  }
122
80
 
123
81
  function demoFooterLinks() {
124
- return `<a href="${PUBLIC_METADATA.canonicalRepoUrl}">GitHub</a> · <a href="${PUBLIC_METADATA.tracked.pages.pricing}" style="color:#f0c246;text-decoration:none;font-size:0.875rem">Cloud Plans</a> · <a href="${PUBLIC_METADATA.tracked.pages.workflows}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">Workflows</a> · <a href="${PUBLIC_METADATA.tracked.pages.geminiCli}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">Gemini CLI</a> · <a href="${PUBLIC_METADATA.tracked.pages.security}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">Security</a> · <a href="${PUBLIC_METADATA.tracked.pages.deployment}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">Deployment Review</a> · <a href="${PUBLIC_METADATA.tracked.pages.support}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">Cloud Support</a> · <a href="${NPM_URL}" style="color:#94a3b8;text-decoration:none;font-size:0.875rem">npm</a>`;
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">Cloud</a>`;
125
83
  }
126
84
 
127
85
  function commonTokens() {
128
86
  return {
129
87
  CANONICAL_SITE_URL: PUBLIC_METADATA.canonicalSiteUrl,
130
- CLOUD_PRICING_URL: PUBLIC_METADATA.tracked.pages.pricing,
131
- CLOUD_WORKFLOWS_URL: PUBLIC_METADATA.tracked.pages.workflows,
132
- CLOUD_GEMINI_CLI_URL: PUBLIC_METADATA.tracked.pages.geminiCli,
133
- CLOUD_READINESS_URL: PUBLIC_METADATA.tracked.pages.readiness,
134
- CLOUD_DOCS_URL: PUBLIC_METADATA.tracked.pages.docs,
135
- CLOUD_SECURITY_URL: PUBLIC_METADATA.tracked.pages.security,
136
- CLOUD_PROCUREMENT_URL: PUBLIC_METADATA.tracked.pages.procurement,
137
- CLOUD_SUPPORT_URL: PUBLIC_METADATA.tracked.pages.support,
138
- CLOUD_DEPLOYMENT_URL: PUBLIC_METADATA.tracked.pages.deployment,
88
+ CLOUD_PRICING_URL: PUBLIC_METADATA.cloudPricingUrl,
89
+ CLOUD_WORKFLOWS_URL: PUBLIC_METADATA.canonicalSiteUrl + "/workflows",
90
+ CLOUD_OFFICIAL_COMPARISON_URL: PUBLIC_METADATA.canonicalSiteUrl + "/official-slack-mcp-vs-managed",
91
+ CLOUD_GEMINI_CLI_URL: PUBLIC_METADATA.canonicalSiteUrl + "/gemini-cli",
92
+ CLOUD_READINESS_URL: PUBLIC_METADATA.canonicalSiteUrl + "/readiness",
93
+ CLOUD_DOCS_URL: PUBLIC_METADATA.cloudDocsUrl,
94
+ CLOUD_SECURITY_URL: PUBLIC_METADATA.cloudSecurityUrl,
95
+ CLOUD_PROCUREMENT_URL: PUBLIC_METADATA.canonicalSiteUrl + "/procurement",
96
+ CLOUD_MARKETPLACE_READINESS_URL: PUBLIC_METADATA.canonicalSiteUrl + "/marketplace-readiness",
97
+ CLOUD_SUPPORT_URL: PUBLIC_METADATA.cloudSupportUrl,
98
+ CLOUD_DEPLOYMENT_URL: PUBLIC_METADATA.canonicalSiteUrl + "/deployment",
139
99
  CLOUD_STATUS_URL: PUBLIC_METADATA.cloudStatusUrl,
140
- CLOUD_SELF_HOST_URL: PUBLIC_METADATA.cloudSelfHostUrl,
141
- CLOUD_ACCOUNT_URL: PUBLIC_METADATA.cloudAccountUrl,
100
+ CLOUD_SELF_HOST_URL: PUBLIC_METADATA.canonicalSiteUrl + "/self-host",
101
+ CLOUD_ACCOUNT_URL: PUBLIC_METADATA.canonicalSiteUrl + "/account",
142
102
  GITHUB_REPO_URL: PUBLIC_METADATA.canonicalRepoUrl,
143
103
  GITHUB_PAGES_ROOT,
144
104
  GITHUB_DOCS_ROOT,
@@ -147,16 +107,16 @@ function commonTokens() {
147
107
  NPM_URL,
148
108
  RELEASES_URL,
149
109
  SETUP_URL,
150
- RELEASE_HEALTH_URL,
151
- VERSION_PARITY_URL,
152
- RUNBOOK_URL,
110
+ RELEASE_HEALTH_URL: RELEASES_URL,
111
+ VERSION_PARITY_URL: RELEASES_URL,
112
+ RUNBOOK_URL: SETUP_URL,
153
113
  SELF_HOSTED_TOOL_COUNT: String(PUBLIC_METADATA.selfHostedToolCount),
154
- CLOUD_MANAGED_TOOL_COUNT: String(PUBLIC_METADATA.cloudManagedToolCount),
155
- TEAM_AI_WORKFLOW_COUNT: String(PUBLIC_METADATA.teamAiWorkflowCount),
156
- CLOUD_SOLO_PRICE: PUBLIC_METADATA.cloudSoloPrice,
157
- CLOUD_TEAM_PRICE: PUBLIC_METADATA.cloudTeamPrice,
158
- CLOUD_TURNKEY_LAUNCH_PRICE: PUBLIC_METADATA.cloudTurnkeyLaunchPrice,
159
- CLOUD_MANAGED_RELIABILITY_PRICE: PUBLIC_METADATA.cloudManagedReliabilityPrice,
114
+ CLOUD_MANAGED_TOOL_COUNT: "15",
115
+ TEAM_AI_WORKFLOW_COUNT: "3",
116
+ CLOUD_SOLO_PRICE: "$19/mo",
117
+ CLOUD_TEAM_PRICE: "$49/mo",
118
+ CLOUD_TURNKEY_LAUNCH_PRICE: "$2.5k+",
119
+ CLOUD_MANAGED_RELIABILITY_PRICE: "$800/mo+",
160
120
  SUPPORT_EMAIL: PUBLIC_METADATA.supportEmail,
161
121
  ROOT_DECISION_PANEL: rootDecisionPanel(),
162
122
  SHARE_LINKS: shareLinks(),
@@ -8,7 +8,7 @@
8
8
  * 4. Chrome auto-extraction (fallback)
9
9
  */
10
10
 
11
- import { readFileSync, writeFileSync, existsSync, renameSync, unlinkSync } from "fs";
11
+ import { readFileSync, writeFileSync, existsSync, renameSync, unlinkSync, chmodSync } from "fs";
12
12
  import { homedir, platform } from "os";
13
13
  import { join } from "path";
14
14
  import { execSync, execFileSync } from "child_process";
@@ -79,7 +79,7 @@ function atomicWriteSync(filePath, content) {
79
79
  try {
80
80
  writeFileSync(tempPath, content);
81
81
  if (IS_MACOS || platform() === 'linux') {
82
- try { execSync(`chmod 600 "${tempPath}"`); } catch {}
82
+ try { chmodSync(tempPath, 0o600); } catch {}
83
83
  }
84
84
  renameSync(tempPath, filePath); // Atomic on POSIX systems
85
85
  } catch (e) {
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.2.5",
5
- "description": "Claude-first Slack MCP for self-host or managed Cloud, with Gemini CLI, deployment review, and secure-default HTTP.",
4
+ "version": "4.0.0",
5
+ "description": "Slack MCP server. Session-based auth, 16 tools, stdio transport. Works with any MCP client.",
6
6
  "type": "module",
7
7
  "main": "src/server.js",
8
8
  "bin": {
@@ -31,10 +31,6 @@
31
31
  "record-demo": "node scripts/record-demo.js",
32
32
  "social-preview:update": "node scripts/update-github-social-preview.js --headed",
33
33
  "cf:browser": "node scripts/cloudflare-browser-tool.js",
34
- "metrics:release-health": "node scripts/collect-release-health.js",
35
- "metrics:release-health:delta": "node scripts/build-release-health-delta.js",
36
- "impact:push:v3": "node scripts/impact-push-v3.js --dry-run",
37
- "impact:push:v3:apply": "node scripts/impact-push-v3.js --apply",
38
34
  "verify:attribution-guardrail": "node scripts/verify-attribution-guardrail.js",
39
35
  "verify:public-pages": "node scripts/verify-generated-public-pages.js",
40
36
  "verify:version-parity": "node scripts/check-version-parity.js",
package/public/share.html CHANGED
@@ -117,22 +117,13 @@
117
117
  <a href="https://github.com/jtalk22/slack-mcp-server/blob/main/docs/SETUP.md" rel="noopener">Install (`--setup`)</a>
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
- <a href="https://mcp.revasserlabs.com/pricing?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Pricing</a>
121
- <a href="https://mcp.revasserlabs.com/workflows?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Workflows</a>
122
- <a href="https://mcp.revasserlabs.com/gemini-cli?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Gemini CLI</a>
123
- <a href="https://mcp.revasserlabs.com/docs?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Cloud Docs</a>
124
- <a href="https://mcp.revasserlabs.com/security?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Security</a>
125
- <a href="https://mcp.revasserlabs.com/procurement?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Procurement</a>
126
- <a href="https://mcp.revasserlabs.com/deployment?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Deployment Review</a>
127
- <a href="https://mcp.revasserlabs.com/support?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Cloud Support</a>
128
- <a href="https://mcp.revasserlabs.com/use-cases/support-triage?utm_source=github&utm_medium=pages&utm_campaign=slack_mcp_cloud" rel="noopener">Support Triage Use Case</a>
129
120
  <a href="https://jtalk22.github.io/slack-mcp-server/" rel="noopener">Autoplay Demo Landing</a>
130
121
  <a href="https://jtalk22.github.io/slack-mcp-server/docs/videos/demo-claude-mobile-20s.mp4" rel="noopener">20s Mobile Clip</a>
131
122
  <a href="https://www.npmjs.com/package/@jtalk22/slack-mcp" rel="noopener">npm Package</a>
132
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">Cloud</a>
133
124
  </div>
134
125
 
135
- <p class="note"><strong>Verify in 30 seconds:</strong> <code>--version</code>, <code>--doctor</code>, <code>--status</code>. Self-host gives 16 tools and full operator control. Cloud starts at $19/mo for 15 managed tools, deployment review, procurement-ready security, readiness guidance, and support. Team at $49/mo adds 3 AI workflows. Claude is the primary path; Gemini CLI is supported on the hosted endpoint.</p>
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. Managed hosting available at <a href="https://mcp.revasserlabs.com">mcp.revasserlabs.com</a>.</p>
136
127
  </main>
137
128
  </body>
138
129
  </html>
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": "Claude-first Slack MCP for self-host or managed Cloud, with Gemini CLI, deployment review, and secure-default HTTP.",
5
+ "description": "Slack MCP server. Session-based auth, 16 tools, stdio transport. Works with any MCP client.",
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": "3.2.5",
20
+ "version": "4.0.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": "3.2.5",
31
+ "version": "4.0.0",
32
32
  "transport": {
33
33
  "type": "stdio"
34
34
  },
package/src/server.js CHANGED
@@ -150,7 +150,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
150
150
  }
151
151
  case "summarize-channel": {
152
152
  const channelId = args?.channel_id || "";
153
- const days = parseInt(args?.days) || 7;
153
+ const days = parseInt(args?.days, 10) || 7;
154
154
  const since = Math.floor(Date.now() / 1000) - (days * 24 * 60 * 60);
155
155
  return {
156
156
  messages: [
package/src/web-server.js CHANGED
@@ -11,8 +11,7 @@ import express from "express";
11
11
  import { randomBytes } from "crypto";
12
12
  import { fileURLToPath } from "url";
13
13
  import { dirname, join } from "path";
14
- import { existsSync, readFileSync, writeFileSync } from "fs";
15
- import { execSync } from "child_process";
14
+ import { existsSync, readFileSync, writeFileSync, chmodSync } from "fs";
16
15
  import { homedir } from "os";
17
16
  import { loadTokensReadOnly } from "../lib/token-store.js";
18
17
  import { PUBLIC_METADATA, RELEASE_VERSION } from "../lib/public-metadata.js";
@@ -60,7 +59,7 @@ function getOrCreateAPIKey() {
60
59
  const newKey = `smcp_${randomBytes(24).toString('base64url')}`;
61
60
  try {
62
61
  writeFileSync(API_KEY_FILE, newKey);
63
- execSync(`chmod 600 "${API_KEY_FILE}"`);
62
+ chmodSync(API_KEY_FILE, 0o600);
64
63
  } catch {}
65
64
 
66
65
  return newKey;
@@ -98,6 +97,12 @@ app.use((req, res, next) => {
98
97
  next();
99
98
  });
100
99
 
100
+ function safeParseInt(value, fallback, max = 10000) {
101
+ const n = parseInt(value, 10);
102
+ if (isNaN(n) || n < 1) return fallback;
103
+ return Math.min(n, max);
104
+ }
105
+
101
106
  // API Key authentication
102
107
  function authenticate(req, res, next) {
103
108
  const authHeader = req.headers.authorization;
@@ -209,7 +214,7 @@ app.get("/conversations", authenticate, async (req, res) => {
209
214
  try {
210
215
  const result = await handleListConversations({
211
216
  types: req.query.types || "im,mpim",
212
- limit: parseInt(req.query.limit) || 100
217
+ limit: safeParseInt(req.query.limit, 100)
213
218
  });
214
219
  res.json(extractContent(result));
215
220
  } catch (e) {
@@ -222,7 +227,7 @@ app.get("/conversations/unreads", authenticate, async (req, res) => {
222
227
  try {
223
228
  const result = await handleConversationsUnreads({
224
229
  types: req.query.types || "im,mpim,public_channel,private_channel",
225
- limit: parseInt(req.query.limit) || 50
230
+ limit: safeParseInt(req.query.limit, 50)
226
231
  });
227
232
  res.json(extractContent(result));
228
233
  } catch (e) {
@@ -235,7 +240,7 @@ app.get("/conversations/:id/history", authenticate, async (req, res) => {
235
240
  try {
236
241
  const result = await handleConversationsHistory({
237
242
  channel_id: req.params.id,
238
- limit: parseInt(req.query.limit) || 50,
243
+ limit: safeParseInt(req.query.limit, 50),
239
244
  oldest: req.query.oldest,
240
245
  latest: req.query.latest,
241
246
  resolve_users: req.query.resolve_users !== "false"
@@ -253,7 +258,7 @@ app.get("/conversations/:id/full", authenticate, async (req, res) => {
253
258
  channel_id: req.params.id,
254
259
  oldest: req.query.oldest,
255
260
  latest: req.query.latest,
256
- max_messages: parseInt(req.query.max_messages) || 2000,
261
+ max_messages: safeParseInt(req.query.max_messages, 2000, 50000),
257
262
  include_threads: req.query.include_threads !== "false",
258
263
  output_file: req.query.output_file
259
264
  });
@@ -312,7 +317,7 @@ app.get("/search", authenticate, async (req, res) => {
312
317
  }
313
318
  const result = await handleSearchMessages({
314
319
  query: req.query.q,
315
- count: parseInt(req.query.count) || 20
320
+ count: safeParseInt(req.query.count, 20)
316
321
  });
317
322
  res.json(extractContent(result));
318
323
  } catch (e) {
@@ -347,7 +352,7 @@ app.post("/messages", authenticate, async (req, res) => {
347
352
  app.get("/users", authenticate, async (req, res) => {
348
353
  try {
349
354
  const result = await handleListUsers({
350
- limit: parseInt(req.query.limit) || 100
355
+ limit: safeParseInt(req.query.limit, 100)
351
356
  });
352
357
  res.json(extractContent(result));
353
358
  } catch (e) {
@@ -369,7 +374,7 @@ app.get("/users/search", authenticate, async (req, res) => {
369
374
  }
370
375
  const result = await handleUsersSearch({
371
376
  query: req.query.q,
372
- limit: parseInt(req.query.limit) || 20
377
+ limit: safeParseInt(req.query.limit, 20)
373
378
  });
374
379
  res.json(extractContent(result));
375
380
  } catch (e) {
@@ -452,9 +457,9 @@ async function main() {
452
457
  console.error(`\n${"═".repeat(60)}`);
453
458
  console.error(` Slack Web API Server v${RELEASE_VERSION}`);
454
459
  console.error(`${"═".repeat(60)}`);
455
- console.error(`\n Dashboard: http://localhost:${PORT}/?key=${API_KEY}`);
456
- console.error(`\n API Key: ${API_KEY}`);
457
- console.error(`\n curl -H "Authorization: Bearer ${API_KEY}" http://localhost:${PORT}/health`);
460
+ console.error(`\n Dashboard: http://localhost:${PORT}/?key=${API_KEY.slice(0, 8)}...`);
461
+ console.error(`\n API Key: ${API_KEY.slice(0, 8)}${"*".repeat(12)}`);
462
+ console.error(`\n curl -H "Authorization: Bearer <key>" http://localhost:${PORT}/health`);
458
463
  console.error(`\n Security: Bound to localhost only (127.0.0.1)`);
459
464
  console.error(`\n${"═".repeat(60)}\n`);
460
465
  });