slack-max-api-mcp 1.0.7 → 1.0.8

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/.env.example CHANGED
@@ -38,6 +38,10 @@ SLACK_CLIENT_SECRET=
38
38
 
39
39
  # Optional auto-onboarding trigger for interactive `slack-max-api-mcp` runs
40
40
  # SLACK_AUTO_ONBOARD=true
41
+ # Built-in default team gateway used when no auto-onboard gateway is set:
42
+ # SLACK_DEFAULT_TEAM_GATEWAY_URL=https://43.202.54.65.sslip.io
43
+ # SLACK_DEFAULT_TEAM_GATEWAY_INSECURE_TLS=true
44
+ # SLACK_GATEWAY_INSECURE_TLS=true
41
45
  # SLACK_AUTO_ONBOARD_URL=https://mcp-gateway.example.com/onboard.ps1?token=...
42
46
  # or
43
47
  # SLACK_AUTO_ONBOARD_GATEWAY=https://mcp-gateway.example.com
package/README.md CHANGED
@@ -62,17 +62,26 @@ Slack Web API를 Codex/Claude Code에서 바로 사용할 수 있게 만든 `std
62
62
  2. USER 토큰 사용 시 메시지/파일 검색, 채널 읽기, 메시지 전송 가능
63
63
  3. BOT으로 검색은 토큰 타입 제한(`not_allowed_token_type`)이 있어 USER 토큰 사용 권장
64
64
 
65
- ## 설치 및 실행
66
-
67
- ```powershell
68
- npm install -g slack-max-api-mcp@latest
69
- slack-max-api-mcp
70
- ```
71
-
72
- 또는:
73
-
74
- ```powershell
75
- npx -y slack-max-api-mcp
65
+ ## 설치 및 실행
66
+
67
+ ```powershell
68
+ npm install -g slack-max-api-mcp@latest
69
+ slack-max-api-mcp
70
+ ```
71
+
72
+ 팀원 기본 온보딩(현재 패키지 기본값):
73
+ 1. 추가 환경변수 없이 `slack-max-api-mcp` 실행 시 자동 온보딩 시도
74
+ 2. 기본 게이트웨이: `https://43.202.54.65.sslip.io`
75
+ 3. 승인 후 Codex 등록 1회:
76
+
77
+ ```powershell
78
+ codex mcp add slack-max -- npx -y slack-max-api-mcp
79
+ ```
80
+
81
+ 또는:
82
+
83
+ ```powershell
84
+ npx -y slack-max-api-mcp
76
85
  ```
77
86
 
78
87
  ## Codex / Claude Code 연결
@@ -122,9 +131,7 @@ npx -y slack-max-api-mcp gateway start
122
131
  ### 팀원 경험 (토큰 전달 없이 권장)
123
132
 
124
133
  ```powershell
125
- $env:NODE_TLS_REJECT_UNAUTHORIZED='0'
126
- npx -y slack-max-api-mcp onboard run --gateway "https://your-gateway.example.com"
127
- Remove-Item Env:NODE_TLS_REJECT_UNAUTHORIZED
134
+ npx -y slack-max-api-mcp onboard run
128
135
  ```
129
136
 
130
137
  자동 동작:
@@ -155,7 +162,7 @@ powershell -ExecutionPolicy Bypass -Command "irm 'https://your-gateway.example.c
155
162
 
156
163
  ### 팀원 경험 (설치 후 `slack-max-api-mcp`만 실행)
157
164
 
158
- 운영자가 아래 값을 사전에 배포(이미지/스크립트/MDM)하면 팀원은 다음만 수행하면 됩니다.
165
+ 현재 패키지 기본 게이트웨이(`https://43.202.54.65.sslip.io`) 계속 사용할 경우 팀원은 다음만 수행하면 됩니다.
159
166
 
