@ignission/slack-task-mcp 0.2.1 → 0.2.2
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 +21 -0
- package/README.md +215 -59
- package/package.json +13 -1
- package/src/auth.js +190 -91
- package/src/credentials.js +1 -1
- package/README.ja.md +0 -112
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ignission G.K.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,112 +1,268 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">🧠 Slack Task MCP</h1>
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>メンションから着手までの摩擦をゼロに</strong>
|
|
7
|
+
</p>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@ignission/slack-task-mcp"><img src="https://img.shields.io/npm/v/@ignission/slack-task-mcp" alt="npm version"></a>
|
|
11
|
+
<a href="https://opensource.org/licenses/ISC"><img src="https://img.shields.io/badge/License-ISC-blue.svg" alt="License: ISC"></a>
|
|
12
|
+
</p>
|
|
6
13
|
|
|
7
|
-
|
|
14
|
+
<p align="center">
|
|
15
|
+
ADHDの特性を持つユーザーのために設計されたMCPサーバー
|
|
16
|
+
</p>
|
|
8
17
|
|
|
9
|
-
|
|
18
|
+
---
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
- You freeze when complex requests come in, unsure what to ask
|
|
13
|
-
- Writing replies takes too long
|
|
14
|
-
- You break down tasks but lose focus midway
|
|
20
|
+
## Why
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
Slackのメンションがたまると、どこから手を付けていいか迷う。難しい依頼が来ると、何を聞けばいいかわからず固まる。返信を書くのに時間がかかる——そんな経験はありませんか?
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
<p align="center">
|
|
25
|
+
|
|
26
|
+
| 😵 困りごと | ➡️ | 🎯 解決 |
|
|
27
|
+
|:---:|:---:|:---:|
|
|
28
|
+
| 「何求められてる?」が曖昧で固まる | → | 目的の明確化 |
|
|
29
|
+
| 「何聞けばいい?」がわからない | → | 不明点の洗い出し + 確認メッセージ案 |
|
|
30
|
+
| 「どう返せばいい?」で時間かかる | → | 返信メッセージの添削・構造化 |
|
|
31
|
+
| 「次何する?」で迷う | → | ネクストアクション提示 |
|
|
32
|
+
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
graph TB
|
|
41
|
+
subgraph Client ["Claude Desktop / Claude Code"]
|
|
42
|
+
MCP["MCP Client"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
subgraph Core ["Slack Task MCP"]
|
|
46
|
+
Server["MCP Server<br/>(stdio transport)"]
|
|
47
|
+
|
|
48
|
+
subgraph Tools ["MCPツール"]
|
|
49
|
+
SlackTools["🔗 Slack連携<br/>get_slack_thread<br/>search_slack"]
|
|
50
|
+
TaskTools["📋 タスク管理<br/>save/list/search<br/>complete_step"]
|
|
51
|
+
AITools["🤖 AI支援<br/>analyze_request<br/>draft_reply"]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
subgraph AgentSDK ["Agent SDK Layer"]
|
|
55
|
+
Analyze["analyze.js<br/>依頼分析"]
|
|
56
|
+
Draft["draft-reply.js<br/>返信添削"]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
21
59
|
|
|
22
|
-
|
|
23
|
-
|
|
60
|
+
subgraph External ["外部サービス"]
|
|
61
|
+
SlackAPI["Slack API"]
|
|
62
|
+
ClaudeAPI["Claude API"]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
MCP -->|MCP Protocol| Server
|
|
66
|
+
Server --> Tools
|
|
67
|
+
AITools --> AgentSDK
|
|
68
|
+
Analyze -->|query| ClaudeAPI
|
|
69
|
+
Draft -->|query| ClaudeAPI
|
|
70
|
+
SlackTools -->|User Token| SlackAPI
|
|
24
71
|
```
|
|
25
72
|
|
|
26
|
-
|
|
73
|
+
**ポイント:**
|
|
74
|
+
- **MCP Server**: Slack APIとのやり取り、タスク管理を担当
|
|
75
|
+
- **Agent SDK Layer**: Claude APIを使った高度な分析・添削処理を担当
|
|
27
76
|
|
|
28
|
-
|
|
77
|
+
---
|
|
29
78
|
|
|
30
|
-
|
|
79
|
+
## Features
|
|
31
80
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
81
|
+
| ツール | 機能 | Agent SDK |
|
|
82
|
+
|--------|------|:---------:|
|
|
83
|
+
| `get_slack_thread` | SlackスレッドのURLからメッセージを取得 | - |
|
|
84
|
+
| `analyze_request` | 依頼を分析し、目的・不明点・確認案を生成 | ✅ |
|
|
85
|
+
| `draft_reply` | 返信を添削し、ロジカルに構造化 | ✅ |
|
|
86
|
+
| `save_task` | タスクを保存(5分以内のステップに分解) | - |
|
|
87
|
+
| `list_tasks` | アクティブなタスク一覧を表示 | - |
|
|
88
|
+
| `search_tasks` | キーワード・日付でタスクを検索 | - |
|
|
89
|
+
| `complete_step` | ステップを完了にする | - |
|
|
90
|
+
| `search_slack` | Slackメッセージをキーワードで検索 | - |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Quick Start
|
|
95
|
+
|
|
96
|
+
### 1. Slack認証
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx @ignission/slack-task-mcp auth login
|
|
41
100
|
```
|
|
42
101
|
|
|
43
|
-
|
|
102
|
+
ブラウザが開き、Slackの認証画面が表示されます。複数のワークスペースを認証する場合は、このコマンドを繰り返し実行してください。
|
|
103
|
+
|
|
104
|
+
### 2. Claude Code / Claude Desktop の設定
|
|
44
105
|
|
|
45
|
-
|
|
106
|
+
**Claude Code (ターミナル)**:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
claude mcp add slack-task -- npx -y @ignission/slack-task-mcp
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Claude Desktop** (`~/.claude/claude_desktop_config.json`):
|
|
46
113
|
|
|
47
114
|
```json
|
|
48
115
|
{
|
|
49
116
|
"mcpServers": {
|
|
50
117
|
"slack-task": {
|
|
51
|
-
"command": "npx
|
|
52
|
-
"args": ["-y", "slack-task-mcp"]
|
|
118
|
+
"command": "npx",
|
|
119
|
+
"args": ["-y", "@ignission/slack-task-mcp"]
|
|
53
120
|
}
|
|
54
121
|
}
|
|
55
122
|
}
|
|
56
123
|
```
|
|
57
124
|
|
|
58
|
-
|
|
125
|
+
### 3. 再起動
|
|
59
126
|
|
|
60
|
-
|
|
127
|
+
設定を反映するためにClaude Code / Claude Desktopを再起動してください。
|
|
61
128
|
|
|
62
|
-
|
|
63
|
-
|------|-------------|
|
|
64
|
-
| `get_slack_thread` | Fetch messages from a Slack thread URL |
|
|
65
|
-
| `analyze_request` | Analyze requests and generate purpose, questions, and confirmation messages |
|
|
66
|
-
| `draft_reply` | Edit and structure replies logically |
|
|
67
|
-
| `save_task` | Save tasks (broken into 5-minute steps) |
|
|
68
|
-
| `list_tasks` | Display task list |
|
|
69
|
-
| `search_tasks` | Search tasks by keyword or date |
|
|
70
|
-
| `complete_step` | Mark a step as complete |
|
|
71
|
-
| `search_slack` | Search Slack messages by keyword |
|
|
129
|
+
---
|
|
72
130
|
|
|
73
131
|
## Usage
|
|
74
132
|
|
|
75
|
-
###
|
|
133
|
+
### 基本ワークフロー
|
|
76
134
|
|
|
77
135
|
```
|
|
78
|
-
|
|
136
|
+
1. get_slack_thread → スレッド取得(文脈DB化)
|
|
137
|
+
2. analyze_request → 目的・不明点・確認案を生成
|
|
138
|
+
3. draft_reply → 返信の下書きを添削・構造化
|
|
139
|
+
4. save_task → タスクとして保存
|
|
140
|
+
5. complete_step → 進捗管理
|
|
79
141
|
```
|
|
80
142
|
|
|
81
|
-
###
|
|
143
|
+
### 使用例
|
|
144
|
+
|
|
145
|
+
#### スレッドを取得・分析
|
|
82
146
|
|
|
83
147
|
```
|
|
84
|
-
|
|
148
|
+
このSlackスレッドを分析して:
|
|
149
|
+
https://xxx.slack.com/archives/C12345678/p1234567890123456
|
|
85
150
|
```
|
|
86
151
|
|
|
87
|
-
|
|
152
|
+
#### タスクを保存
|
|
88
153
|
|
|
89
154
|
```
|
|
90
|
-
|
|
155
|
+
このタスクを5分以内のステップに分解して保存して
|
|
91
156
|
```
|
|
92
157
|
|
|
93
|
-
|
|
158
|
+
#### 返信を添削
|
|
94
159
|
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
160
|
+
```
|
|
161
|
+
この返信を添削して「レポートできました。添付します。確認お願いします。」
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### タスク一覧を確認
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
タスク一覧を見せて
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### ステップを完了
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
ステップ1を完了にして
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## ADHDフレンドリー設計
|
|
179
|
+
|
|
180
|
+
- **5分以内で終わるステップに分解** — 小さな達成感を積み重ねる
|
|
181
|
+
- **最初のステップは最も簡単なものに** — 着手のハードルを下げる
|
|
182
|
+
- **途中で止めてもOKな区切りを明示** — 中断しても再開しやすい
|
|
183
|
+
- **Slackを文脈DBとして活用** — 「あの話どうなったっけ」をClaudeに聞ける
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Tech Stack
|
|
188
|
+
|
|
189
|
+
| 技術 | 用途 |
|
|
190
|
+
|------|------|
|
|
191
|
+
| **Node.js** (ES Modules) | ランタイム |
|
|
192
|
+
| **MCP Protocol** | Claude Code / Desktop との通信 |
|
|
193
|
+
| **Claude Agent SDK** | 依頼分析・返信添削の AI 処理 |
|
|
194
|
+
| **Slack Web API** | Slack連携(User Token使用) |
|
|
195
|
+
| **Zod** | スキーマバリデーション |
|
|
196
|
+
| **Cloudflare Workers** | OAuth認証サーバー |
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Project Structure
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
slack-task-mcp/
|
|
204
|
+
├── packages/
|
|
205
|
+
│ ├── core/ # MCPサーバー本体
|
|
206
|
+
│ │ └── src/
|
|
207
|
+
│ │ ├── index.js # サーバーエントリポイント
|
|
208
|
+
│ │ ├── cli.js # CLIコマンド
|
|
209
|
+
│ │ ├── auth.js # OAuth認証
|
|
210
|
+
│ │ └── agents/ # Agent SDK エージェント
|
|
211
|
+
│ │ ├── index.js # 共通設定
|
|
212
|
+
│ │ ├── analyze.js # 依頼分析
|
|
213
|
+
│ │ └── draft-reply.js # 返信添削
|
|
214
|
+
│ └── oauth-worker/ # Cloudflare Workers (OAuth)
|
|
215
|
+
│ └── src/index.js
|
|
216
|
+
├── pnpm-workspace.yaml
|
|
217
|
+
└── package.json
|
|
100
218
|
```
|
|
101
219
|
|
|
220
|
+
---
|
|
221
|
+
|
|
102
222
|
## Data Storage
|
|
103
223
|
|
|
224
|
+
XDG Base Directory Specification に準拠した場所にデータを保存します:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
~/.local/share/slack-task-mcp/
|
|
228
|
+
├── credentials/
|
|
229
|
+
│ ├── T01234567.json # ワークスペースごとの認証情報
|
|
230
|
+
│ └── T98765432.json
|
|
231
|
+
└── tasks.json # タスクデータ
|
|
104
232
|
```
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
233
|
+
|
|
234
|
+
環境変数 `XDG_DATA_HOME` が設定されている場合は、そのパスが使用されます。
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Troubleshooting
|
|
239
|
+
|
|
240
|
+
### Slack APIエラー
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npx @ignission/slack-task-mcp auth status # 認証状態を確認
|
|
244
|
+
npx @ignission/slack-task-mcp auth login # 新しいワークスペースを認証
|
|
245
|
+
npx @ignission/slack-task-mcp auth logout # 全ワークスペースからログアウト
|
|
246
|
+
npx @ignission/slack-task-mcp auth logout -w mycompany # 特定のワークスペースのみログアウト
|
|
108
247
|
```
|
|
109
248
|
|
|
249
|
+
### MCPサーバーが認識されない
|
|
250
|
+
|
|
251
|
+
- 設定ファイルのパスが正しいか確認
|
|
252
|
+
- Claude Code / Claude Desktopを再起動したか確認
|
|
253
|
+
|
|
254
|
+
### プライベートチャンネルが読めない
|
|
255
|
+
|
|
256
|
+
- あなたが参加しているチャンネルのみ読み取り可能です
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
Issue や PR は歓迎です!
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
110
266
|
## License
|
|
111
267
|
|
|
112
|
-
|
|
268
|
+
[ISC](LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ignission/slack-task-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "MCP Server for Slack task management with Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -30,11 +30,23 @@
|
|
|
30
30
|
],
|
|
31
31
|
"author": "Ignission G.K.",
|
|
32
32
|
"license": "MIT",
|
|
33
|
+
"packageManager": "pnpm@10.26.0",
|
|
34
|
+
"scripts": {
|
|
35
|
+
"lint": "biome lint .",
|
|
36
|
+
"format": "biome format --write .",
|
|
37
|
+
"check": "biome check --write .",
|
|
38
|
+
"test": "vitest",
|
|
39
|
+
"test:run": "vitest run"
|
|
40
|
+
},
|
|
33
41
|
"dependencies": {
|
|
34
42
|
"@anthropic-ai/claude-agent-sdk": "^0.1.76",
|
|
35
43
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
36
44
|
"@slack/web-api": "^7.13.0",
|
|
37
45
|
"open": "^10.1.0",
|
|
38
46
|
"zod": "^4.2.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@biomejs/biome": "^2.3.11",
|
|
50
|
+
"vitest": "^4.0.16"
|
|
39
51
|
}
|
|
40
52
|
}
|
package/src/auth.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* OAuth 認証モジュール
|
|
5
5
|
*
|
|
6
|
-
* Cloudflare
|
|
6
|
+
* ハイブリッド方式: Cloudflare Worker + ローカルサーバー
|
|
7
|
+
* - Worker: トークン交換(Client Secretを安全に保持)
|
|
8
|
+
* - ローカルサーバー: コールバック受け取り(KV不要で即時反映)
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
|
-
import
|
|
11
|
+
import http from "node:http";
|
|
10
12
|
import open from "open";
|
|
11
13
|
import {
|
|
12
14
|
listWorkspaces,
|
|
@@ -18,127 +20,224 @@ import {
|
|
|
18
20
|
|
|
19
21
|
// 定数
|
|
20
22
|
const AUTH_TIMEOUT = 5 * 60 * 1000; // 5分
|
|
21
|
-
const
|
|
23
|
+
const DEFAULT_PORT = 8888;
|
|
24
|
+
const MAX_PORT_ATTEMPTS = 10;
|
|
22
25
|
|
|
23
26
|
// OAuth Worker URL
|
|
24
27
|
const OAUTH_WORKER_URL =
|
|
25
28
|
process.env.OAUTH_WORKER_URL || "https://slack-task-mcp-oauth.ignission.workers.dev";
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
|
-
*
|
|
31
|
+
* team_nameからドメインを推測(フォールバック用)
|
|
29
32
|
*/
|
|
30
|
-
function
|
|
31
|
-
return
|
|
33
|
+
function extractDomainFromTeamName(teamName) {
|
|
34
|
+
return teamName
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^a-z0-9-]/g, "-")
|
|
37
|
+
.replace(/-+/g, "-")
|
|
38
|
+
.replace(/^-|-$/g, "");
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
/**
|
|
35
|
-
*
|
|
42
|
+
* 空いているポートを探す
|
|
36
43
|
*/
|
|
37
|
-
async function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
async function findAvailablePort(startPort) {
|
|
45
|
+
for (let port = startPort; port < startPort + MAX_PORT_ATTEMPTS; port++) {
|
|
46
|
+
const available = await new Promise((resolve) => {
|
|
47
|
+
const server = http.createServer();
|
|
48
|
+
server.once("error", () => resolve(false));
|
|
49
|
+
server.once("listening", () => {
|
|
50
|
+
server.close();
|
|
51
|
+
resolve(true);
|
|
52
|
+
});
|
|
53
|
+
server.listen(port, "127.0.0.1");
|
|
54
|
+
});
|
|
55
|
+
if (available) return port;
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`ポート ${startPort}-${startPort + MAX_PORT_ATTEMPTS - 1} が全て使用中です`);
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
/**
|
|
47
|
-
*
|
|
48
|
-
* Cloudflare Workers を使用
|
|
61
|
+
* HTMLレスポンスを生成
|
|
49
62
|
*/
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
await open(authUrl);
|
|
70
|
-
} catch (_err) {
|
|
71
|
-
console.log("");
|
|
72
|
-
console.log("ブラウザを自動で開けませんでした。以下の URL を手動で開いてください:");
|
|
73
|
-
console.log("");
|
|
74
|
-
console.log(authUrl);
|
|
63
|
+
function htmlResponse(title, message, isError = false) {
|
|
64
|
+
const icon = isError ? "❌" : "✅";
|
|
65
|
+
const color = isError ? "#dc3545" : "#28a745";
|
|
66
|
+
return `
|
|
67
|
+
<!DOCTYPE html>
|
|
68
|
+
<html>
|
|
69
|
+
<head>
|
|
70
|
+
<meta charset="utf-8">
|
|
71
|
+
<title>${title}</title>
|
|
72
|
+
<style>
|
|
73
|
+
body {
|
|
74
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
align-items: center;
|
|
78
|
+
min-height: 100vh;
|
|
79
|
+
margin: 0;
|
|
80
|
+
background: #f5f5f5;
|
|
75
81
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
.container {
|
|
83
|
+
text-align: center;
|
|
84
|
+
padding: 40px;
|
|
85
|
+
background: white;
|
|
86
|
+
border-radius: 12px;
|
|
87
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
88
|
+
}
|
|
89
|
+
.icon { font-size: 48px; margin-bottom: 16px; }
|
|
90
|
+
h1 { color: ${color}; margin: 0 0 16px 0; }
|
|
91
|
+
p { color: #666; margin: 0; }
|
|
92
|
+
</style>
|
|
93
|
+
</head>
|
|
94
|
+
<body>
|
|
95
|
+
<div class="container">
|
|
96
|
+
<div class="icon">${icon}</div>
|
|
97
|
+
<h1>${title}</h1>
|
|
98
|
+
<p>${message}</p>
|
|
99
|
+
</div>
|
|
100
|
+
</body>
|
|
101
|
+
</html>`;
|
|
102
|
+
}
|
|
80
103
|
|
|
81
|
-
|
|
82
|
-
|
|
104
|
+
/**
|
|
105
|
+
* ハイブリッド方式でOAuth認証を実行
|
|
106
|
+
* 1. ローカルサーバーを起動
|
|
107
|
+
* 2. Worker経由でSlack認証
|
|
108
|
+
* 3. Workerがトークン交換後、ローカルサーバーにリダイレクト
|
|
109
|
+
*/
|
|
110
|
+
async function startHybridOAuth(options = {}) {
|
|
111
|
+
const noBrowser = options.noBrowser || false;
|
|
83
112
|
|
|
84
|
-
|
|
85
|
-
|
|
113
|
+
// 空きポートを探す
|
|
114
|
+
const port = await findAvailablePort(DEFAULT_PORT);
|
|
86
115
|
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
let server;
|
|
118
|
+
let timeoutId;
|
|
89
119
|
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
const cleanup = () => {
|
|
121
|
+
clearTimeout(timeoutId);
|
|
122
|
+
if (server) {
|
|
123
|
+
server.close();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
server = http.createServer(async (req, res) => {
|
|
128
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
129
|
+
|
|
130
|
+
if (url.pathname === "/callback") {
|
|
131
|
+
// Workerからリダイレクトされてきたトークン情報を取得
|
|
132
|
+
const accessToken = url.searchParams.get("access_token");
|
|
133
|
+
const error = url.searchParams.get("error");
|
|
134
|
+
|
|
135
|
+
if (error) {
|
|
136
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
137
|
+
res.end(htmlResponse("認証キャンセル", "このウィンドウを閉じてください。", true));
|
|
138
|
+
console.error("");
|
|
139
|
+
console.error(`❌ 認証がキャンセルされました: ${error}`);
|
|
140
|
+
cleanup();
|
|
141
|
+
resolve(false);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!accessToken) {
|
|
146
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
147
|
+
res.end(htmlResponse("エラー", "トークンが取得できませんでした。", true));
|
|
148
|
+
console.error("");
|
|
149
|
+
console.error("❌ トークンが取得できませんでした");
|
|
150
|
+
cleanup();
|
|
151
|
+
resolve(false);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// credentials を保存
|
|
156
|
+
const teamName = url.searchParams.get("team_name") || "Unknown";
|
|
157
|
+
const teamDomain = url.searchParams.get("team_domain") || extractDomainFromTeamName(teamName);
|
|
92
158
|
const credentials = {
|
|
93
|
-
access_token:
|
|
94
|
-
token_type:
|
|
95
|
-
scope:
|
|
96
|
-
user_id:
|
|
97
|
-
team_id:
|
|
98
|
-
team_name:
|
|
99
|
-
team_domain:
|
|
100
|
-
created_at:
|
|
159
|
+
access_token: accessToken,
|
|
160
|
+
token_type: url.searchParams.get("token_type") || "user",
|
|
161
|
+
scope: url.searchParams.get("scope") || "",
|
|
162
|
+
user_id: url.searchParams.get("user_id") || "",
|
|
163
|
+
team_id: url.searchParams.get("team_id") || "",
|
|
164
|
+
team_name: teamName,
|
|
165
|
+
team_domain: teamDomain,
|
|
166
|
+
created_at: new Date().toISOString(),
|
|
101
167
|
};
|
|
102
168
|
|
|
103
|
-
|
|
169
|
+
try {
|
|
170
|
+
await saveCredentials(credentials);
|
|
171
|
+
|
|
172
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
173
|
+
res.end(htmlResponse(
|
|
174
|
+
"認証が完了しました!",
|
|
175
|
+
`ワークスペース: ${credentials.team_name}<br>このウィンドウを閉じてください。`
|
|
176
|
+
));
|
|
177
|
+
|
|
178
|
+
console.log("");
|
|
179
|
+
console.log("✅ 認証が完了しました!");
|
|
180
|
+
console.log(` ワークスペース: ${credentials.team_name}`);
|
|
181
|
+
console.log(` ドメイン: ${credentials.team_domain}.slack.com`);
|
|
182
|
+
console.log(` 保存先: ${getCredentialsDir()}/${credentials.team_id}.json`);
|
|
183
|
+
|
|
184
|
+
cleanup();
|
|
185
|
+
resolve(true);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
|
|
188
|
+
res.end(htmlResponse("エラー", err.message, true));
|
|
189
|
+
console.error("");
|
|
190
|
+
console.error(`❌ 認証情報の保存に失敗: ${err.message}`);
|
|
191
|
+
cleanup();
|
|
192
|
+
resolve(false);
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
res.writeHead(404);
|
|
196
|
+
res.end("Not Found");
|
|
197
|
+
}
|
|
198
|
+
});
|
|
104
199
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
console.log(` ドメイン: ${credentials.team_domain}.slack.com`);
|
|
109
|
-
console.log(` 保存先: ${getCredentialsDir()}/${credentials.team_id}.json`);
|
|
200
|
+
server.listen(port, "127.0.0.1", () => {
|
|
201
|
+
// Worker の認証 URL を生成
|
|
202
|
+
const authUrl = `${OAUTH_WORKER_URL}/auth?port=${port}`;
|
|
110
203
|
|
|
111
|
-
|
|
112
|
-
|
|
204
|
+
console.log("🔐 Slack OAuth 認証を開始します...");
|
|
205
|
+
console.log("");
|
|
113
206
|
|
|
114
|
-
if (
|
|
115
|
-
console.
|
|
116
|
-
console.
|
|
117
|
-
|
|
207
|
+
if (noBrowser) {
|
|
208
|
+
console.log("以下の URL をブラウザで開いてください:");
|
|
209
|
+
console.log("");
|
|
210
|
+
console.log(authUrl);
|
|
211
|
+
} else {
|
|
212
|
+
console.log("ブラウザで Slack ログイン画面を開いています...");
|
|
213
|
+
open(authUrl).catch(() => {
|
|
214
|
+
console.log("");
|
|
215
|
+
console.log("ブラウザを自動で開けませんでした。以下の URL を手動で開いてください:");
|
|
216
|
+
console.log("");
|
|
217
|
+
console.log(authUrl);
|
|
218
|
+
});
|
|
118
219
|
}
|
|
119
220
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
221
|
+
console.log("");
|
|
222
|
+
console.log("認証が完了するまで待機中...");
|
|
223
|
+
console.log(`(コールバック待機: http://localhost:${port})`);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// タイムアウト設定
|
|
227
|
+
timeoutId = setTimeout(() => {
|
|
228
|
+
console.error("");
|
|
229
|
+
console.error("❌ 認証がタイムアウトしました(5分)");
|
|
230
|
+
cleanup();
|
|
231
|
+
resolve(false);
|
|
232
|
+
}, AUTH_TIMEOUT);
|
|
233
|
+
});
|
|
131
234
|
}
|
|
132
235
|
|
|
133
236
|
/**
|
|
134
|
-
*
|
|
237
|
+
* OAuth 認証フローを実行
|
|
135
238
|
*/
|
|
136
|
-
function
|
|
137
|
-
return
|
|
138
|
-
.toLowerCase()
|
|
139
|
-
.replace(/[^a-z0-9-]/g, "-")
|
|
140
|
-
.replace(/-+/g, "-")
|
|
141
|
-
.replace(/^-|-$/g, "");
|
|
239
|
+
export async function authenticate(options = {}) {
|
|
240
|
+
return startHybridOAuth(options);
|
|
142
241
|
}
|
|
143
242
|
|
|
144
243
|
/**
|
package/src/credentials.js
CHANGED
|
@@ -15,7 +15,7 @@ export { _getCredentialsDir as getCredentialsDir };
|
|
|
15
15
|
* 認証情報ディレクトリを初期化
|
|
16
16
|
*/
|
|
17
17
|
async function ensureCredentialsDir() {
|
|
18
|
-
const dir =
|
|
18
|
+
const dir = _getCredentialsDir();
|
|
19
19
|
await fs.mkdir(dir, { recursive: true });
|
|
20
20
|
return dir;
|
|
21
21
|
}
|
package/README.ja.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# slack-task-mcp
|
|
2
|
-
|
|
3
|
-
Slack タスク管理 MCP サーバー for Claude Code / Claude Desktop
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/slack-task-mcp)
|
|
6
|
-
|
|
7
|
-
[English](https://github.com/ignission/slack-task-mcp/blob/main/packages/core/README.md)
|
|
8
|
-
|
|
9
|
-
## こんな人向け
|
|
10
|
-
|
|
11
|
-
- Slackのメンションがたまると、どこから手を付けていいか迷う
|
|
12
|
-
- 難しい依頼が来ると、何を聞けばいいかわからず固まる
|
|
13
|
-
- 返信を書くのに時間がかかる
|
|
14
|
-
- タスクを分解しても、途中で集中が切れて諦めてしまう
|
|
15
|
-
|
|
16
|
-
## インストール
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
# 認証(初回のみ)
|
|
20
|
-
npx slack-task-mcp auth
|
|
21
|
-
|
|
22
|
-
# 認証状態を確認
|
|
23
|
-
npx slack-task-mcp auth status
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Claude Desktop 設定
|
|
27
|
-
|
|
28
|
-
### macOS
|
|
29
|
-
|
|
30
|
-
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{
|
|
34
|
-
"mcpServers": {
|
|
35
|
-
"slack-task": {
|
|
36
|
-
"command": "npx",
|
|
37
|
-
"args": ["-y", "slack-task-mcp"]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Windows
|
|
44
|
-
|
|
45
|
-
`%APPDATA%\Claude\claude_desktop_config.json`:
|
|
46
|
-
|
|
47
|
-
```json
|
|
48
|
-
{
|
|
49
|
-
"mcpServers": {
|
|
50
|
-
"slack-task": {
|
|
51
|
-
"command": "npx.cmd",
|
|
52
|
-
"args": ["-y", "slack-task-mcp"]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
設定後、Claude Desktopを再起動してください。
|
|
59
|
-
|
|
60
|
-
## 機能
|
|
61
|
-
|
|
62
|
-
| ツール | 説明 |
|
|
63
|
-
|--------|------|
|
|
64
|
-
| `get_slack_thread` | SlackスレッドURLからメッセージを取得 |
|
|
65
|
-
| `analyze_request` | 依頼を分析し、目的・不明点・確認案を生成 |
|
|
66
|
-
| `draft_reply` | 返信を添削し、ロジカルに構造化 |
|
|
67
|
-
| `save_task` | タスクを保存(5分以内のステップに分解) |
|
|
68
|
-
| `list_tasks` | タスク一覧を表示 |
|
|
69
|
-
| `search_tasks` | キーワード・日付でタスクを検索 |
|
|
70
|
-
| `complete_step` | ステップを完了にする |
|
|
71
|
-
| `search_slack` | Slackメッセージをキーワードで検索 |
|
|
72
|
-
|
|
73
|
-
## 使い方
|
|
74
|
-
|
|
75
|
-
### Slackスレッドを分析
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
このスレッドを分析して: https://xxx.slack.com/archives/C12345678/p1234567890
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### タスクとして保存
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
5分以内のステップに分解して保存して
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 返信を添削
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
この返信を添削して「レポートできました。確認お願いします。」
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## CLIコマンド
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
npx slack-task-mcp auth # 認証
|
|
97
|
-
npx slack-task-mcp auth status # 認証状態を確認
|
|
98
|
-
npx slack-task-mcp auth logout # ログアウト
|
|
99
|
-
npx slack-task-mcp --help # ヘルプ
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## データ保存先
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
~/.slack-task-mcp/
|
|
106
|
-
├── credentials.json # 認証情報
|
|
107
|
-
└── tasks.json # タスクデータ
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## ライセンス
|
|
111
|
-
|
|
112
|
-
MIT
|