@dyno181cm.nexsoft/zentao_mcp 1.5.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 +36 -28
- package/build/formatters/myWorkFormatter.js +55 -0
- package/build/tools/detailTool.js +32 -0
- package/build/tools/myWorkTool.js +18 -0
- package/build/tools.js +5 -9
- package/build/zentaoClient.js +14 -0
- package/package.json +1 -1
- package/build/tools/bugTool.js +0 -22
- package/build/tools/downloadTool.js +0 -56
- package/build/tools/taskTool.js +0 -22
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
[](https://www.typescriptlang.org)
|
|
9
9
|
[](https://modelcontextprotocol.io)
|
|
10
|
+
[](https://github.com/dyno-nexsoft/zentao_mcp/tree/master/tests)
|
|
10
11
|
|
|
11
12
|
A **Model Context Protocol (MCP)** server for integrating AI assistants (Claude, Cursor, etc.) with the [ZenTao](https://www.zentao.net) project management API.
|
|
12
13
|
Fetch task details, bug reports, and attachments — all directly inside your AI chat.
|
|
@@ -17,20 +18,22 @@ Fetch task details, bug reports, and attachments — all directly inside your AI
|
|
|
17
18
|
|
|
18
19
|
| Tool | Description |
|
|
19
20
|
|---|---|
|
|
20
|
-
| `
|
|
21
|
-
| `zentao_get_bug_details` | Fetch full details of a bug by ID (severity, repro steps, history & comments, inline images, attachments) |
|
|
22
|
-
| `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 |
|
|
23
22
|
| `zentao_get_comments` | Fetch only the history and comments timeline of a task or bug |
|
|
23
|
+
| `zentao_add_comment` | Add a comment/remark to a task or bug |
|
|
24
24
|
| `zentao_update_task_status` | Update task status (start, finish, close, pause, cancel, restart) and add optional comments/hours |
|
|
25
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`) |
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
**Under the hood:**
|
|
29
30
|
- 🔐 Auto login & token refresh — no manual auth needed
|
|
30
31
|
- 📦 In-memory cache (2 min TTL) + in-flight request dedup — avoids redundant API calls
|
|
32
|
+
- 🔁 Classic JSON API fallback — seamlessly retries via the web API when the REST endpoint returns empty or errors
|
|
31
33
|
- 🖼️ Inline HTML images are automatically downloaded and served as local `file://` links
|
|
32
34
|
- 📎 Attachments are downloaded and embedded as clickable local links
|
|
33
35
|
- 🛡️ Corrupt partial downloads are auto-cleaned on error
|
|
36
|
+
- ⚡ Non-blocking async image I/O — base64 encoding uses `fs.promises` + `Promise.all`
|
|
34
37
|
|
|
35
38
|
---
|
|
36
39
|
|
|
@@ -100,35 +103,30 @@ Add to your MCP client config (e.g. `claude_desktop_config.json`):
|
|
|
100
103
|
|
|
101
104
|
## 🛠️ Available Tools
|
|
102
105
|
|
|
103
|
-
### `
|
|
104
|
-
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.
|
|
105
108
|
|
|
106
109
|
| Parameter | Type | Required | Description |
|
|
107
110
|
|---|---|---|---|
|
|
108
|
-
| `
|
|
109
|
-
|
|
110
|
-
### `zentao_get_bug_details`
|
|
111
|
-
Get full details of a ZenTao bug, including repro steps and inline images.
|
|
112
|
-
|
|
113
|
-
| Parameter | Type | Required | Description |
|
|
114
|
-
|---|---|---|---|
|
|
115
|
-
| `bugId` | `string \| number` | ✅ | Bug ID |
|
|
111
|
+
| `type` | `"task" \| "bug"` | ✅ | Type of the object |
|
|
112
|
+
| `id` | `string \| number` | ✅ | Task or Bug ID |
|
|
116
113
|
|
|
117
|
-
### `
|
|
118
|
-
|
|
114
|
+
### `zentao_get_comments`
|
|
115
|
+
Get only the history and comments timeline of a task or bug.
|
|
119
116
|
|
|
120
117
|
| Parameter | Type | Required | Description |
|
|
121
118
|
|---|---|---|---|
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
119
|
+
| `type` | `"task" \| "bug"` | ✅ | Type of the object |
|
|
120
|
+
| `id` | `string \| number` | ✅ | Task or Bug ID |
|
|
124
121
|
|
|
125
|
-
### `
|
|
126
|
-
|
|
122
|
+
### `zentao_add_comment`
|
|
123
|
+
Add a comment/remark to a task or bug.
|
|
127
124
|
|
|
128
125
|
| Parameter | Type | Required | Description |
|
|
129
126
|
|---|---|---|---|
|
|
130
127
|
| `type` | `"task" \| "bug"` | ✅ | Type of the object |
|
|
131
128
|
| `id` | `string \| number` | ✅ | Task or Bug ID |
|
|
129
|
+
| `comment` | `string` | ✅ | Comment content |
|
|
132
130
|
|
|
133
131
|
### `zentao_update_task_status`
|
|
134
132
|
Update a task's status with optional comments, actual start/finish dates, and consumed hours.
|
|
@@ -158,6 +156,9 @@ Update a bug's status with optional comments and resolutions.
|
|
|
158
156
|
| `assignedTo` | `string` | ❌ | Optional user account to assign to next |
|
|
159
157
|
| `openedBuild` | `string` | ❌ | Optional build ID where bug was found (for `activate`) |
|
|
160
158
|
|
|
159
|
+
### `zentao_get_assigned_to_me`
|
|
160
|
+
Get tasks and bugs currently assigned to the configured user account. Takes no arguments.
|
|
161
|
+
|
|
161
162
|
---
|
|
162
163
|
|
|
163
164
|
## 🧑💻 Development
|
|
@@ -174,24 +175,31 @@ npm run test:api # Live API integration test
|
|
|
174
175
|
```
|
|
175
176
|
src/
|
|
176
177
|
├── index.ts # MCP server entry point
|
|
177
|
-
├── zentaoClient.ts # Axios client: auth, cache, dedup,
|
|
178
|
+
├── zentaoClient.ts # Axios client: auth, cache, dedup, fallback, stream helpers
|
|
178
179
|
├── tools.ts # Thin orchestrator + backward-compat exports
|
|
179
180
|
├── utils/
|
|
180
181
|
│ ├── fileUtils.ts # toFileUrl · getMimeType · formatSize
|
|
181
182
|
│ ├── markdownUtils.ts # htmlToMarkdown · parseFiles · formatUser
|
|
182
|
-
│ └── mcpResponse.ts # mcpText · buildMcpResponse
|
|
183
|
+
│ └── mcpResponse.ts # mcpText · buildMcpResponse (async)
|
|
183
184
|
├── formatters/
|
|
184
|
-
│ ├── imageLocalizer.ts # Inline <img> → local file:// link
|
|
185
|
+
│ ├── imageLocalizer.ts # Inline <img> → local file:// link (deduped, concurrent)
|
|
185
186
|
│ ├── attachmentRenderer.ts # Attachments → Markdown ## Files section
|
|
186
187
|
│ ├── actionFormatter.ts # renderHistoryAndComments
|
|
187
188
|
│ ├── taskFormatter.ts # taskToMarkdown (includes comments)
|
|
188
|
-
│
|
|
189
|
+
│ ├── bugFormatter.ts # bugToMarkdown (includes comments)
|
|
190
|
+
│ └── myWorkFormatter.ts # myWorkToMarkdown (includes comments)
|
|
189
191
|
└── tools/
|
|
190
|
-
├──
|
|
191
|
-
├──
|
|
192
|
-
├──
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
├── detailTool.ts # zentao_get_details
|
|
193
|
+
├── commentTool.ts # zentao_get_comments · zentao_add_comment
|
|
194
|
+
├── statusTool.ts # zentao_update_task_status · zentao_update_bug_status
|
|
195
|
+
└── myWorkTool.ts # zentao_get_assigned_to_me
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Running tests
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm test # Unit tests — 13 tests across ZentaoClient
|
|
202
|
+
npm run test:api # Live API integration test (requires .env)
|
|
195
203
|
```
|
|
196
204
|
|
|
197
205
|
---
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a raw ZenTao "my work" response object into a human-readable Markdown document.
|
|
3
|
+
*
|
|
4
|
+
* @param myWork The raw "my work" object containing profile, task, and bug lists.
|
|
5
|
+
* @param client Authenticated ZentaoClient to get baseUrl for linking.
|
|
6
|
+
*/
|
|
7
|
+
export function myWorkToMarkdown(myWork, client) {
|
|
8
|
+
if (!myWork)
|
|
9
|
+
return "No work items found.";
|
|
10
|
+
const profile = myWork.profile || {};
|
|
11
|
+
const taskData = myWork.task || { total: 0, tasks: [] };
|
|
12
|
+
const bugData = myWork.bug || { total: 0, bugs: [] };
|
|
13
|
+
const webUrl = client.webUrl || "";
|
|
14
|
+
const header = [
|
|
15
|
+
`# Work Items Assigned to ${profile.realname || profile.account || "Me"}`,
|
|
16
|
+
`- **Account:** ${profile.account || "N/A"}`,
|
|
17
|
+
`- **Role:** ${profile.role?.name || "N/A"}`,
|
|
18
|
+
`- **Total Tasks:** ${taskData.total}`,
|
|
19
|
+
`- **Total Bugs:** ${bugData.total}`,
|
|
20
|
+
""
|
|
21
|
+
];
|
|
22
|
+
const sections = [...header];
|
|
23
|
+
// ── Tasks Section ──
|
|
24
|
+
sections.push("## Tasks Assigned to Me");
|
|
25
|
+
if (taskData.total === 0 || !taskData.tasks || taskData.tasks.length === 0) {
|
|
26
|
+
sections.push("*No tasks assigned to you.*", "");
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
sections.push("| ID | Task Name | Pri | Status | Execution | Deadline | Progress |", "| :--- | :--- | :---: | :---: | :--- | :---: | :---: |");
|
|
30
|
+
for (const t of taskData.tasks) {
|
|
31
|
+
const taskLink = webUrl ? `[${t.id}](${webUrl}/task-view-${t.id}.html)` : `${t.id}`;
|
|
32
|
+
const execution = t.executionName || "N/A";
|
|
33
|
+
const prog = t.progress ?? 0;
|
|
34
|
+
const deadline = t.deadline || "N/A";
|
|
35
|
+
sections.push(`| ${taskLink} | ${t.name} | ${t.pri} | ${t.status} | ${execution} | ${deadline} | ${prog}% |`);
|
|
36
|
+
}
|
|
37
|
+
sections.push("");
|
|
38
|
+
}
|
|
39
|
+
// ── Bugs Section ──
|
|
40
|
+
sections.push("## Bugs Assigned to Me");
|
|
41
|
+
if (bugData.total === 0 || !bugData.bugs || bugData.bugs.length === 0) {
|
|
42
|
+
sections.push("*No bugs assigned to you.*", "");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
sections.push("| ID | Bug Title | Pri | Status | Product | Deadline |", "| :--- | :--- | :---: | :---: | :--- | :---: |");
|
|
46
|
+
for (const b of bugData.bugs) {
|
|
47
|
+
const bugLink = webUrl ? `[${b.id}](${webUrl}/bug-view-${b.id}.html)` : `${b.id}`;
|
|
48
|
+
const product = b.productName || "N/A";
|
|
49
|
+
const deadline = b.deadline || "N/A";
|
|
50
|
+
sections.push(`| ${bugLink} | ${b.title} | ${b.pri} | ${b.status} | ${product} | ${deadline} |`);
|
|
51
|
+
}
|
|
52
|
+
sections.push("");
|
|
53
|
+
}
|
|
54
|
+
return sections.join("\n");
|
|
55
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { myWorkToMarkdown } from "../formatters/myWorkFormatter.js";
|
|
2
|
+
import { mcpText } from "../utils/mcpResponse.js";
|
|
3
|
+
/**
|
|
4
|
+
* Register the `zentao_get_assigned_to_me` MCP tool on the given server.
|
|
5
|
+
*
|
|
6
|
+
* @param server The MCP Server instance.
|
|
7
|
+
* @param client Authenticated ZentaoClient used to fetch and process data.
|
|
8
|
+
*/
|
|
9
|
+
export function registerMyWorkTool(server, client) {
|
|
10
|
+
server.registerTool("zentao_get_assigned_to_me", {
|
|
11
|
+
description: "Get tasks and bugs assigned to the current user (configured in environment variables)",
|
|
12
|
+
inputSchema: {},
|
|
13
|
+
}, async () => {
|
|
14
|
+
const data = await client.getMyWork();
|
|
15
|
+
const markdown = myWorkToMarkdown(data, client);
|
|
16
|
+
return mcpText(markdown);
|
|
17
|
+
});
|
|
18
|
+
}
|
package/build/tools.js
CHANGED
|
@@ -13,11 +13,10 @@
|
|
|
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 {
|
|
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";
|
|
19
|
+
import { registerMyWorkTool } from "./tools/myWorkTool.js";
|
|
21
20
|
// ─── Shared singleton ────────────────────────────────────────────────────────
|
|
22
21
|
const client = new ZentaoClient();
|
|
23
22
|
// ─── Backward-compatible re-exports ──────────────────────────────────────────
|
|
@@ -36,9 +35,7 @@ export function bugToMarkdown(rawBug, downloadedImages) {
|
|
|
36
35
|
* Registers all Zentao MCP tools on the provided server instance.
|
|
37
36
|
*
|
|
38
37
|
* Available tools:
|
|
39
|
-
* - `
|
|
40
|
-
* - `zentao_get_bug_details` — Fetch full details of a bug by ID.
|
|
41
|
-
* - `zentao_download_attachment` — Download an attachment and save locally.
|
|
38
|
+
* - `zentao_get_details` — Fetch full details of a task or a bug by ID.
|
|
42
39
|
* - `zentao_get_comments` — Fetch history and comments timeline for task/bug.
|
|
43
40
|
* - `zentao_update_task_status` — Update a task's status with comments.
|
|
44
41
|
* - `zentao_update_bug_status` — Update a bug's status with comments.
|
|
@@ -46,9 +43,8 @@ export function bugToMarkdown(rawBug, downloadedImages) {
|
|
|
46
43
|
* @param server The MCP Server instance where the tools will be registered.
|
|
47
44
|
*/
|
|
48
45
|
export function registerTools(server) {
|
|
49
|
-
|
|
50
|
-
registerBugTool(server, client);
|
|
51
|
-
registerDownloadTool(server, client);
|
|
46
|
+
registerDetailTool(server, client);
|
|
52
47
|
registerCommentTool(server, client);
|
|
53
48
|
registerStatusTools(server, client);
|
|
49
|
+
registerMyWorkTool(server, client);
|
|
54
50
|
}
|
package/build/zentaoClient.js
CHANGED
|
@@ -52,6 +52,12 @@ export class ZentaoClient {
|
|
|
52
52
|
}
|
|
53
53
|
return this.baseUrl.split('/api/v1')[0];
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Public getter exposing the web base URL.
|
|
57
|
+
*/
|
|
58
|
+
get webUrl() {
|
|
59
|
+
return this.webBaseUrl;
|
|
60
|
+
}
|
|
55
61
|
// ─── Cache helpers ────────────────────────────────────────────────────────────
|
|
56
62
|
/**
|
|
57
63
|
* Clears the in-memory cache for GET requests. Helpful for testing.
|
|
@@ -304,6 +310,14 @@ export class ZentaoClient {
|
|
|
304
310
|
});
|
|
305
311
|
}
|
|
306
312
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
313
|
+
/**
|
|
314
|
+
* Retrieves tasks and bugs assigned to the current user (my work).
|
|
315
|
+
*
|
|
316
|
+
* @returns Resolves with the user's work items (tasks and bugs).
|
|
317
|
+
*/
|
|
318
|
+
async getMyWork() {
|
|
319
|
+
return this.get('/user?fields=task,bug&type=assignedTo');
|
|
320
|
+
}
|
|
307
321
|
/**
|
|
308
322
|
* Retrieves details of a specific task.
|
|
309
323
|
* Checks the cache first, otherwise fetches from API.
|
package/package.json
CHANGED
package/build/tools/bugTool.js
DELETED
|
@@ -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
|
-
}
|
package/build/tools/taskTool.js
DELETED
|
@@ -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
|
-
}
|