@bangdao-ai/zentao-mcp 1.1.1 → 1.1.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/README.md CHANGED
@@ -139,11 +139,12 @@ pip3 install -r requirements.txt
139
139
  "@bangdao-ai/zentao-mcp@latest"
140
140
  ],
141
141
  "env": {
142
- "ZENTAO_PRODUCT_ID": "365",
143
- "ZENTAO_OPENED_BY": "69610",
144
- "KEY": "643f0f490d1ea0d47520dd270989c99a",
142
+ "ZENTAO_PRODUCT_ID": "your-product-id",
143
+ "ZENTAO_OPENED_BY": "your-user-id",
144
+ "KEY": "your-api-key",
145
145
  "ZENTAO_KEYWORDS": "AI",
146
- "ZENTAO_TITLE_PREFIX": ""
146
+ "ZENTAO_TITLE_PREFIX": "",
147
+ "ZENTAO_ROLE_TYPE": "test"
147
148
  }
148
149
  }
149
150
  }
@@ -156,6 +157,7 @@ pip3 install -r requirements.txt
156
157
  - `KEY`(必需):API认证密钥,作为API认证的key参数
157
158
  - `ZENTAO_KEYWORDS`(可选):关键词,默认为空
158
159
  - `ZENTAO_TITLE_PREFIX`(可选):标题前缀,默认为空
160
+ - `ZENTAO_ROLE_TYPE`(可选):角色类型,默认为"test"
159
161
 
160
162
  ### 兜底配置(可选)
161
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bangdao-ai/zentao-mcp",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "禅道Bug管理系统MCP工具",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -30,5 +30,8 @@
30
30
  "repository": {
31
31
  "type": "git",
32
32
  "url": "git+https://github.com/bangdao-ai/zentao-mcp.git"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
33
36
  }
34
37
  }
@@ -167,67 +167,68 @@ class ZenTaoAPIClient:
167
167
  'User-Agent': 'Python-ZenTao-Client/1.0'
168
168
  }
169
169
 
170
- # 打印请求信息
171
- print("\n" + "=" * 80)
172
- print("【禅道API请求信息】")
173
- print("=" * 80)
174
- print(f"API URL: {api_url}")
175
- print(f"\n【Headers】")
176
- for key, value in headers.items():
177
- print(f" {key}: {value}")
178
-
179
- print(f"\n【Token生成信息】")
180
- print(f" code: {self.code}")
181
- print(f" key: {self.key[:10]}...{self.key[-10:] if len(self.key) > 20 else self.key}") # 只显示部分key,保护隐私
182
- print(f" time: {current_timestamp}")
183
- print(f" token生成公式: md5(code + key + time)")
184
- print(f" token生成字符串: {self.code}{self.key}{current_timestamp}")
185
- print(f" token: {token}")
186
-
187
- print(f"\n【URL参数】")
188
- for key, value in url_params.items():
189
- print(f" {key}: {value}")
190
-
191
- # 处理form_data用于显示
192
- display_form_data = form_data
193
- if isinstance(form_data, dict):
194
- # 检查是否有数组类型的值
195
- processed_data = []
196
- for key, value in form_data.items():
197
- if isinstance(value, (list, tuple)):
198
- for item in value:
199
- processed_data.append((key, str(item)))
200
- else:
201
- processed_data.append((key, str(value)))
202
- display_form_data = processed_data
203
-
204
- if display_form_data:
205
- print(f"\n【Body (form-data)】")
206
- if isinstance(display_form_data, list):
207
- for item in display_form_data:
208
- if isinstance(item, tuple):
209
- key, value = item
210
- # 如果是文件,只显示文件名
211
- if hasattr(value, 'read'):
212
- print(f" {key}: <文件对象>")
170
+ # 打印请求信息(仅在非静默模式下)
171
+ if not self.silent:
172
+ print("\n" + "=" * 80)
173
+ print("【禅道API请求信息】")
174
+ print("=" * 80)
175
+ print(f"API URL: {api_url}")
176
+ print(f"\n【Headers】")
177
+ for key, value in headers.items():
178
+ print(f" {key}: {value}")
179
+
180
+ print(f"\n【Token生成信息】")
181
+ print(f" code: {self.code}")
182
+ print(f" key: {self.key[:10]}...{self.key[-10:] if len(self.key) > 20 else self.key}") # 只显示部分key,保护隐私
183
+ print(f" time: {current_timestamp}")
184
+ print(f" token生成公式: md5(code + key + time)")
185
+ print(f" token生成字符串: {self.code}{self.key}{current_timestamp}")
186
+ print(f" token: {token}")
187
+
188
+ print(f"\n【URL参数】")
189
+ for key, value in url_params.items():
190
+ print(f" {key}: {value}")
191
+
192
+ # 处理form_data用于显示
193
+ display_form_data = form_data
194
+ if isinstance(form_data, dict):
195
+ # 检查是否有数组类型的值
196
+ processed_data = []
197
+ for key, value in form_data.items():
198
+ if isinstance(value, (list, tuple)):
199
+ for item in value:
200
+ processed_data.append((key, str(item)))
201
+ else:
202
+ processed_data.append((key, str(value)))
203
+ display_form_data = processed_data
204
+
205
+ if display_form_data:
206
+ print(f"\n【Body (form-data)】")
207
+ if isinstance(display_form_data, list):
208
+ for item in display_form_data:
209
+ if isinstance(item, tuple):
210
+ key, value = item
211
+ # 如果是文件,只显示文件名
212
+ if hasattr(value, 'read'):
213
+ print(f" {key}: <文件对象>")
214
+ else:
215
+ print(f" {key}: {value}")
213
216
  else:
