@impv_npm/task-manager-mcp 1.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 ADDED
@@ -0,0 +1,330 @@
1
+ # Task Manager MCP Server
2
+
3
+ Task ManagerアプリをClaude CodeなどのMCPクライアントから操作するためのMCPサーバーです。
4
+
5
+ ## 概要
6
+
7
+ このMCPサーバーを使用すると、以下の操作をAIアシスタントから直接実行できます:
8
+
9
+ - タスクの一覧取得、作成、開始、完了、クローズ、削除
10
+ - 次に取り組むべきタスクの提案
11
+ - 業務開始/終了の通知とSlackステータスの自動更新
12
+
13
+ ## 前提条件
14
+
15
+ - Task Managerアプリが起動していること(ローカルまたは本番環境)
16
+ - 有効なMCP APIキーを持っていること
17
+
18
+ ## セットアップ手順
19
+
20
+ ### 1. APIキーの作成
21
+
22
+ 1. Task Managerアプリにログイン
23
+ 2. **設定** ページに移動
24
+ 3. **API設定** セクションの **MCP APIキー** カードを見つける
25
+ 4. 「新しいAPIキーを作成」欄に名前を入力(例: "Claude Code")
26
+ 5. **+** ボタンをクリックしてキーを作成
27
+ 6. 表示されたAPIキー(`tm_`で始まる文字列)をコピーして安全に保管
28
+
29
+ **重要**: APIキーは作成時に一度しか表示されません。必ずコピーして保存してください。
30
+
31
+ ### 2. Claude Code での設定
32
+
33
+ `~/.claude/settings.local.json` の `mcpServers` セクションに以下を追加します:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "task-manager": {
39
+ "command": "npx",
40
+ "args": ["-y", "@impv/task-manager-mcp"],
41
+ "env": {
42
+ "TASK_MANAGER_API_KEY": "tm_xxxxxxxxxxxxxxxxxxxx",
43
+ "TASK_MANAGER_URL": "https://your-app.vercel.app"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ **設定項目:**
51
+
52
+ | 環境変数 | 必須 | 説明 |
53
+ |---------|------|------|
54
+ | `TASK_MANAGER_API_KEY` | Yes | 設定画面で作成したAPIキー |
55
+ | `TASK_MANAGER_URL` | No | Task ManagerアプリのURL(デフォルト: `http://localhost:3000`)|
56
+
57
+ ### 3. Claude Code の再起動
58
+
59
+ 設定を反映するためにClaude Codeを再起動します。
60
+
61
+ ## 使用可能なツール
62
+
63
+ ### タスク管理
64
+
65
+ | ツール | 説明 | 主なパラメータ |
66
+ |--------|------|----------------|
67
+ | `task_list` | タスク一覧を取得 | `query`, `status`, `client`, `project`, `assignee`, `includeDone` |
68
+ | `task_add` | 新しいタスクを作成 | `title`, `body`, `client`, `project`, `taskBreakdown`, `dueDate`, `assignees` |
69
+ | `task_start` | タスクを開始(In Progress) | `taskNumber`, `sendSlackNotification` |
70
+ | `task_review` | レビュー待ちに変更(In Review) | `taskNumber` |
71
+ | `task_end` | タスクを完了(Done) | `taskNumber`, `sendSlackNotification` |
72
+ | `task_close` | タスクをクローズ | `taskNumber`, `reason` |
73
+ | `task_delete` | タスクを削除 | `taskNumber`, `confirm` |
74
+ | `task_advise` | 次のタスクを提案 | `assignee`, `includeAll` |
75
+
76
+ ### 業務管理
77
+
78
+ | ツール | 説明 | 主なパラメータ |
79
+ |--------|------|----------------|
80
+ | `work_start` | 業務を開始 | `note` |
81
+ | `work_end` | 業務を終了 | `note` |
82
+
83
+ ## ツール詳細
84
+
85
+ ### task_list
86
+
87
+ タスク一覧を取得します。複数のフィルタを組み合わせて絞り込みができます。
88
+
89
+ **パラメータ:**
90
+ - `query` (string, optional): 検索キーワード
91
+ - `status` (string, optional): "Todo" | "In Progress" | "In Review" | "Done"
92
+ - `client` (string, optional): クライアント名でフィルタ
93
+ - `project` (string, optional): プロジェクト名でフィルタ
94
+ - `assignee` (string, optional): 担当者名でフィルタ
95
+ - `includeDone` (boolean, optional): 完了タスクを含めるか
96
+
97
+ ### task_add
98
+
99
+ 新しいタスクを作成します。クライアントやプロジェクトが存在しない場合は自動的に作成されます。
100
+
101
+ **パラメータ:**
102
+ - `title` (string, required): タスクのタイトル
103
+ - `body` (string, required): タスクの説明
104
+ - `client` (string, optional): クライアント名
105
+ - `project` (string, optional): プロジェクト名
106
+ - `taskBreakdown` (string[], optional): サブタスクのリスト
107
+ - `ticket` (string, optional): 関連チケットURL
108
+ - `requestSource` (string, optional): 依頼元URL
109
+ - `dueDate` (string, optional): 期日(YYYY-MM-DD形式)
110
+ - `assignees` (string[], optional): 担当者のログイン名リスト
111
+
112
+ ### task_start
113
+
114
+ タスクを開始します。ステータスが「In Progress」に変更され、Slackステータスも更新されます。
115
+
116
+ **パラメータ:**
117
+ - `taskNumber` (number, required): タスク番号(#123の123部分)
118
+ - `sendSlackNotification` (boolean, optional): Slack通知を送信するか(デフォルト: true)
119
+
120
+ ### task_review
121
+
122
+ タスクをレビュー待ちに変更します。
123
+
124
+ **パラメータ:**
125
+ - `taskNumber` (number, required): タスク番号
126
+
127
+ ### task_end
128
+
129
+ タスクを完了します。ステータスが「Done」に変更され、Slackステータスも更新されます。
130
+
131
+ **パラメータ:**
132
+ - `taskNumber` (number, required): タスク番号
133
+ - `sendSlackNotification` (boolean, optional): Slack通知を送信するか(デフォルト: true)
134
+
135
+ ### task_close
136
+
137
+ タスクをクローズします(キャンセル、重複などの理由で完了せずに閉じる場合)。
138
+
139
+ **パラメータ:**
140
+ - `taskNumber` (number, required): タスク番号
141
+ - `reason` (string, optional): クローズの理由
142
+
143
+ ### task_delete
144
+
145
+ タスクを完全に削除します。この操作は取り消せません。
146
+
147
+ **パラメータ:**
148
+ - `taskNumber` (number, required): タスク番号
149
+ - `confirm` (boolean, required): 削除確認(trueを指定しないと削除されない)
150
+
151
+ ### task_advise
152
+
153
+ 優先度と期日に基づいて、次に取り組むべきタスクを提案します。
154
+
155
+ **パラメータ:**
156
+ - `assignee` (string, optional): 担当者名でフィルタ
157
+ - `includeAll` (boolean, optional): 全ての推奨タスクを表示するか(デフォルトは上位3件)
158
+
159
+ ### work_start
160
+
161
+ 業務を開始します。Slackに通知を送り、ステータスを業務中に変更します。
162
+
163
+ **パラメータ:**
164
+ - `note` (string, optional): 業務開始時のメモ
165
+
166
+ ### work_end
167
+
168
+ 業務を終了します。Slackに通知を送り、ステータスをクリアします。
169
+
170
+ **パラメータ:**
171
+ - `note` (string, optional): 業務終了時のメモ
172
+
173
+ ## 活用例
174
+
175
+ ### 1. 朝の業務開始
176
+
177
+ ```
178
+ 「業務を開始して」
179
+ → work_start が呼ばれ、Slackステータスが業務中に更新される
180
+ ```
181
+
182
+ ### 2. タスクの確認と着手
183
+
184
+ ```
185
+ 「今日やるべきタスクを教えて」
186
+ → task_advise が呼ばれ、優先度の高いタスクが提案される
187
+
188
+ 「タスク#123を開始する」
189
+ → task_start が呼ばれ、ステータスがIn Progressに変更される
190
+ ```
191
+
192
+ ### 3. タスクの作成
193
+
194
+ ```
195
+ 「Acme社のダッシュボードにグラフ追加するタスクを作成して」
196
+ → task_add が呼ばれ、新しいタスクが作成される
197
+ ```
198
+
199
+ ### 4. タスク一覧の確認
200
+
201
+ ```
202
+ 「進行中のタスク一覧を見せて」
203
+ → task_list が status: "In Progress" で呼ばれる
204
+
205
+ 「Acme社のタスクを教えて」
206
+ → task_list が client: "Acme" で呼ばれる
207
+ ```
208
+
209
+ ### 5. タスクの完了
210
+
211
+ ```
212
+ 「タスク#123を完了した」
213
+ → task_end が呼ばれ、ステータスがDoneに変更される
214
+ ```
215
+
216
+ ### 6. 業務終了
217
+
218
+ ```
219
+ 「業務終了」
220
+ → work_end が呼ばれ、Slackステータスがクリアされる
221
+ ```
222
+
223
+ ## トラブルシューティング
224
+
225
+ ### APIキーのエラー
226
+
227
+ ```
228
+ Error: TASK_MANAGER_API_KEY environment variable is required
229
+ ```
230
+
231
+ → 環境変数 `TASK_MANAGER_API_KEY` が設定されているか確認してください。
232
+
233
+ ```
234
+ Error: Invalid API key format. Key must start with 'tm_'
235
+ ```
236
+
237
+ → APIキーの形式が正しいか確認してください。キーは `tm_` で始まる必要があります。
238
+
239
+ ### 認証エラー
240
+
241
+ ```
242
+ Error: Unauthorized
243
+ ```
244
+
245
+ → APIキーが有効か確認してください。設定画面で新しいキーを発行し直すことをお勧めします。
246
+
247
+ ### サーバーに接続できない
248
+
249
+ → `TASK_MANAGER_URL` が正しいか、Task Managerアプリが起動しているか確認してください。
250
+
251
+ ## セキュリティに関する注意
252
+
253
+ - APIキーは機密情報です。Git リポジトリにコミットしないでください。
254
+ - APIキーが漏洩した場合は、設定画面から即座に削除し、新しいキーを発行してください。
255
+ - 各APIキーは作成したユーザーの権限で操作を実行します。
256
+
257
+ ## 開発
258
+
259
+ ```bash
260
+ # 開発モードで起動
261
+ pnpm dev
262
+
263
+ # ビルド
264
+ pnpm build
265
+
266
+ # ビルド後のサーバーを起動
267
+ pnpm start
268
+ ```
269
+
270
+ ### ローカルでのClaude Code設定
271
+
272
+ ローカル開発時は以下の設定を使用します:
273
+
274
+ ```json
275
+ {
276
+ "mcpServers": {
277
+ "task-manager": {
278
+ "command": "node",
279
+ "args": ["/path/to/task-manager/mcp-server/dist/index.js"],
280
+ "env": {
281
+ "TASK_MANAGER_API_KEY": "tm_xxxxxxxxxxxxxxxxxxxx",
282
+ "TASK_MANAGER_URL": "http://localhost:3000"
283
+ }
284
+ }
285
+ }
286
+ }
287
+ ```
288
+
289
+ ### npm公開
290
+
291
+ ```bash
292
+ cd mcp-server
293
+
294
+ # npmにログイン(初回のみ)
295
+ npm login
296
+
297
+ # 公開
298
+ npm publish --access public
299
+ ```
300
+
301
+ ## アーキテクチャ
302
+
303
+ ```
304
+ Claude Code / MCP Client
305
+
306
+ │ stdio (JSON-RPC)
307
+
308
+ ┌─────────────────────────┐
309
+ │ MCP Server (Node.js) │
310
+ │ - src/index.ts │ MCPサーバーのエントリポイント
311
+ │ - src/tools.ts │ ツールの定義
312
+ │ - src/client.ts │ API呼び出しクライアント
313
+ └─────────────────────────┘
314
+
315
+ │ HTTP (REST API)
316
+
317
+ ┌─────────────────────────┐
318
+ │ Task Manager API │
319
+ │ - /api/mcp │ MCPリクエストのエンドポイント
320
+ └─────────────────────────┘
321
+
322
+
323
+ ┌─────────────────────────┐
324
+ │ Supabase (PostgreSQL) │
325
+ └─────────────────────────┘
326
+ ```
327
+
328
+ ## ライセンス
329
+
330
+ Private
@@ -0,0 +1,12 @@
1
+ interface McpApiResponse<T = unknown> {
2
+ success: boolean;
3
+ data?: T;
4
+ error?: string;
5
+ }
6
+ export declare class TaskManagerClient {
7
+ private baseUrl;
8
+ private apiKey;
9
+ constructor(baseUrl: string, apiKey: string);
10
+ call<T = unknown>(tool: string, params?: Record<string, unknown>): Promise<McpApiResponse<T>>;
11
+ }
12
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,23 @@
1
+ export class TaskManagerClient {
2
+ baseUrl;
3
+ apiKey;
4
+ constructor(baseUrl, apiKey) {
5
+ this.baseUrl = baseUrl.replace(/\/$/, "");
6
+ this.apiKey = apiKey;
7
+ }
8
+ async call(tool, params = {}) {
9
+ const response = await fetch(`${this.baseUrl}/api/mcp`, {
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ "Authorization": `Bearer ${this.apiKey}`,
14
+ },
15
+ body: JSON.stringify({ tool, params }),
16
+ });
17
+ if (!response.ok) {
18
+ const data = await response.json().catch(() => ({ error: "Unknown error" }));
19
+ return { success: false, error: data.error || `HTTP ${response.status}` };
20
+ }
21
+ return await response.json();
22
+ }
23
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { TaskManagerClient } from "./client.js";
5
+ import { registerTools } from "./tools.js";
6
+ async function main() {
7
+ // Environment variable validation
8
+ const apiKey = process.env.TASK_MANAGER_API_KEY;
9
+ const appUrl = process.env.TASK_MANAGER_URL || "http://localhost:3000";
10
+ if (!apiKey) {
11
+ console.error("Error: TASK_MANAGER_API_KEY environment variable is required");
12
+ process.exit(1);
13
+ }
14
+ if (!apiKey.startsWith("tm_")) {
15
+ console.error("Error: Invalid API key format. Key must start with 'tm_'");
16
+ process.exit(1);
17
+ }
18
+ // Create API client
19
+ const client = new TaskManagerClient(appUrl, apiKey);
20
+ // Create MCP server
21
+ const server = new McpServer({
22
+ name: "task-manager",
23
+ version: "1.0.0",
24
+ });
25
+ // Register tools
26
+ registerTools(server, client);
27
+ // Create transport and connect
28
+ const transport = new StdioServerTransport();
29
+ await server.connect(transport);
30
+ }
31
+ main().catch((error) => {
32
+ console.error("Fatal error:", error);
33
+ process.exit(1);
34
+ });
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { TaskManagerClient } from "./client.js";
3
+ export declare function registerTools(server: McpServer, client: TaskManagerClient): void;
package/dist/tools.js ADDED
@@ -0,0 +1,111 @@
1
+ import { z } from "zod";
2
+ export function registerTools(server, client) {
3
+ // task_list - タスク一覧取得
4
+ server.tool("task_list", "タスク一覧を取得します。フィルタリング可能。", {
5
+ query: z.string().optional().describe("検索キーワード"),
6
+ status: z.enum(["Todo", "In Progress", "In Review", "Done"]).optional().describe("ステータスでフィルタ"),
7
+ client: z.string().optional().describe("クライアント名でフィルタ"),
8
+ project: z.string().optional().describe("プロジェクト名でフィルタ"),
9
+ assignee: z.string().optional().describe("担当者名でフィルタ"),
10
+ includeDone: z.boolean().optional().describe("完了タスクを含めるか"),
11
+ }, async (params) => {
12
+ const result = await client.call("task_list", params);
13
+ return {
14
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
15
+ };
16
+ });
17
+ // task_add - タスク作成
18
+ server.tool("task_add", "新しいタスクを作成します。", {
19
+ title: z.string().describe("タスクのタイトル"),
20
+ body: z.string().describe("タスクの説明"),
21
+ client: z.string().optional().describe("クライアント名(存在しない場合は作成)"),
22
+ project: z.string().optional().describe("プロジェクト名(存在しない場合は作成)"),
23
+ taskBreakdown: z.array(z.string()).optional().describe("サブタスクのリスト"),
24
+ ticket: z.string().optional().describe("関連チケットURL"),
25
+ requestSource: z.string().optional().describe("依頼元URL"),
26
+ dueDate: z.string().optional().describe("期日(YYYY-MM-DD形式)"),
27
+ assignees: z.array(z.string()).optional().describe("担当者のログイン名リスト"),
28
+ }, async (params) => {
29
+ const result = await client.call("task_add", params);
30
+ return {
31
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
32
+ };
33
+ });
34
+ // task_start - タスク開始
35
+ server.tool("task_start", "タスクを開始します(In Progressに変更)。Slackステータスも更新されます。", {
36
+ taskNumber: z.number().describe("タスク番号(#123の123部分)"),
37
+ sendSlackNotification: z.boolean().optional().default(true).describe("Slack通知を送信するか"),
38
+ }, async (params) => {
39
+ const result = await client.call("task_start", params);
40
+ return {
41
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
42
+ };
43
+ });
44
+ // task_review - レビュー提出
45
+ server.tool("task_review", "タスクをレビュー待ちに変更します(In Reviewに変更)。", {
46
+ taskNumber: z.number().describe("タスク番号(#123の123部分)"),
47
+ }, async (params) => {
48
+ const result = await client.call("task_review", params);
49
+ return {
50
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
51
+ };
52
+ });
53
+ // task_end - タスク完了
54
+ server.tool("task_end", "タスクを完了します(Doneに変更)。Slackステータスも更新されます。", {
55
+ taskNumber: z.number().describe("タスク番号(#123の123部分)"),
56
+ sendSlackNotification: z.boolean().optional().default(true).describe("Slack通知を送信するか"),
57
+ }, async (params) => {
58
+ const result = await client.call("task_end", params);
59
+ return {
60
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
61
+ };
62
+ });
63
+ // task_close - タスククローズ
64
+ server.tool("task_close", "タスクをクローズします(キャンセル、重複などの理由で完了せずに閉じる)。", {
65
+ taskNumber: z.number().describe("タスク番号(#123の123部分)"),
66
+ reason: z.string().optional().describe("クローズの理由"),
67
+ }, async (params) => {
68
+ const result = await client.call("task_close", params);
69
+ return {
70
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
71
+ };
72
+ });
73
+ // task_delete - タスク削除
74
+ server.tool("task_delete", "タスクを完全に削除します。この操作は取り消せません。", {
75
+ taskNumber: z.number().describe("タスク番号(#123の123部分)"),
76
+ confirm: z.boolean().describe("削除を確認する(trueを指定しないと削除されない)"),
77
+ }, async (params) => {
78
+ const result = await client.call("task_delete", params);
79
+ return {
80
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
81
+ };
82
+ });
83
+ // task_advise - 次のタスク提案
84
+ server.tool("task_advise", "優先度と期日に基づいて、次に取り組むべきタスクを提案します。", {
85
+ assignee: z.string().optional().describe("担当者名でフィルタ"),
86
+ includeAll: z.boolean().optional().describe("全ての推奨タスクを表示するか(デフォルトは上位3件)"),
87
+ }, async (params) => {
88
+ const result = await client.call("task_advise", params);
89
+ return {
90
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
91
+ };
92
+ });
93
+ // work_start - 業務開始
94
+ server.tool("work_start", "業務を開始します。Slackに通知を送り、ステータスを業務中に変更します。", {
95
+ note: z.string().optional().describe("業務開始時のメモ"),
96
+ }, async (params) => {
97
+ const result = await client.call("work_start", params);
98
+ return {
99
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
100
+ };
101
+ });
102
+ // work_end - 業務終了
103
+ server.tool("work_end", "業務を終了します。Slackに通知を送り、ステータスをクリアします。", {
104
+ note: z.string().optional().describe("業務終了時のメモ"),
105
+ }, async (params) => {
106
+ const result = await client.call("work_end", params);
107
+ return {
108
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
109
+ };
110
+ });
111
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@impv_npm/task-manager-mcp",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "task-manager-mcp": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "start": "node dist/index.js",
15
+ "dev": "tsx src/index.ts",
16
+ "prepublishOnly": "pnpm build"
17
+ },
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.0.0",
20
+ "zod": "^4.3.6"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^20",
24
+ "tsx": "^4.7.0",
25
+ "typescript": "^5"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ }
30
+ }