bn-slack-mcp-server 0.0.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.
Files changed (71) hide show
  1. package/README.md +243 -0
  2. package/dist/debug-middleware.d.ts +12 -0
  3. package/dist/debug-middleware.d.ts.map +1 -0
  4. package/dist/debug-middleware.js +36 -0
  5. package/dist/debug-middleware.js.map +1 -0
  6. package/dist/helpers.d.ts +86 -0
  7. package/dist/helpers.d.ts.map +1 -0
  8. package/dist/helpers.js +235 -0
  9. package/dist/helpers.js.map +1 -0
  10. package/dist/index.d.ts +9 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +162 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/schemas.d.ts +286 -0
  15. package/dist/schemas.d.ts.map +1 -0
  16. package/dist/schemas.js +840 -0
  17. package/dist/schemas.js.map +1 -0
  18. package/dist/slack-api-client.d.ts +51 -0
  19. package/dist/slack-api-client.d.ts.map +1 -0
  20. package/dist/slack-api-client.js +227 -0
  21. package/dist/slack-api-client.js.map +1 -0
  22. package/dist/tool-loader.d.ts +35 -0
  23. package/dist/tool-loader.d.ts.map +1 -0
  24. package/dist/tool-loader.js +121 -0
  25. package/dist/tool-loader.js.map +1 -0
  26. package/dist/tool-registry.d.ts +44 -0
  27. package/dist/tool-registry.d.ts.map +1 -0
  28. package/dist/tool-registry.js +56 -0
  29. package/dist/tool-registry.js.map +1 -0
  30. package/dist/tools/cache.d.ts +69 -0
  31. package/dist/tools/cache.d.ts.map +1 -0
  32. package/dist/tools/cache.js +94 -0
  33. package/dist/tools/cache.js.map +1 -0
  34. package/dist/tools/channels.d.ts +76 -0
  35. package/dist/tools/channels.d.ts.map +1 -0
  36. package/dist/tools/channels.js +251 -0
  37. package/dist/tools/channels.js.map +1 -0
  38. package/dist/tools/conversations.d.ts +77 -0
  39. package/dist/tools/conversations.d.ts.map +1 -0
  40. package/dist/tools/conversations.js +302 -0
  41. package/dist/tools/conversations.js.map +1 -0
  42. package/dist/tools/files.d.ts +15 -0
  43. package/dist/tools/files.d.ts.map +1 -0
  44. package/dist/tools/files.js +30 -0
  45. package/dist/tools/files.js.map +1 -0
  46. package/dist/tools/index.d.ts +12 -0
  47. package/dist/tools/index.d.ts.map +1 -0
  48. package/dist/tools/index.js +20 -0
  49. package/dist/tools/index.js.map +1 -0
  50. package/dist/tools/messages.d.ts +20 -0
  51. package/dist/tools/messages.d.ts.map +1 -0
  52. package/dist/tools/messages.js +40 -0
  53. package/dist/tools/messages.js.map +1 -0
  54. package/dist/tools/system.d.ts +48 -0
  55. package/dist/tools/system.d.ts.map +1 -0
  56. package/dist/tools/system.js +124 -0
  57. package/dist/tools/system.js.map +1 -0
  58. package/dist/tools/users.d.ts +69 -0
  59. package/dist/tools/users.d.ts.map +1 -0
  60. package/dist/tools/users.js +179 -0
  61. package/dist/tools/users.js.map +1 -0
  62. package/dist/tools/workspace.d.ts +50 -0
  63. package/dist/tools/workspace.d.ts.map +1 -0
  64. package/dist/tools/workspace.js +56 -0
  65. package/dist/tools/workspace.js.map +1 -0
  66. package/dist/types.d.ts +160 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +2 -0
  69. package/dist/types.js.map +1 -0
  70. package/package.json +48 -0
  71. package/tools.json +483 -0
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # Slack MCP Server
2
+
3
+ A stateless Model Context Protocol (MCP) server for Slack workspace integration with comprehensive messaging, user management, and workspace analytics capabilities.
4
+
5
+ ## Features
6
+
7
+ - **24 Comprehensive Tools**: Full Slack API coverage for messaging, users, channels, files, and more
8
+ - **Enhanced Descriptions**: LLM-friendly parameter descriptions for better tool usage
9
+ - **Caching System**: Intelligent caching with 24h users / 6h channels TTL for performance
10
+ - **Name Resolution**: Automatic resolution of #channel, @user to IDs
11
+ - **Time-based Limits**: Support for "1d", "1w", "30d" format in message queries
12
+ - **Stateless Architecture**: Each request is independent with no session management
13
+ - **Bearer Token Auth**: Per-request authentication via Authorization header
14
+
15
+ ## Quick Start
16
+
17
+ ### Prerequisites
18
+
19
+ - Node.js 18+
20
+ - pnpm (recommended) or npm
21
+ - Slack Bot Token with appropriate scopes
22
+
23
+ ### Installation
24
+
25
+ ```bash
26
+ # Install dependencies
27
+ pnpm install
28
+
29
+ # Build TypeScript
30
+ pnpm run build
31
+
32
+ # Start production server
33
+ pnpm start
34
+
35
+ # Start development server with hot reload
36
+ pnpm run dev
37
+
38
+ # Start with debug logging
39
+ pnpm run dev:debug
40
+ ```
41
+
42
+ ### Docker
43
+
44
+ ```bash
45
+ # Build image
46
+ docker build -t slack-mcp-server .
47
+
48
+ # Run container
49
+ docker run -p 30001:30001 slack-mcp-server
50
+ ```
51
+
52
+ ### Endpoints
53
+
54
+ - **`POST /mcp`** - Main MCP endpoint for tool execution
55
+ - **`GET /health`** - Health check endpoint
56
+
57
+ Default port: **30001**
58
+
59
+ ### Authentication
60
+
61
+ All requests require a Slack Bot Token via Authorization header:
62
+
63
+ ```bash
64
+ Authorization: Bearer xoxb-your-slack-bot-token
65
+ ```
66
+
67
+ [Create a Slack App](https://api.slack.com/apps) and get a Bot User OAuth Token with these scopes:
68
+ - `channels:read`, `channels:history` - Public channels
69
+ - `groups:read`, `groups:history` - Private channels
70
+ - `im:read`, `im:history` - Direct messages
71
+ - `mpim:read`, `mpim:history` - Group DMs
72
+ - `users:read` - User information
73
+ - `chat:write` - Send messages
74
+ - `reactions:write` - Add reactions
75
+ - `files:read` - List files
76
+ - `team:read` - Workspace info
77
+
78
+ ## Tools (24 total)
79
+
80
+ ### Conversation Tools (5)
81
+
82
+ | Tool | Description |
83
+ |------|-------------|
84
+ | `conversations_history` | Get messages from a channel or DM with user details |
85
+ | `conversations_replies` | Get thread replies by channel and thread_ts |
86
+ | `conversations_add_message` | Send a message (supports threading) |
87
+ | `conversations_search_messages` | Search with filters (URL lookup, date, user) |
88
+ | `bulk_conversations_history` | Fetch multiple channels efficiently |
89
+
90
+ ### User Tools (3)
91
+
92
+ | Tool | Description |
93
+ |------|-------------|
94
+ | `users_list` | List users (filter by active/deleted/admins) |
95
+ | `user_info` | Get detailed info for one or more users |
96
+ | `user_presence` | Get online/away status |
97
+
98
+ ### Channel Tools (6)
99
+
100
+ | Tool | Description |
101
+ |------|-------------|
102
+ | `channel_info` | Get channel details (cache-first) |
103
+ | `channel_members` | List members with details |
104
+ | `channels_list` | List by type (public, private, im, mpim) |
105
+ | `channels_detailed` | Efficient bulk channel listing |
106
+ | `set_channel_topic` | Update channel topic |
107
+ | `set_channel_purpose` | Update channel purpose |
108
+
109
+ ### Message Tools (2)
110
+
111
+ | Tool | Description |
112
+ |------|-------------|
113
+ | `message_permalink` | Get permanent link to message |
114
+ | `add_reaction` | Add emoji reaction |
115
+
116
+ ### File Tools (1)
117
+
118
+ | Tool | Description |
119
+ |------|-------------|
120
+ | `files_list` | List files (filter by channel/user/type) |
121
+
122
+ ### Workspace Tools (1)
123
+
124
+ | Tool | Description |
125
+ |------|-------------|
126
+ | `workspace_info` | Get team name, domain, enterprise info |
127
+
128
+ ### Cache Tools (3)
129
+
130
+ | Tool | Description |
131
+ |------|-------------|
132
+ | `initialize_cache` | Pre-populate users and channels cache |
133
+ | `cache_info` | Get cache file locations and freshness |
134
+ | `clear_cache` | Force cache refresh |
135
+
136
+ ### System Tools (2)
137
+
138
+ | Tool | Description |
139
+ |------|-------------|
140
+ | `check_permissions` | Test token scopes |
141
+ | `analytics_summary` | Workspace stats from cache |
142
+
143
+ ## Usage Examples
144
+
145
+ ### Get channel messages
146
+
147
+ ```bash
148
+ curl -X POST http://localhost:30001/mcp \
149
+ -H "Content-Type: application/json" \
150
+ -H "Authorization: Bearer xoxb-your-token" \
151
+ -d '{
152
+ "jsonrpc": "2.0",
153
+ "id": "1",
154
+ "method": "tools/call",
155
+ "params": {
156
+ "name": "conversations_history",
157
+ "arguments": {
158
+ "channel_id": "#general",
159
+ "limit": "1d"
160
+ }
161
+ }
162
+ }'
163
+ ```
164
+
165
+ ### Search messages
166
+
167
+ ```bash
168
+ curl -X POST http://localhost:30001/mcp \
169
+ -H "Content-Type: application/json" \
170
+ -H "Authorization: Bearer xoxb-your-token" \
171
+ -d '{
172
+ "jsonrpc": "2.0",
173
+ "id": "2",
174
+ "method": "tools/call",
175
+ "params": {
176
+ "name": "conversations_search_messages",
177
+ "arguments": {
178
+ "search_query": "deployment",
179
+ "filter_in_channel": "#engineering",
180
+ "filter_date_after": "2024-01-01"
181
+ }
182
+ }
183
+ }'
184
+ ```
185
+
186
+ ### Send a message
187
+
188
+ ```bash
189
+ curl -X POST http://localhost:30001/mcp \
190
+ -H "Content-Type: application/json" \
191
+ -H "Authorization: Bearer xoxb-your-token" \
192
+ -d '{
193
+ "jsonrpc": "2.0",
194
+ "id": "3",
195
+ "method": "tools/call",
196
+ "params": {
197
+ "name": "conversations_add_message",
198
+ "arguments": {
199
+ "channel_id": "#general",
200
+ "payload": "Hello from MCP! *bold* and _italic_"
201
+ }
202
+ }
203
+ }'
204
+ ```
205
+
206
+ ## Caching
207
+
208
+ The server uses file-based caching for performance:
209
+
210
+ - **Users cache**: `~/slack-cache/users_cache.json` (24h TTL)
211
+ - **Channels cache**: `~/slack-cache/channels_cache_v2.json` (6h TTL)
212
+
213
+ Override paths via environment variables:
214
+ - `SLACK_MCP_USERS_CACHE`
215
+ - `SLACK_MCP_CHANNELS_CACHE`
216
+
217
+ Use `initialize_cache` at the start of sessions for best performance.
218
+
219
+ ## Environment Variables
220
+
221
+ | Variable | Description | Default |
222
+ |----------|-------------|---------|
223
+ | `PORT` | Server port | 30001 |
224
+ | `DEBUG` | Enable debug output | false |
225
+ | `SLACK_MCP_USERS_CACHE` | Custom users cache path | ~/slack-cache/users_cache.json |
226
+ | `SLACK_MCP_CHANNELS_CACHE` | Custom channels cache path | ~/slack-cache/channels_cache_v2.json |
227
+
228
+ ## Development
229
+
230
+ ```bash
231
+ # Run with hot reload
232
+ pnpm run dev
233
+
234
+ # Run with debug logging
235
+ DEBUG=true pnpm run dev
236
+
237
+ # Type check
238
+ pnpm run build
239
+ ```
240
+
241
+ ## License
242
+
243
+ PROPRIETARY - BlueNexus AI
@@ -0,0 +1,12 @@
1
+ import type { ToolResponse } from "./types.js";
2
+ export declare const DEBUG_MODE: boolean;
3
+ /**
4
+ * Wraps a tool execution with debug metadata when DEBUG mode is enabled.
5
+ *
6
+ * @param toolName - Name of the tool being executed
7
+ * @param toolInput - Input arguments passed to the tool
8
+ * @param executeToolFn - Async function that executes the tool and returns data
9
+ * @returns ToolResponse with data and optional debug metadata
10
+ */
11
+ export declare function wrapWithDebug<T>(toolName: string, toolInput: unknown, executeToolFn: () => Promise<T>): Promise<ToolResponse<T>>;
12
+ //# sourceMappingURL=debug-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-middleware.d.ts","sourceRoot":"","sources":["../src/debug-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,eAAO,MAAM,UAAU,SAA+B,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,OAAO,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CA0B1B"}
@@ -0,0 +1,36 @@
1
+ // Check if DEBUG mode is enabled via environment variable
2
+ export const DEBUG_MODE = process.env.DEBUG === "true";
3
+ /**
4
+ * Wraps a tool execution with debug metadata when DEBUG mode is enabled.
5
+ *
6
+ * @param toolName - Name of the tool being executed
7
+ * @param toolInput - Input arguments passed to the tool
8
+ * @param executeToolFn - Async function that executes the tool and returns data
9
+ * @returns ToolResponse with data and optional debug metadata
10
+ */
11
+ export async function wrapWithDebug(toolName, toolInput, executeToolFn) {
12
+ const startTime = performance.now();
13
+ try {
14
+ const data = await executeToolFn();
15
+ const endTime = performance.now();
16
+ const toolCallTime = endTime - startTime;
17
+ if (DEBUG_MODE) {
18
+ return {
19
+ data,
20
+ debug: {
21
+ toolName,
22
+ toolInput,
23
+ toolCallTime,
24
+ timestamp: new Date().toISOString(),
25
+ },
26
+ };
27
+ }
28
+ // In non-debug mode, return just the data wrapped
29
+ return { data };
30
+ }
31
+ catch (error) {
32
+ // Re-throw the error to be handled by caller
33
+ throw error;
34
+ }
35
+ }
36
+ //# sourceMappingURL=debug-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-middleware.js","sourceRoot":"","sources":["../src/debug-middleware.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,SAAkB,EAClB,aAA+B;IAE/B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;QAEzC,IAAI,UAAU,EAAE,CAAC;YACf,OAAO;gBACL,IAAI;gBACJ,KAAK,EAAE;oBACL,QAAQ;oBACR,SAAS;oBACT,YAAY;oBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC;aACF,CAAC;QACJ,CAAC;QAED,kDAAkD;QAClD,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6CAA6C;QAC7C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Helper utilities for Slack MCP Server
3
+ */
4
+ import type { LimitParams, CacheFileInfo } from "./types.js";
5
+ /**
6
+ * Get the cache directory path, creating it if necessary
7
+ */
8
+ export declare function getCacheDir(): string;
9
+ /**
10
+ * Check if cache file exists and is fresh
11
+ */
12
+ export declare function isCacheFresh(cachePath: string, cacheDurationHours: number): boolean;
13
+ /**
14
+ * Load data from cache file
15
+ */
16
+ export declare function loadCache<T>(cachePath: string): T | null;
17
+ /**
18
+ * Save data to cache file
19
+ */
20
+ export declare function saveCache<T>(cachePath: string, data: T): void;
21
+ /**
22
+ * Delete cache file
23
+ */
24
+ export declare function deleteCache(cachePath: string): boolean;
25
+ /**
26
+ * Get detailed file information for cache status
27
+ */
28
+ export declare function getCacheFileInfo(filePath: string): CacheFileInfo;
29
+ /**
30
+ * Parse limit parameter into API parameters
31
+ * Supports:
32
+ * - Time-based: "1d", "1w", "30d" -> oldest timestamp
33
+ * - Numeric: "50" -> limit=50
34
+ */
35
+ export declare function parseLimit(limitStr: string): LimitParams;
36
+ /**
37
+ * Format error for consistent error responses
38
+ */
39
+ export declare function formatError(error: unknown): string;
40
+ /**
41
+ * Create a user lookup map from array of users
42
+ */
43
+ export declare function createUserLookup<T extends {
44
+ id: string;
45
+ }>(users: T[]): Map<string, T>;
46
+ /**
47
+ * Create a name-to-ID lookup for users
48
+ */
49
+ export declare function createUserNameLookup(users: Array<{
50
+ id: string;
51
+ name?: string;
52
+ real_name?: string;
53
+ profile?: {
54
+ display_name?: string;
55
+ };
56
+ }>): Map<string, string>;
57
+ /**
58
+ * Extract user details for message enrichment
59
+ */
60
+ export declare function extractUserDetails(user: {
61
+ name?: string;
62
+ real_name?: string;
63
+ is_bot?: boolean;
64
+ profile?: {
65
+ display_name?: string;
66
+ };
67
+ }): {
68
+ username: string;
69
+ real_name: string;
70
+ display_name: string;
71
+ is_bot: boolean;
72
+ };
73
+ /**
74
+ * Convert markdown to Slack format
75
+ * Basic conversion: ** -> * (bold), __ -> _ (italic)
76
+ */
77
+ export declare function markdownToSlack(text: string): string;
78
+ /**
79
+ * Parse Slack message URL to extract channel ID and timestamp
80
+ * URL format: https://workspace.slack.com/archives/C123456789/p1234567890123456
81
+ */
82
+ export declare function parseSlackUrl(url: string): {
83
+ channelId: string;
84
+ ts: string;
85
+ } | null;
86
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAapC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAaT;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAOxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAW7D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAUtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAgChE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA8BxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKlD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACvD,KAAK,EAAE,CAAC,EAAE,GACT,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAQhB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC,CAAC,GACD,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC,GAAG;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB,CAOA;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,GACV;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuB1C"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Helper utilities for Slack MCP Server
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync, unlinkSync } from "fs";
5
+ import { resolve, dirname } from "path";
6
+ import { homedir } from "os";
7
+ /**
8
+ * Get the cache directory path, creating it if necessary
9
+ */
10
+ export function getCacheDir() {
11
+ const cacheDir = resolve(homedir(), "slack-cache");
12
+ if (!existsSync(cacheDir)) {
13
+ try {
14
+ mkdirSync(cacheDir, { recursive: true });
15
+ }
16
+ catch {
17
+ // Fall back to current directory if can't create ~/slack-cache
18
+ return ".";
19
+ }
20
+ }
21
+ return cacheDir;
22
+ }
23
+ /**
24
+ * Check if cache file exists and is fresh
25
+ */
26
+ export function isCacheFresh(cachePath, cacheDurationHours) {
27
+ if (!existsSync(cachePath)) {
28
+ return false;
29
+ }
30
+ try {
31
+ const stat = statSync(cachePath);
32
+ const cacheAge = Date.now() - stat.mtimeMs;
33
+ const maxAge = cacheDurationHours * 60 * 60 * 1000;
34
+ return cacheAge < maxAge;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * Load data from cache file
42
+ */
43
+ export function loadCache(cachePath) {
44
+ try {
45
+ const data = readFileSync(cachePath, "utf-8");
46
+ return JSON.parse(data);
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ /**
53
+ * Save data to cache file
54
+ */
55
+ export function saveCache(cachePath, data) {
56
+ try {
57
+ // Ensure directory exists
58
+ const dir = dirname(cachePath);
59
+ if (!existsSync(dir)) {
60
+ mkdirSync(dir, { recursive: true });
61
+ }
62
+ writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
63
+ }
64
+ catch (error) {
65
+ console.warn(`Failed to save cache to ${cachePath}:`, error);
66
+ }
67
+ }
68
+ /**
69
+ * Delete cache file
70
+ */
71
+ export function deleteCache(cachePath) {
72
+ try {
73
+ if (existsSync(cachePath)) {
74
+ unlinkSync(cachePath);
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ /**
84
+ * Get detailed file information for cache status
85
+ */
86
+ export function getCacheFileInfo(filePath) {
87
+ const absPath = resolve(filePath);
88
+ if (existsSync(absPath)) {
89
+ try {
90
+ const stat = statSync(absPath);
91
+ const ageMs = Date.now() - stat.mtimeMs;
92
+ const ageHours = ageMs / (1000 * 60 * 60);
93
+ return {
94
+ exists: true,
95
+ absolute_path: absPath,
96
+ size_bytes: stat.size,
97
+ size_kb: Math.round((stat.size / 1024) * 100) / 100,
98
+ last_modified: new Date(stat.mtimeMs).toISOString(),
99
+ age_hours: Math.round(ageHours * 100) / 100,
100
+ is_fresh: ageHours < 24,
101
+ };
102
+ }
103
+ catch {
104
+ // Fall through to return non-existent info
105
+ }
106
+ }
107
+ return {
108
+ exists: false,
109
+ absolute_path: absPath,
110
+ size_bytes: 0,
111
+ size_kb: 0,
112
+ last_modified: null,
113
+ age_hours: null,
114
+ is_fresh: false,
115
+ };
116
+ }
117
+ /**
118
+ * Parse limit parameter into API parameters
119
+ * Supports:
120
+ * - Time-based: "1d", "1w", "30d" -> oldest timestamp
121
+ * - Numeric: "50" -> limit=50
122
+ */
123
+ export function parseLimit(limitStr) {
124
+ if (!limitStr) {
125
+ return { limit: 100 };
126
+ }
127
+ // Check if it's a time-based limit (e.g., "1d", "1w", "30d")
128
+ if (limitStr.endsWith("d") || limitStr.endsWith("w")) {
129
+ let days;
130
+ if (limitStr.endsWith("d")) {
131
+ days = parseInt(limitStr.slice(0, -1), 10);
132
+ }
133
+ else {
134
+ days = parseInt(limitStr.slice(0, -1), 10) * 7;
135
+ }
136
+ if (isNaN(days) || days <= 0) {
137
+ return { limit: 100 };
138
+ }
139
+ // Convert to timestamp
140
+ const oldestTs = (Date.now() - days * 24 * 60 * 60 * 1000) / 1000;
141
+ return { oldest: String(oldestTs), limit: 1000 };
142
+ }
143
+ // Numeric limit
144
+ const limit = parseInt(limitStr, 10);
145
+ if (isNaN(limit) || limit <= 0) {
146
+ return { limit: 100 };
147
+ }
148
+ return { limit: Math.min(limit, 1000) };
149
+ }
150
+ /**
151
+ * Format error for consistent error responses
152
+ */
153
+ export function formatError(error) {
154
+ if (error instanceof Error) {
155
+ return error.message;
156
+ }
157
+ return String(error);
158
+ }
159
+ /**
160
+ * Create a user lookup map from array of users
161
+ */
162
+ export function createUserLookup(users) {
163
+ const lookup = new Map();
164
+ for (const user of users) {
165
+ if (user.id) {
166
+ lookup.set(user.id, user);
167
+ }
168
+ }
169
+ return lookup;
170
+ }
171
+ /**
172
+ * Create a name-to-ID lookup for users
173
+ */
174
+ export function createUserNameLookup(users) {
175
+ const lookup = new Map();
176
+ for (const user of users) {
177
+ if (!user.id)
178
+ continue;
179
+ if (user.name) {
180
+ lookup.set(user.name, user.id);
181
+ lookup.set(user.name.toLowerCase(), user.id);
182
+ }
183
+ if (user.real_name) {
184
+ lookup.set(user.real_name, user.id);
185
+ lookup.set(user.real_name.toLowerCase(), user.id);
186
+ }
187
+ if (user.profile?.display_name) {
188
+ lookup.set(user.profile.display_name, user.id);
189
+ lookup.set(user.profile.display_name.toLowerCase(), user.id);
190
+ }
191
+ }
192
+ return lookup;
193
+ }
194
+ /**
195
+ * Extract user details for message enrichment
196
+ */
197
+ export function extractUserDetails(user) {
198
+ return {
199
+ username: user.name || "unknown",
200
+ real_name: user.real_name || "Unknown",
201
+ display_name: user.profile?.display_name || "",
202
+ is_bot: user.is_bot || false,
203
+ };
204
+ }
205
+ /**
206
+ * Convert markdown to Slack format
207
+ * Basic conversion: ** -> * (bold), __ -> _ (italic)
208
+ */
209
+ export function markdownToSlack(text) {
210
+ return text.replace(/\*\*/g, "*").replace(/__/g, "_");
211
+ }
212
+ /**
213
+ * Parse Slack message URL to extract channel ID and timestamp
214
+ * URL format: https://workspace.slack.com/archives/C123456789/p1234567890123456
215
+ */
216
+ export function parseSlackUrl(url) {
217
+ if (!url.includes("slack.com/archives/")) {
218
+ return null;
219
+ }
220
+ const parts = url.split("/");
221
+ if (parts.length < 6) {
222
+ return null;
223
+ }
224
+ const channelId = parts[parts.length - 2];
225
+ const tsPart = parts[parts.length - 1];
226
+ if (!tsPart.startsWith("p")) {
227
+ return null;
228
+ }
229
+ // Convert permalink timestamp to message timestamp
230
+ // p1234567890123456 -> 1234567890.123456
231
+ const tsRaw = tsPart.slice(1);
232
+ const ts = `${tsRaw.slice(0, 10)}.${tsRaw.slice(10)}`;
233
+ return { channelId, ts };
234
+ }
235
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Slack MCP Server
4
+ *
5
+ * A stateless Model Context Protocol server for Slack API
6
+ * using Bearer token authentication.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}