@leeguoo/zentao-mcp 0.3.0 → 0.3.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/README.md +2 -1
- package/package.json +1 -1
- package/src/index.js +53 -14
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ The MCP server provides four tools that can be triggered by natural language in
|
|
|
97
97
|
- **`zentao_products_list`** - List all products
|
|
98
98
|
- **`zentao_bugs_list`** - List bugs for a specific product
|
|
99
99
|
- **`zentao_bugs_stats`** - Get bug statistics across products
|
|
100
|
-
- **`zentao_bugs_mine`** - List my bugs by assignment or creator
|
|
100
|
+
- **`zentao_bugs_mine`** - List my bugs by assignment or creator (status filter supported)
|
|
101
101
|
|
|
102
102
|
### Usage Examples
|
|
103
103
|
|
|
@@ -157,6 +157,7 @@ The AI will automatically:
|
|
|
157
157
|
**zentao_bugs_mine:**
|
|
158
158
|
```json
|
|
159
159
|
{
|
|
160
|
+
"status": "active",
|
|
160
161
|
"scope": "assigned",
|
|
161
162
|
"includeZero": false,
|
|
162
163
|
"includeDetails": true,
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -50,10 +50,35 @@ function normalizeError(message, payload) {
|
|
|
50
50
|
return { status: 0, msg: message || "error", result: payload ?? [] };
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
function
|
|
53
|
+
function normalizeAccountValue(value) {
|
|
54
54
|
return String(value || "").trim().toLowerCase();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function extractAccounts(value) {
|
|
58
|
+
if (value === undefined || value === null) return [];
|
|
59
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
60
|
+
const normalized = normalizeAccountValue(value);
|
|
61
|
+
return normalized ? [normalized] : [];
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(value)) {
|
|
64
|
+
return value.flatMap((item) => extractAccounts(item));
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === "object") {
|
|
67
|
+
const candidates = [];
|
|
68
|
+
if (value.account) candidates.push(...extractAccounts(value.account));
|
|
69
|
+
if (value.realname) candidates.push(...extractAccounts(value.realname));
|
|
70
|
+
if (value.name) candidates.push(...extractAccounts(value.name));
|
|
71
|
+
if (value.user) candidates.push(...extractAccounts(value.user));
|
|
72
|
+
return candidates.filter(Boolean);
|
|
73
|
+
}
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function matchesAccount(value, matchAccount) {
|
|
78
|
+
const candidates = extractAccounts(value);
|
|
79
|
+
return candidates.includes(matchAccount);
|
|
80
|
+
}
|
|
81
|
+
|
|
57
82
|
class ZentaoClient {
|
|
58
83
|
constructor({ baseUrl, account, password }) {
|
|
59
84
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
@@ -234,14 +259,23 @@ class ZentaoClient {
|
|
|
234
259
|
async bugsMine({
|
|
235
260
|
account,
|
|
236
261
|
scope,
|
|
262
|
+
status,
|
|
237
263
|
productIds,
|
|
238
264
|
includeZero,
|
|
239
265
|
perPage,
|
|
240
266
|
maxItems,
|
|
241
267
|
includeDetails,
|
|
242
268
|
}) {
|
|
243
|
-
const matchAccount =
|
|
269
|
+
const matchAccount = normalizeAccountValue(account || this.account);
|
|
244
270
|
const targetScope = (scope || "assigned").toLowerCase();
|
|
271
|
+
const rawStatus = status ?? "active";
|
|
272
|
+
const statusList = Array.isArray(rawStatus)
|
|
273
|
+
? rawStatus
|
|
274
|
+
: String(rawStatus).split(/[|,]/);
|
|
275
|
+
const statusSet = new Set(
|
|
276
|
+
statusList.map((item) => String(item).trim().toLowerCase()).filter(Boolean)
|
|
277
|
+
);
|
|
278
|
+
const allowAllStatus = statusSet.has("all") || statusSet.size === 0;
|
|
245
279
|
|
|
246
280
|
const productsResponse = await this.listProducts({ page: 1, limit: 1000 });
|
|
247
281
|
if (productsResponse.status !== 1) return productsResponse;
|
|
@@ -264,17 +298,17 @@ class ZentaoClient {
|
|
|
264
298
|
});
|
|
265
299
|
|
|
266
300
|
const matches = productBugs.filter((bug) => {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
301
|
+
if (!allowAllStatus) {
|
|
302
|
+
const bugStatus = String(bug.status || "").trim().toLowerCase();
|
|
303
|
+
if (!statusSet.has(bugStatus)) return false;
|
|
304
|
+
}
|
|
305
|
+
const assigned = matchesAccount(bug.assignedTo, matchAccount);
|
|
306
|
+
const opened = matchesAccount(bug.openedBy, matchAccount);
|
|
307
|
+
const resolved = matchesAccount(bug.resolvedBy, matchAccount);
|
|
308
|
+
if (targetScope === "assigned") return assigned;
|
|
309
|
+
if (targetScope === "opened") return opened;
|
|
310
|
+
if (targetScope === "resolved") return resolved;
|
|
311
|
+
return assigned || opened || resolved;
|
|
278
312
|
});
|
|
279
313
|
|
|
280
314
|
if (!includeZero && matches.length === 0) continue;
|
|
@@ -309,6 +343,7 @@ class ZentaoClient {
|
|
|
309
343
|
return normalizeResult({
|
|
310
344
|
account: matchAccount,
|
|
311
345
|
scope: targetScope,
|
|
346
|
+
status: allowAllStatus ? "all" : Array.from(statusSet),
|
|
312
347
|
total: totalMatches,
|
|
313
348
|
products: rows,
|
|
314
349
|
bugs: includeDetails ? bugs : [],
|
|
@@ -337,7 +372,7 @@ function getClient() {
|
|
|
337
372
|
const server = new Server(
|
|
338
373
|
{
|
|
339
374
|
name: "zentao-mcp",
|
|
340
|
-
version: "0.
|
|
375
|
+
version: "0.3.2",
|
|
341
376
|
},
|
|
342
377
|
{
|
|
343
378
|
capabilities: {
|
|
@@ -396,6 +431,10 @@ const tools = [
|
|
|
396
431
|
type: "string",
|
|
397
432
|
description: "Filter scope: assigned|opened|resolved|all (default assigned).",
|
|
398
433
|
},
|
|
434
|
+
status: {
|
|
435
|
+
type: ["string", "array"],
|
|
436
|
+
description: "Status filter: active|resolved|closed|all (default active).",
|
|
437
|
+
},
|
|
399
438
|
productIds: {
|
|
400
439
|
type: "array",
|
|
401
440
|
items: { type: "integer" },
|