@dyno181cm.nexsoft/zentao_mcp 1.2.2 → 1.2.3

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/build/tools.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import * as os from "os";
3
3
  import * as path from "path";
4
+ import fs from "fs";
4
5
  import { ZentaoClient } from "./zentaoClient.js";
5
6
  const client = new ZentaoClient();
7
+ const activeDownloads = new Map();
6
8
  /**
7
9
  * Registers Zentao-specific tools to the Model Context Protocol (MCP) server.
8
10
  *
@@ -129,10 +131,31 @@ export function registerTools(server) {
129
131
  const ext = extension ? (extension.startsWith('.') ? extension : `.${extension}`) : '';
130
132
  const targetPath = path.join(os.tmpdir(), `zentao_file_${fileId}${ext}`);
131
133
  try {
132
- const savedPath = await client.downloadFile(fileId, targetPath);
133
- return {
134
- content: [{ type: "text", text: `File downloaded successfully to: ${savedPath}` }],
135
- };
134
+ // If it already exists on disk and is not currently being downloaded
135
+ if (fs.existsSync(targetPath) && !activeDownloads.has(targetPath)) {
136
+ return {
137
+ content: [{ type: "text", text: `File already exists locally at: ${targetPath}` }],
138
+ };
139
+ }
140
+ // If it is currently being downloaded, await the active promise
141
+ if (activeDownloads.has(targetPath)) {
142
+ await activeDownloads.get(targetPath);
143
+ return {
144
+ content: [{ type: "text", text: `File downloaded successfully to: ${targetPath}` }],
145
+ };
146
+ }
147
+ // Start new download and track it
148
+ const downloadPromise = client.downloadFile(fileId, targetPath);
149
+ activeDownloads.set(targetPath, downloadPromise);
150
+ try {
151
+ const savedPath = await downloadPromise;
152
+ return {
153
+ content: [{ type: "text", text: `File downloaded successfully to: ${savedPath}` }],
154
+ };
155
+ }
156
+ finally {
157
+ activeDownloads.delete(targetPath);
158
+ }
136
159
  }
137
160
  catch (error) {
138
161
  return {
@@ -84,24 +84,18 @@ export class ZentaoClient {
84
84
  * @throws {Error} If account/password env vars are missing or if the API request fails.
85
85
  */
86
86
  async login() {
87
- try {
88
- if (!this.account || !this.password) {
89
- throw new Error('ZENTAO_ACCOUNT or ZENTAO_PASSWORD is not set in environment variables');
90
- }
91
- const response = await this.client.post('/tokens', {
92
- account: this.account,
93
- password: this.password,
94
- });
95
- if (response.data && response.data.token) {
96
- this.token = response.data.token;
97
- }
98
- else {
99
- throw new Error('Login failed: Token not found in response');
100
- }
87
+ if (!this.account || !this.password) {
88
+ throw new Error('ZENTAO_ACCOUNT or ZENTAO_PASSWORD is not set in environment variables');
89
+ }
90
+ const response = await this.client.post('/tokens', {
91
+ account: this.account,
92
+ password: this.password,
93
+ });
94
+ if (response.data && response.data.token) {
95
+ this.token = response.data.token;
101
96
  }
102
- catch (error) {
103
- console.error('Failed to login to Zentao:', error.message);
104
- throw error;
97
+ else {
98
+ throw new Error('Login failed: Token not found in response');
105
99
  }
106
100
  }
107
101
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyno181cm.nexsoft/zentao_mcp",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Zentao MCP Server",
5
5
  "repository": {
6
6
  "type": "git",