@aipper/zentao-mcp-server 0.1.12 → 0.1.14
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/.env.example +3 -0
- package/package.json +1 -1
- package/src/index.js +7 -3
- package/src/tools.js +16 -0
- package/src/zentao.js +43 -1
package/.env.example
CHANGED
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -82,6 +82,7 @@ function getConfigFromEnv() {
|
|
|
82
82
|
const timeoutMs = Number(process.env.ZENTAO_HTTP_TIMEOUT_MS || "30000");
|
|
83
83
|
const defaultProductId = Number(process.env.ZENTAO_PRODUCT_ID || "0") || null;
|
|
84
84
|
const defaultProjectSetId = Number(process.env.ZENTAO_PROJECT_SET_ID || "0") || null;
|
|
85
|
+
const defaultProjectId = Number(process.env.ZENTAO_PROJECT_ID || "0") || null;
|
|
85
86
|
const myBugsPath = String(process.env.ZENTAO_MY_BUGS_PATH || "").trim();
|
|
86
87
|
const bugsFallbackPaths = String(process.env.ZENTAO_BUGS_FALLBACK_PATHS || "")
|
|
87
88
|
.split(",")
|
|
@@ -104,6 +105,7 @@ function getConfigFromEnv() {
|
|
|
104
105
|
allowInsecureHttp: ALLOW_INSECURE_HTTP,
|
|
105
106
|
defaultProductId,
|
|
106
107
|
defaultProjectSetId,
|
|
108
|
+
defaultProjectId,
|
|
107
109
|
myBugsPath,
|
|
108
110
|
bugsFallbackPaths,
|
|
109
111
|
projectSetBugsPaths,
|
|
@@ -162,6 +164,7 @@ async function main() {
|
|
|
162
164
|
limit: args.limit,
|
|
163
165
|
page: args.page,
|
|
164
166
|
productId: args.productId,
|
|
167
|
+
projectId: args.projectId,
|
|
165
168
|
projectSetId: args.projectSetId,
|
|
166
169
|
path: args.path || "/bugs",
|
|
167
170
|
});
|
|
@@ -192,6 +195,7 @@ async function main() {
|
|
|
192
195
|
limit: args.limit,
|
|
193
196
|
page: args.page,
|
|
194
197
|
productId: args.productId,
|
|
198
|
+
projectId: args.projectId,
|
|
195
199
|
projectSetId: args.projectSetId,
|
|
196
200
|
maxItems: args.maxItems,
|
|
197
201
|
resolution: args.resolution || "fixed",
|
|
@@ -236,9 +240,9 @@ async function main() {
|
|
|
236
240
|
ok: false,
|
|
237
241
|
tool: rawToolName,
|
|
238
242
|
message: String(err?.message || err),
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
status: err?.status ?? null,
|
|
244
|
+
hint: "If you see 'Need product id', set env ZENTAO_PRODUCT_ID or pass productId in get_my_bugs. For project-scoped bugs, set ZENTAO_PROJECT_ID or pass projectId.",
|
|
245
|
+
hint2: "For project-set instances, prefer get_my_bugs with projectSetId or ZENTAO_MY_BUGS_PATH=/my/bug; list_my_projects may miss project sets without concrete projects.",
|
|
242
246
|
};
|
|
243
247
|
return toMcpTextResult(JSON.stringify(errorPayload, null, 2), { isError: true });
|
|
244
248
|
}
|
package/src/tools.js
CHANGED
|
@@ -41,6 +41,11 @@ export const TOOLS = [
|
|
|
41
41
|
limit: { type: "number", minimum: 1, maximum: 200, description: "Default 20, max 200" },
|
|
42
42
|
page: { type: "number", minimum: 1, description: "Default 1" },
|
|
43
43
|
productId: { type: "number", minimum: 1, description: "Optional product id (for instances requiring product scope)" },
|
|
44
|
+
projectId: {
|
|
45
|
+
type: "number",
|
|
46
|
+
minimum: 1,
|
|
47
|
+
description: "Optional project id. Directly query /projects/{id}/bugs, no cross-project merge.",
|
|
48
|
+
},
|
|
44
49
|
projectSetId: {
|
|
45
50
|
type: "number",
|
|
46
51
|
minimum: 1,
|
|
@@ -100,6 +105,11 @@ export const TOOLS = [
|
|
|
100
105
|
limit: { type: "number", minimum: 1, maximum: 200, description: "List page size, default 50" },
|
|
101
106
|
page: { type: "number", minimum: 1, description: "Default 1" },
|
|
102
107
|
productId: { type: "number", minimum: 1, description: "Optional product id (for instances requiring product scope)" },
|
|
108
|
+
projectId: {
|
|
109
|
+
type: "number",
|
|
110
|
+
minimum: 1,
|
|
111
|
+
description: "Optional project id. Directly query /projects/{id}/bugs, no cross-project merge.",
|
|
112
|
+
},
|
|
103
113
|
projectSetId: {
|
|
104
114
|
type: "number",
|
|
105
115
|
minimum: 1,
|
|
@@ -196,6 +206,9 @@ export function assertToolArgs(name, args) {
|
|
|
196
206
|
if (args.projectSetId !== undefined && (!Number.isFinite(args.projectSetId) || args.projectSetId < 1)) {
|
|
197
207
|
throw new Error("get_my_bugs.projectSetId must be a number >= 1");
|
|
198
208
|
}
|
|
209
|
+
if (args.projectId !== undefined && (!Number.isFinite(args.projectId) || args.projectId < 1)) {
|
|
210
|
+
throw new Error("get_my_bugs.projectId must be a number >= 1");
|
|
211
|
+
}
|
|
199
212
|
}
|
|
200
213
|
if (name === "get_bug_detail") {
|
|
201
214
|
if (!Number.isFinite(args.id) || Number(args.id) < 1) {
|
|
@@ -232,6 +245,9 @@ export function assertToolArgs(name, args) {
|
|
|
232
245
|
if (args.projectSetId !== undefined && (!Number.isFinite(args.projectSetId) || args.projectSetId < 1)) {
|
|
233
246
|
throw new Error("batch_resolve_my_bugs.projectSetId must be a number >= 1");
|
|
234
247
|
}
|
|
248
|
+
if (args.projectId !== undefined && (!Number.isFinite(args.projectId) || args.projectId < 1)) {
|
|
249
|
+
throw new Error("batch_resolve_my_bugs.projectId must be a number >= 1");
|
|
250
|
+
}
|
|
235
251
|
if (args.path !== undefined) {
|
|
236
252
|
if (typeof args.path !== "string") throw new Error("batch_resolve_my_bugs.path must be a string");
|
|
237
253
|
if (!SAFE_BUG_LIST_PATHS.has(args.path)) {
|
package/src/zentao.js
CHANGED
|
@@ -95,6 +95,7 @@ function createAbortSignal(timeoutMs) {
|
|
|
95
95
|
* @param {number} config.timeoutMs - Request timeout in milliseconds
|
|
96
96
|
* @param {number} [config.defaultProductId] - Default product ID
|
|
97
97
|
* @param {number} [config.defaultProjectSetId] - Default project set ID
|
|
98
|
+
* @param {number} [config.defaultProjectId] - Default project ID
|
|
98
99
|
* @param {string} [config.myBugsPath] - My bugs path
|
|
99
100
|
* @param {string[]} [config.bugsFallbackPaths] - Bug fallback paths
|
|
100
101
|
* @param {string[]} [config.projectSetBugsPaths] - Project set bug paths
|
|
@@ -113,6 +114,7 @@ export function createZenTaoClient(config) {
|
|
|
113
114
|
allowInsecureHttp,
|
|
114
115
|
defaultProductId,
|
|
115
116
|
defaultProjectSetId,
|
|
117
|
+
defaultProjectId,
|
|
116
118
|
myBugsPath,
|
|
117
119
|
bugsFallbackPaths,
|
|
118
120
|
projectSetBugsPaths,
|
|
@@ -515,7 +517,9 @@ export function createZenTaoClient(config) {
|
|
|
515
517
|
: cleaned.startsWith("//")
|
|
516
518
|
? new URL(`${baseProtocol}${cleaned}`)
|
|
517
519
|
: cleaned.startsWith("/")
|
|
518
|
-
?
|
|
520
|
+
? (cleaned.includes("?") || cleaned.includes("#"))
|
|
521
|
+
? new URL(cleaned.replace(/^\//, ""), deploymentBaseUrl)
|
|
522
|
+
: resolveAgainstDeploymentPath(cleaned)
|
|
519
523
|
: resolveAgainstDeploymentPath(`/${cleaned.replace(/^\.?\//, "")}`);
|
|
520
524
|
if (candidate.origin !== baseOrigin) return "";
|
|
521
525
|
return candidate.toString();
|
|
@@ -748,6 +752,7 @@ export function createZenTaoClient(config) {
|
|
|
748
752
|
limit = 20,
|
|
749
753
|
page = 1,
|
|
750
754
|
productId,
|
|
755
|
+
projectId,
|
|
751
756
|
projectSetId,
|
|
752
757
|
path = "/bugs",
|
|
753
758
|
} = {}) {
|
|
@@ -755,6 +760,41 @@ export function createZenTaoClient(config) {
|
|
|
755
760
|
const safePage = Math.max(1, Number(page) || 1);
|
|
756
761
|
const dashboardScanLimit = Math.max(safeLimit, 100);
|
|
757
762
|
const assignee = normalizeString(auth.account);
|
|
763
|
+
const effectiveProjectId = normalizePositiveInt(projectId) || normalizePositiveInt(defaultProjectId);
|
|
764
|
+
|
|
765
|
+
if (effectiveProjectId) {
|
|
766
|
+
const query = { limit: safeLimit, page: safePage, assignedTo: assignee, status: status || undefined };
|
|
767
|
+
try {
|
|
768
|
+
const resp = await call({ path: `/projects/${effectiveProjectId}/bugs`, method: "GET", query });
|
|
769
|
+
const bugs = parseBugsFromResponse(resp?.data);
|
|
770
|
+
const filtered = bugs.filter((bug) => matchesBugFilters(bug, { status, keyword, assignee }));
|
|
771
|
+
return {
|
|
772
|
+
total: filtered.length,
|
|
773
|
+
matched: filtered.length,
|
|
774
|
+
page: safePage,
|
|
775
|
+
limit: safeLimit,
|
|
776
|
+
projectId: effectiveProjectId,
|
|
777
|
+
assignedTo: assignee,
|
|
778
|
+
bugs: filtered,
|
|
779
|
+
raw: {
|
|
780
|
+
status: resp?.status ?? null,
|
|
781
|
+
path: `/projects/${effectiveProjectId}/bugs`,
|
|
782
|
+
triedPaths: [{
|
|
783
|
+
path: `/projects/${effectiveProjectId}/bugs`,
|
|
784
|
+
status: resp?.status ?? null,
|
|
785
|
+
total: bugs.length,
|
|
786
|
+
matched: filtered.length,
|
|
787
|
+
}],
|
|
788
|
+
scannedTotal: bugs.length,
|
|
789
|
+
paths: [{ path: `/projects/${effectiveProjectId}/bugs`, status: resp?.status ?? null, total: bugs.length, matched: filtered.length }],
|
|
790
|
+
merged: false,
|
|
791
|
+
},
|
|
792
|
+
};
|
|
793
|
+
} catch (err) {
|
|
794
|
+
throw err;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
758
798
|
const effectiveProductId = normalizePositiveInt(productId) || normalizePositiveInt(defaultProductId);
|
|
759
799
|
const effectiveProjectSetId = normalizePositiveInt(projectSetId) || normalizePositiveInt(defaultProjectSetId);
|
|
760
800
|
const requestedPath = normalizeBugsListPath(path);
|
|
@@ -1287,6 +1327,7 @@ export function createZenTaoClient(config) {
|
|
|
1287
1327
|
limit = 50,
|
|
1288
1328
|
page = 1,
|
|
1289
1329
|
productId,
|
|
1330
|
+
projectId,
|
|
1290
1331
|
projectSetId,
|
|
1291
1332
|
maxItems = 20,
|
|
1292
1333
|
resolution = "fixed",
|
|
@@ -1302,6 +1343,7 @@ export function createZenTaoClient(config) {
|
|
|
1302
1343
|
limit,
|
|
1303
1344
|
page,
|
|
1304
1345
|
productId,
|
|
1346
|
+
projectId,
|
|
1305
1347
|
projectSetId,
|
|
1306
1348
|
path,
|
|
1307
1349
|
});
|