160
167
  ```powershell
161
168
  npm install -g slack-max-api-mcp@latest
@@ -168,10 +175,10 @@ slack-max-api-mcp
168
175
  3. Slack Allow 승인
169
176
  4. 완료 후 Codex에서 바로 사용
170
177
 
171
- 필요한 사전 배포값(팀원이 직접 입력하지 않아도 됨):
172
- 1. `SLACK_AUTO_ONBOARD_URL` 또는
173
- 2. `SLACK_AUTO_ONBOARD_GATEWAY` + `SLACK_AUTO_ONBOARD_TOKEN`
174
- 3. 토큰 없는 자동 온보딩은 `SLACK_AUTO_ONBOARD_GATEWAY` 단독도 가능 (게이트웨이 `SLACK_GATEWAY_PUBLIC_ONBOARD=true` 필요)
178
+ 게이트웨이 주소를 바꿔야 때만(운영자):
179
+ 1. `SLACK_DEFAULT_TEAM_GATEWAY_URL`
180
+ 2. `SLACK_DEFAULT_TEAM_GATEWAY_INSECURE_TLS` (`true/false`)
181
+ 3. 또는 기존 방식대로 `SLACK_AUTO_ONBOARD_URL`, `SLACK_AUTO_ONBOARD_GATEWAY` 사용 가능
175
182
 
176
183
  ## 2) 단독/개인 운영: 로컬 OAuth 모드
177
184
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-max-api-mcp",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Slack MCP server (stdio) for Codex and Claude Code",
5
5
  "main": "src/slack-mcp-server.js",
6
6
  "bin": {
@@ -27,6 +27,7 @@
27
27
  "type": "commonjs",
28
28
  "dependencies": {
29
29
  "@modelcontextprotocol/sdk": "^1.27.1",
30
+ "undici": "^7.16.0",
30
31
  "zod": "^4.3.6"
31
32
  }
32
33
  }
@@ -6,6 +6,7 @@ const http = require("node:http");
6
6
  const path = require("node:path");
7
7
  const crypto = require("node:crypto");
8
8
  const { spawn } = require("node:child_process");
9
+ const { Agent, fetch: undiciFetch } = require("undici");
9
10
  const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
10
11
  const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
11
12
  const { z } = require("zod");
@@ -57,8 +58,20 @@ const GATEWAY_PUBLIC_ONBOARD_PROFILE_PREFIX =
57
58
  const GATEWAY_STATE_TTL_MS = Number(process.env.SLACK_GATEWAY_STATE_TTL_MS || 15 * 60 * 1000);
58
59
  const INVITE_TOKEN_DEFAULT_DAYS = Number(process.env.SLACK_INVITE_TOKEN_DEFAULT_DAYS || 7);
59
60
  const AUTO_ONBOARD_ENABLED = process.env.SLACK_AUTO_ONBOARD !== "false";
61
+ const DEFAULT_TEAM_GATEWAY_URL =
62
+ process.env.SLACK_DEFAULT_TEAM_GATEWAY_URL || "https://43.202.54.65.sslip.io";
63
+ const DEFAULT_TEAM_GATEWAY_INSECURE_TLS =
64
+ process.env.SLACK_DEFAULT_TEAM_GATEWAY_INSECURE_TLS !== "false";
65
+ const GATEWAY_INSECURE_TLS =
66
+ process.env.SLACK_GATEWAY_INSECURE_TLS === "true"
67
+ ? true
68
+ : process.env.SLACK_GATEWAY_INSECURE_TLS === "false"
69
+ ? false
70
+ : null;
60
71
  const AUTO_ONBOARD_GATEWAY =
61
- process.env.SLACK_AUTO_ONBOARD_GATEWAY || process.env.SLACK_ONBOARD_GATEWAY_URL || "";
72
+ process.env.SLACK_AUTO_ONBOARD_GATEWAY ||
73
+ process.env.SLACK_ONBOARD_GATEWAY_URL ||
74
+ DEFAULT_TEAM_GATEWAY_URL;
62
75
  const AUTO_ONBOARD_PROFILE = process.env.SLACK_AUTO_ONBOARD_PROFILE || "";
63
76
  const AUTO_ONBOARD_TOKEN = process.env.SLACK_AUTO_ONBOARD_TOKEN || process.env.SLACK_ONBOARD_TOKEN || "";
64
77
  const AUTO_ONBOARD_URL = process.env.SLACK_AUTO_ONBOARD_URL || process.env.SLACK_ONBOARD_URL || "";
@@ -68,6 +81,11 @@ const ONBOARD_PACKAGE_SPEC =
68
81
  process.env.SLACK_ONBOARD_INSTALL_SPEC ||
69
82
  "slack-max-api-mcp@latest";
70
83
  const ONBOARD_SKIP_TLS_VERIFY = process.env.SLACK_ONBOARD_SKIP_TLS_VERIFY === "true";
84
+ const INSECURE_TLS_DISPATCHER = new Agent({
85
+ connect: {
86
+ rejectUnauthorized: false,
87
+ },
88
+ });
71
89
 
72
90
  function parseSimpleEnvFile(filePath) {
73
91
  if (!fs.existsSync(filePath)) return {};
@@ -127,6 +145,33 @@ function ensureParentDirectory(filePath) {
127
145
  fs.mkdirSync(dirPath, { recursive: true });
128
146
  }
129
147
 
148
+ function normalizeBaseUrl(url) {
149
+ return String(url || "").trim().replace(/\/+$/, "");
150
+ }
151
+
152
+ function normalizeUrlOrigin(url) {
153
+ try {
154
+ const parsed = new URL(String(url || "").trim());
155
+ return `${parsed.protocol}//${parsed.host}`.replace(/\/+$/, "");
156
+ } catch {
157
+ return normalizeBaseUrl(url);
158
+ }
159
+ }
160
+
161
+ function shouldUseInsecureGatewayTls(url) {
162
+ if (!url) return false;
163
+ if (GATEWAY_INSECURE_TLS !== null) return GATEWAY_INSECURE_TLS;
164
+ if (!DEFAULT_TEAM_GATEWAY_INSECURE_TLS) return false;
165
+ return normalizeUrlOrigin(url) === normalizeUrlOrigin(DEFAULT_TEAM_GATEWAY_URL);
166
+ }
167
+
168
+ async function fetchWithOptionalInsecureGatewayTls(url, options) {
169
+ if (!shouldUseInsecureGatewayTls(url)) {
170
+ return undiciFetch(url, options);
171
+ }
172
+ return undiciFetch(url, { ...(options || {}), dispatcher: INSECURE_TLS_DISPATCHER });
173
+ }
174
+
130
175
  function emptyTokenStore() {
131
176
  return { version: 1, default_profile: null, profiles: {} };
132
177
  }
