@youcloud/mantis-mcp 1.0.4 → 1.0.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # 更新记录
2
2
 
3
+ ## [1.0.5] - 2026-10-19
4
+
5
+ - 用户引用兼容无前导零的十进制编号字符串,统一为数字后指派、筛选与恢复;补充明确的格式错误提示,继续拒绝含糊类型和不安全整数。
6
+ - 缺陷上下文补齐备注附件索引、所属备注与去重,避免顶层附件为空时遗漏分析材料。
7
+
3
8
  ## [1.0.4] - 2026-10-19
4
9
 
5
10
  - 修复 Windows 下操作账本目录同步失败导致所有写工具及操作核查不可用的问题;保留文件同步与替换失败的阻断行为,并清理失败的临时文件。
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mantis MCP
2
2
 
3
- 内部研发团队使用的 MantisBT MCP 服务,通过 stdio 为 Coding Agent 提供缺陷查询、修复登记、附件上传和可恢复的工作流操作。
3
+ 内部研发团队使用的 MantisBT MCP 服务,通过 stdio 为 Coding Agent 提供缺陷创建、查询、分配、修复、关闭等全生命周期管理和可恢复操作。
4
4
 
5
5
  项目与问题反馈:[内部 GitLab](https://git.umlife.net/ai-tools/mantis-mcp/-/work_items)。npm 包:[@youcloud/mantis-mcp](https://www.npmjs.com/package/@youcloud/mantis-mcp)。
6
6
 
@@ -24,11 +24,18 @@ export class Issues {
24
24
  }
25
25
  }
26
26
  export function visibleCollection(issue, key, emptyArraysOmitted) {
27
- if (Array.isArray(issue[key]))
28
- return issue[key];
29
- if (!(key in issue) && emptyArraysOmitted && ['attachments', 'notes', 'relationships'].includes(key))
30
- return [];
31
- return undefined;
27
+ const items = Array.isArray(issue[key]) ? issue[key]
28
+ : !(key in issue) && emptyArraysOmitted && ['attachments', 'notes', 'relationships'].includes(key) ? [] : undefined;
29
+ if (key !== 'attachments' || !items)
30
+ return items;
31
+ // REST 将备注附件放在 notes[].attachments;只合并当前响应已可见的附件,不修改原始事实快照。
32
+ const attachments = new Map(items.map(item => [item.id, item]));
33
+ for (const note of Array.isArray(issue.notes) ? issue.notes : []) {
34
+ for (const attachment of Array.isArray(note.attachments) ? note.attachments : []) {
35
+ attachments.set(attachment.id, { ...attachments.get(attachment.id), ...attachment, note_id: note.id });
36
+ }
37
+ }
38
+ return [...attachments.values()];
32
39
  }
33
40
  export function facts(issue, baseUrl) {
34
41
  const keys = ['id', 'summary', 'project', 'category', 'priority', 'severity', 'status', 'resolution', 'version', 'fixed_in_version', 'target_version', 'updated_at'];
@@ -168,9 +168,11 @@ export class Context {
168
168
  let item;
169
169
  if (section === 'notes')
170
170
  item = { id: raw.id, reporter: minimalUser(raw.reporter), text: raw.text, view_state: raw.view_state,
171
+ ...(Array.isArray(raw.attachments) && raw.attachments.length ? { attachment_ids: raw.attachments.map((a) => a.id) } : {}),
171
172
  updated_at: raw.updated_at, view_url: `${session.baseUrl}/view.php?id=${issue.id}#bugnote${raw.id}` };
172
173
  else if (section === 'attachments')
173
174
  item = { id: raw.id, filename: raw.file_name ?? raw.filename, size: raw.size, content_type: raw.content_type,
175
+ ...(raw.note_id !== undefined ? { note_id: raw.note_id } : {}),
174
176
  download_url: `${session.baseUrl}/file_download.php?file_id=${raw.id}&type=bug`, view_url: output.issue.view_url };
175
177
  else if (section === 'monitors')
176
178
  item = minimalUser(raw);
@@ -5,7 +5,13 @@ import { ConnectionConfigError } from '../connection-config.js';
5
5
  const systemErrorCodes = new Set([...getSystemErrorMap().values()].map(([name]) => name));
6
6
  export const id = z.number().int().positive().describe('正整数编号');
7
7
  export const text = z.string().refine(v => v.trim().length > 0, '不可为空白').describe('非空正文');
8
- const ref = z.union([z.literal('me'), id]).describe('当前用户 me 或明确的用户编号');
8
+ const refError = '用户引用须为 "me"、正整数用户编号或其十进制字符串(无前导零,最大 9007199254740991);用户名请先用 get_project_context 查询编号';
9
+ // 仅兼容明确的十进制编号,避免数字强转把布尔值、数组或指数写法当成用户。
10
+ const userId = z.number().int({ error: refError }).positive({ error: refError });
11
+ const userIdString = z.string().regex(/^[1-9][0-9]*$/, refError)
12
+ .refine(value => Number.isSafeInteger(Number(value)), refError).transform(Number);
13
+ const ref = z.union([z.literal('me'), userId, userIdString], { error: refError })
14
+ .describe('当前用户 "me"、正整数用户编号或无前导零的十进制编号字符串;不接受用户名');
9
15
  const iso = z.iso.datetime({ offset: true }).describe('含时区的 ISO8601 时间');
10
16
  const evidence = z.array(z.strictObject({ kind: z.enum(['url', 'text']), value: text }));
11
17
  const environment = { environment: text.optional(), version_id: id.optional() };
package/docs/cookbook.md CHANGED
@@ -58,6 +58,8 @@
58
58
 
59
59
  ## 写入公共参数与生命周期
60
60
 
61
+ 用户引用 `assignee`(指派、受理、查询)和 `reporter`(查询)接受 `"me"`、正整数编号或无前导零的十进制编号字符串,例如 `5` 与 `"5"` 等价。编号不得超过 `9007199254740991`;不接受空白、布尔值、数组、指数写法或用户名。按姓名或登录名操作时,先用 `get_project_context` 的 `members` 区块和 `member_query` 确认用户编号,再传入引用。
62
+
61
63
  | 参数 | 规则 |
62
64
  |---|---|
63
65
  | `operation_id` | 每个新动作独立 UUID;真实写入必填,同次核查和恢复保持不变 |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@youcloud/mantis-mcp",
3
- "version": "1.0.4",
4
- "description": "面向研发工作流的 MantisBT MCP 服务,支持缺陷查询、修复登记、附件和可恢复操作",
3
+ "version": "1.0.5",
4
+ "description": "面向研发工作流的 MantisBT MCP 服务,支持缺陷创建、查询、分配、修复、关闭等全生命周期管理和可恢复操作",
5
5
  "license": "MIT",
6
6
  "homepage": "https://git.umlife.net/ai-tools/mantis-mcp",
7
7
  "bugs": {