@dyno181cm.nexsoft/zentao_mcp 1.6.0 → 1.7.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
@@ -7,7 +7,7 @@
7
7
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square&logo=node.js)](https://nodejs.org)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?style=flat-square&logo=typescript)](https://www.typescriptlang.org)
9
9
  [![MCP](https://img.shields.io/badge/MCP-compatible-8A2BE2?style=flat-square)](https://modelcontextprotocol.io)
10
- [![Tests](https://img.shields.io/badge/tests-26%20passed-brightgreen?style=flat-square&logo=jest)](https://github.com/dyno-nexsoft/zentao_mcp/tree/master/tests)
10
+ [![Tests](https://img.shields.io/badge/tests-13%20passed-brightgreen?style=flat-square&logo=jest)](https://github.com/dyno-nexsoft/zentao_mcp/tree/master/tests)
11
11
 
12
12
  A **Model Context Protocol (MCP)** server for integrating AI assistants (Claude, Cursor, etc.) with the [ZenTao](https://www.zentao.net) project management API.
13
13
  Fetch task details, bug reports, and attachments — all directly inside your AI chat.
@@ -18,13 +18,12 @@ Fetch task details, bug reports, and attachments — all directly inside your AI
18
18
 
19
19
  | Tool | Description |
20
20
  |---|---|
21
- | `zentao_get_task_details` | Fetch full details of a task by ID (status, assignee, description, history & comments, attachments) |
22
- | `zentao_get_bug_details` | Fetch full details of a bug by ID (severity, repro steps, history & comments, inline images, attachments) |
23
- | `zentao_download_attachment` | Download any ZenTao file attachment to local disk |
21
+ | `zentao_get_details` | Fetch full details of a task or bug by ID |
24
22
  | `zentao_get_comments` | Fetch only the history and comments timeline of a task or bug |
25
23
  | `zentao_add_comment` | Add a comment/remark to a task or bug |
26
24
  | `zentao_update_task_status` | Update task status (start, finish, close, pause, cancel, restart) and add optional comments/hours |
27
25
  | `zentao_update_bug_status` | Update bug status (resolve, close, activate) and add optional comments/resolutions |
26
+ | `zentao_get_assigned_to_me` | Get tasks and bugs currently assigned to you (configured via `ZENTAO_ACCOUNT`) |
28
27
 
29
28
 
30
29
  **Under the hood:**
@@ -104,27 +103,13 @@ Add to your MCP client config (e.g. `claude_desktop_config.json`):
104
103
 
105
104
  ## 🛠️ Available Tools
106
105
 
107
- ### `zentao_get_task_details`
108
- Get full details of a ZenTao task.
106
+ ### `zentao_get_details`
107
+ Get full details of a ZenTao task or bug, including repro steps (for bugs), inline images, attachments, history, and comments.
109
108
 
110
109
  | Parameter | Type | Required | Description |
111
110
  |---|---|---|---|
112
- | `taskId` | `string \| number` | ✅ | Task ID |
113
-
114
- ### `zentao_get_bug_details`
115
- Get full details of a ZenTao bug, including repro steps and inline images.
116
-
117
- | Parameter | Type | Required | Description |
118
- |---|---|---|---|
119
- | `bugId` | `string \| number` | ✅ | Bug ID |
120
-
121
- ### `zentao_download_attachment`
122
- Download a ZenTao file attachment to local disk.
123
-
124
- | Parameter | Type | Required | Description |
125
- |---|---|---|---|
126
- | `fileId` | `string \| number` | ✅ | File ID to download |
127
- | `extension` | `string` | ❌ | File extension hint (e.g. `mp4`, `png`) |
111
+ | `type` | `"task" \| "bug"` | ✅ | Type of the object |
112
+ | `id` | `string \| number` | ✅ | Task or Bug ID |
128
113
 
129
114
  ### `zentao_get_comments`
130
115
  Get only the history and comments timeline of a task or bug.
@@ -171,6 +156,9 @@ Update a bug's status with optional comments and resolutions.
171
156
  | `assignedTo` | `string` | ❌ | Optional user account to assign to next |
172
157
  | `openedBuild` | `string` | ❌ | Optional build ID where bug was found (for `activate`) |
173
158
 
159
+ ### `zentao_get_assigned_to_me`
160
+ Get tasks and bugs currently assigned to the configured user account. Takes no arguments.
161
+
174
162
  ---
175
163
 
176
164
  ## 🧑‍💻 Development
@@ -198,19 +186,19 @@ src/
198
186
  │ ├── attachmentRenderer.ts # Attachments → Markdown ## Files section
199
187
  │ ├── actionFormatter.ts # renderHistoryAndComments
200
188
  │ ├── taskFormatter.ts # taskToMarkdown (includes comments)
201
- └── bugFormatter.ts # bugToMarkdown (includes comments)
189
+ ├── bugFormatter.ts # bugToMarkdown (includes comments)
190
+ │ └── myWorkFormatter.ts # myWorkToMarkdown (includes comments)
202
191
  └── tools/
203
- ├── taskTool.ts # zentao_get_task_details
204
- ├── bugTool.ts # zentao_get_bug_details
205
- ├── downloadTool.ts # zentao_download_attachment
192
+ ├── detailTool.ts # zentao_get_details
206
193
  ├── commentTool.ts # zentao_get_comments · zentao_add_comment
207
- └── statusTool.ts # zentao_update_task_status · zentao_update_bug_status
194
+ ├── statusTool.ts # zentao_update_task_status · zentao_update_bug_status
195
+ └── myWorkTool.ts # zentao_get_assigned_to_me
208
196
  ```
209
197
 
210
198
  ### Running tests
211
199
 
212
200
  ```bash
213
- npm test # Unit tests — 26 tests across ZentaoClient + formatters
201
+ npm test # Unit tests — 13 tests across ZentaoClient
214
202
  npm run test:api # Live API integration test (requires .env)
215
203
  ```
216
204
 
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ import { taskToMarkdown } from "../formatters/taskFormatter.js";
3
+ import { bugToMarkdown } from "../formatters/bugFormatter.js";
4
+ import { buildMcpResponse } from "../utils/mcpResponse.js";
5
+ /**
6
+ * Register the `zentao_get_details` MCP tool on the given server.
7
+ *
8
+ * @param server The MCP Server instance.
9
+ * @param client Authenticated ZentaoClient used to fetch and process data.
10
+ */
11
+ export function registerDetailTool(server, client) {
12
+ server.registerTool("zentao_get_details", {
13
+ description: "Get detailed information of a task or a bug",
14
+ inputSchema: {
15
+ type: z.enum(["task", "bug"]).describe("Type of the object ('task' or 'bug')"),
16
+ id: z.union([z.string(), z.number()]).describe("Task or Bug ID"),
17
+ },
18
+ }, async ({ type, id }) => {
19
+ let data;
20
+ let markdown;
21
+ const downloadedImages = [];
22
+ if (type === "task") {
23
+ data = await client.getTaskDetails(id);
24
+ markdown = await taskToMarkdown(data, client, downloadedImages);
25
+ }
26
+ else {
27
+ data = await client.getBugDetails(id);
28
+ markdown = await bugToMarkdown(data, client, downloadedImages);
29
+ }
30
+ return await buildMcpResponse(markdown, downloadedImages);
31
+ });
32
+ }
package/build/tools.js CHANGED
@@ -13,9 +13,7 @@
13
13
  import { ZentaoClient } from "./zentaoClient.js";
14
14
  import { taskToMarkdown as _taskToMarkdown, } from "./formatters/taskFormatter.js";
15
15
  import { bugToMarkdown as _bugToMarkdown, } from "./formatters/bugFormatter.js";
16
- import { registerTaskTool } from "./tools/taskTool.js";
17
- import { registerBugTool } from "./tools/bugTool.js";
18
- import { registerDownloadTool } from "./tools/downloadTool.js";
16
+ import { registerDetailTool } from "./tools/detailTool.js";
19
17
  import { registerCommentTool } from "./tools/commentTool.js";
20
18
  import { registerStatusTools } from "./tools/statusTool.js";
21
19
  import { registerMyWorkTool } from "./tools/myWorkTool.js";
@@ -37,9 +35,7 @@ export function bugToMarkdown(rawBug, downloadedImages) {
37
35
  * Registers all Zentao MCP tools on the provided server instance.
38
36
  *
39
37
  * Available tools:
40
- * - `zentao_get_task_details` — Fetch full details of a task by ID.
41
- * - `zentao_get_bug_details` — Fetch full details of a bug by ID.
42
- * - `zentao_download_attachment` — Download an attachment and save locally.
38
+ * - `zentao_get_details` — Fetch full details of a task or a bug by ID.
43
39
  * - `zentao_get_comments` — Fetch history and comments timeline for task/bug.
44
40
  * - `zentao_update_task_status` — Update a task's status with comments.
45
41
  * - `zentao_update_bug_status` — Update a bug's status with comments.
@@ -47,9 +43,7 @@ export function bugToMarkdown(rawBug, downloadedImages) {
47
43
  * @param server The MCP Server instance where the tools will be registered.
48
44
  */
49
45
  export function registerTools(server) {
50
- registerTaskTool(server, client);
51
- registerBugTool(server, client);
52
- registerDownloadTool(server, client);
46
+ registerDetailTool(server, client);
53
47
  registerCommentTool(server, client);
54
48
  registerStatusTools(server, client);
55
49
  registerMyWorkTool(server, client);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyno181cm.nexsoft/zentao_mcp",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Zentao MCP Server",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,22 +0,0 @@
1
- import { z } from "zod";
2
- import { bugToMarkdown } from "../formatters/bugFormatter.js";
3
- import { buildMcpResponse } from "../utils/mcpResponse.js";
4
- /**
5
- * Register the `zentao_get_bug_details` MCP tool on the given server.
6
- *
7
- * @param server The MCP Server instance.
8
- * @param client Authenticated ZentaoClient used to fetch and process data.
9
- */
10
- export function registerBugTool(server, client) {
11
- server.registerTool("zentao_get_bug_details", {
12
- description: "Get detailed information of a bug",
13
- inputSchema: {
14
- bugId: z.union([z.string(), z.number()]).describe("Bug ID"),
15
- },
16
- }, async ({ bugId }) => {
17
- const data = await client.getBugDetails(bugId);
18
- const downloadedImages = [];
19
- const markdown = await bugToMarkdown(data, client, downloadedImages);
20
- return await buildMcpResponse(markdown, downloadedImages);
21
- });
22
- }
@@ -1,56 +0,0 @@
1
- import { z } from "zod";
2
- import * as os from "os";
3
- import * as path from "path";
4
- import fs from "fs";
5
- import { mcpText } from "../utils/mcpResponse.js";
6
- /** Tracks in-flight downloads to deduplicate concurrent requests for the same file. */
7
- const activeDownloads = new Map();
8
- /**
9
- * Download a ZenTao attachment to a local path.
10
- * Deduplicates concurrent requests for the same target file.
11
- */
12
- async function downloadAttachment(client, fileId, targetPath) {
13
- if (fs.existsSync(targetPath) && !activeDownloads.has(targetPath)) {
14
- return `File already exists locally at: ${targetPath}`;
15
- }
16
- if (activeDownloads.has(targetPath)) {
17
- await activeDownloads.get(targetPath);
18
- return `File downloaded successfully to: ${targetPath}`;
19
- }
20
- const downloadPromise = client.downloadFile(fileId, targetPath);
21
- activeDownloads.set(targetPath, downloadPromise);
22
- try {
23
- const savedPath = await downloadPromise;
24
- return `File downloaded successfully to: ${savedPath}`;
25
- }
26
- finally {
27
- activeDownloads.delete(targetPath);
28
- }
29
- }
30
- /**
31
- * Register the `zentao_download_attachment` MCP tool on the given server.
32
- *
33
- * @param server The MCP Server instance.
34
- * @param client Authenticated ZentaoClient used for downloading files.
35
- */
36
- export function registerDownloadTool(server, client) {
37
- server.registerTool("zentao_download_attachment", {
38
- description: "Download a file attachment from ZenTao and save it locally",
39
- inputSchema: {
40
- fileId: z.union([z.string(), z.number()]).describe("File ID to download"),
41
- extension: z.string().optional().describe("Optional file extension (e.g., mp4, png)"),
42
- },
43
- }, async ({ fileId, extension }) => {
44
- const ext = extension
45
- ? extension.startsWith('.') ? extension : `.${extension}`
46
- : '';
47
- const targetPath = path.join(os.tmpdir(), `zentao_file_${fileId}${ext}`);
48
- try {
49
- const message = await downloadAttachment(client, fileId, targetPath);
50
- return mcpText(message);
51
- }
52
- catch (error) {
53
- return mcpText(`Failed to download file: ${error.message}`);
54
- }
55
- });
56
- }
@@ -1,22 +0,0 @@
1
- import { z } from "zod";
2
- import { taskToMarkdown } from "../formatters/taskFormatter.js";
3
- import { buildMcpResponse } from "../utils/mcpResponse.js";
4
- /**
5
- * Register the `zentao_get_task_details` MCP tool on the given server.
6
- *
7
- * @param server The MCP Server instance.
8
- * @param client Authenticated ZentaoClient used to fetch and process data.
9
- */
10
- export function registerTaskTool(server, client) {
11
- server.registerTool("zentao_get_task_details", {
12
- description: "Get detailed information of a task",
13
- inputSchema: {
14
- taskId: z.union([z.string(), z.number()]).describe("Task ID"),
15
- },
16
- }, async ({ taskId }) => {
17
- const data = await client.getTaskDetails(taskId);
18
- const downloadedImages = [];
19
- const markdown = await taskToMarkdown(data, client, downloadedImages);
20
- return await buildMcpResponse(markdown, downloadedImages);
21
- });
22
- }