@@ -354,7 +399,8 @@ async function callSlackApiViaGateway(method, params = {}, tokenOverride, option
354
399
  throw new Error("Gateway URL is missing. Set SLACK_GATEWAY_URL to use gateway mode.");
355
400
  }
356
401
 
357
- const response = await fetch(`${runtimeGateway.url}/api/slack/call`, {
402
+ const gatewayCallUrl = `${runtimeGateway.url}/api/slack/call`;
403
+ const response = await fetchWithOptionalInsecureGatewayTls(gatewayCallUrl, {
358
404
  method: "POST",
359
405
  headers: buildGatewayAuthHeaders(runtimeGateway.apiKey),
360
406
  body: JSON.stringify({
@@ -404,7 +450,8 @@ async function slackHttpViaGateway(input) {
404
450
  throw new Error("Gateway URL is missing. Set SLACK_GATEWAY_URL to use gateway mode.");
405
451
  }
406
452
 
407
- const response = await fetch(`${runtimeGateway.url}/api/slack/http`, {
453
+ const gatewayHttpUrl = `${runtimeGateway.url}/api/slack/http`;
454
+ const response = await fetchWithOptionalInsecureGatewayTls(gatewayHttpUrl, {
408
455
  method: "POST",
409
456
  headers: buildGatewayAuthHeaders(runtimeGateway.apiKey),
410
457
  body: JSON.stringify({
@@ -1018,11 +1065,12 @@ function printOnboardHelp() {
1018
1065
  "Slack Max onboarding helper",
1019
1066
  "",
1020
1067
  "Usage:",
1021
- " slack-max-api-mcp onboard run --gateway https://gateway.example.com [--token <invite_token>]",
1068
+ " slack-max-api-mcp onboard run [--gateway https://gateway.example.com] [--token <invite_token>]",
1022
1069
  " [--profile NAME] [--team T123] [--scope a,b] [--user-scope c,d]",
1023
- " slack-max-api-mcp onboard quick --gateway https://gateway.example.com",
1070
+ " slack-max-api-mcp onboard quick [--gateway https://gateway.example.com]",
1024
1071
  " slack-max-api-mcp onboard help",
1025
1072
  "",
1073
+ `Default gateway (if omitted): ${DEFAULT_TEAM_GATEWAY_URL}`,
1026
1074
  "If --token is omitted, it uses gateway public onboarding endpoint (/onboard/bootstrap).",
1027
1075
  "This command writes local client config and opens the Slack OAuth approval page automatically.",
1028
1076
  ];
@@ -1031,11 +1079,11 @@ function printOnboardHelp() {
1031
1079
 
1032
1080
  async function runOnboardStart(args) {
1033
1081
  const { options } = parseCliArgs(args);
1034
- const gateway = String(options.gateway || options.url || "").replace(/\/+$/, "");
1082
+ const gateway = normalizeBaseUrl(options.gateway || options.url || DEFAULT_TEAM_GATEWAY_URL);
1035
1083
  const token = String(options.token || "");
1036
1084
  if (!gateway) {
1037
1085
  throw new Error(
1038
- "Usage: slack-max-api-mcp onboard run --gateway <url> [--token <invite_token>] [--profile <name>]"
1086
+ "Usage: slack-max-api-mcp onboard run [--gateway <url>] [--token <invite_token>] [--profile <name>]"
1039
1087
  );
1040
1088
  }
1041
1089
 
@@ -1057,7 +1105,7 @@ async function runOnboardStart(args) {
1057
1105
  return `${gateway}/onboard/bootstrap${query ? `?${query}` : ""}`;
1058
1106
  })();
1059
1107
 
1060
- const response = await fetch(onboardingUrl, {
1108
+ const response = await fetchWithOptionalInsecureGatewayTls(onboardingUrl, {
1061
1109
  method: "GET",
1062
1110
  headers: { Accept: "application/json" },
1063
1111
  });