214
- print(f" {key}: {value}")
217
+ print(f" {item}")
218
+ elif isinstance(display_form_data, dict):
219
+ for key, value in display_form_data.items():
220
+ print(f" {key}: {value}")
221
+
222
+ if files:
223
+ print(f"\n【Files】")
224
+ for key, file_info in files.items():
225
+ if isinstance(file_info, tuple):
226
+ filename = file_info[0] if len(file_info) > 0 else "unknown"
227
+ print(f" {key}: {filename}")
215
228
  else:
216
- print(f" {item}")
217
- elif isinstance(display_form_data, dict):
218
- for key, value in display_form_data.items():
219
- print(f" {key}: {value}")
220
-
221
- if files:
222
- print(f"\n【Files】")
223
- for key, file_info in files.items():
224
- if isinstance(file_info, tuple):
225
- filename = file_info[0] if len(file_info) > 0 else "unknown"
226
- print(f" {key}: {filename}")
227
- else:
228
- print(f" {key}: {file_info}")
229
-
230
- print("=" * 80)
229
+ print(f" {key}: {file_info}")
230
+
231
+ print("=" * 80)
231
232
 
232
233
  try:
233
234
  if files:
@@ -252,24 +253,33 @@ class ZenTaoAPIClient:
252
253
  else:
253
254
  response = requests.post(api_url, params=url_params, headers=headers, timeout=30)
254
255
 
255
- # 打印响应信息
256
- print("\n【禅道API响应信息】")
257
- print("=" * 80)
258
- print(f"状态码: {response.status_code}")
259
- print(f"响应Headers:")
260
- for key, value in response.headers.items():
261
- print(f" {key}: {value}")
262
-
256
+ # 处理响应
263
257
  try:
264
258
  response_json = response.json()
265
- print(f"\n响应Body (JSON):")
266
- print(json.dumps(response_json, ensure_ascii=False, indent=2))
267
- print("=" * 80 + "\n")
259
+ # 打印响应信息(仅在非静默模式下)
260
+ if not self.silent:
261
+ print("\n【禅道API响应信息】")
262
+ print("=" * 80)
263
+ print(f"状态码: {response.status_code}")
264
+ print(f"响应Headers:")
265
+ for key, value in response.headers.items():
266
+ print(f" {key}: {value}")
267
+ print(f"\n响应Body (JSON):")
268
+ print(json.dumps(response_json, ensure_ascii=False, indent=2))
269
+ print("=" * 80 + "\n")
268
270
  return response_json
269
271
  except json.JSONDecodeError:
270
- print(f"\n响应Body (非JSON):")
271
- print(response.text[:1000]) # 只显示前1000个字符
272
- print("=" * 80 + "\n")
272
+ # 打印响应信息(仅在非静默模式下)
273
+ if not self.silent:
274
+ print("\n【禅道API响应信息】")
275
+ print("=" * 80)
276
+ print(f"状态码: {response.status_code}")
277
+ print(f"响应Headers:")
278
+ for key, value in response.headers.items():
279
+ print(f" {key}: {value}")
280
+ print(f"\n响应Body (非JSON):")
281
+ print(response.text[:1000]) # 只显示前1000个字符
282
+ print("=" * 80 + "\n")
273
283
  return {
274
284
  "status": 0,
275
285
  "message": "fail",
@@ -278,9 +288,11 @@ class ZenTaoAPIClient:
278
288
  "raw_response": response.text
279
289
  }
280
290
  except requests.exceptions.RequestException as e:
281
- print(f"\n【请求异常】")
282
- print(f"错误信息: {str(e)}")
283
- print("=" * 80 + "\n")
291
+ # 打印异常信息(仅在非静默模式下)
292
+ if not self.silent:
293
+ print(f"\n【请求异常】")
294
+ print(f"错误信息: {str(e)}")
295
+ print("=" * 80 + "\n")
284
296
  return {
285
297
  "status": 0,
286
298
  "message": "fail",
@@ -669,13 +681,19 @@ class ZenTaoNexus:
669
681
  LOWER_BUG = "0"
670
682
  REGRESSION = "0"
671
683
 
672
- # 职位类型到任务类型的映射
684
+ # 职位类型到任务类型的映射(支持中英文)
673
685
  ROLE_TO_TASK_TYPE = {
686
+ # 中文
674
687
  "测试": "4", # 测试
675
688
  "前端": "8", # 前端开发
676
689
  "后端": "3", # 后端开发
677
690
  "其它": "20", # 其他
678
- "其他": "20" # 其他(兼容两种写法)
691
+ "其他": "20", # 其他(兼容两种写法)
692
+ # 英文
693
+ "test": "4", # 测试
694
+ "frontend": "8", # 前端开发
695
+ "backend": "3", # 后端开发
696
+ "other": "20" # 其他
679
697
  }
680
698
 
681
699
  def __init__(self, config_path: str = None):
@@ -875,8 +893,9 @@ class ZenTaoNexus:
875
893
  """
876
894
  # 如果 task_data 中没有指定 mold,且配置了职位类型,则自动设置
877
895
  if 'mold' not in task_data or (task_data.get('mold') == '' or task_data.get('mold') is None):
878
- if self.role_type and self.role_type in self.ROLE_TO_TASK_TYPE:
879
- task_data['mold'] = self.ROLE_TO_TASK_TYPE[self.role_type]
896
+ if self.role_type:
897
+ # 如果映射存在,使用映射值;否则使用"其它"对应的值 "20"
898
+ task_data['mold'] = self.ROLE_TO_TASK_TYPE.get(self.role_type, "20")
880
899
 
881
900
  # 自动设置预计开始时间(当前日期)
882
901
  if 'estStarted' not in task_data or (task_data.get('estStarted') == '' or task_data.get('estStarted') is None):