@zereight/mcp-gitlab 2.3.8-next.145 → 2.3.8-next.147

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.
@@ -0,0 +1,42 @@
1
+ const NEXT_PREFIX = "\nNext: ";
2
+ export function hasRecoveryHint(message) {
3
+ return message.includes(NEXT_PREFIX);
4
+ }
5
+ export function recoveryHintFor(message) {
6
+ if (/^Access denied:/i.test(message)) {
7
+ return undefined;
8
+ }
9
+ if (/is not available on this server/i.test(message)) {
10
+ if (/slim tool profile/i.test(message) || /cannot activate/i.test(message)) {
11
+ return undefined;
12
+ }
13
+ if (/discover_tools|GITLAB_TOOLSETS|GITLAB_TOOLS/.test(message)) {
14
+ return "call discover_tools with the category, or add it to GITLAB_TOOLSETS.";
15
+ }
16
+ }
17
+ if (/\b401\b/.test(message) || /unauthorized/i.test(message)) {
18
+ return "set GITLAB_PERSONAL_ACCESS_TOKEN (or run `zereight-mcp-gitlab auth`) and retry.";
19
+ }
20
+ if (/rate limit/i.test(message)) {
21
+ return "wait and retry; lower per_page or paginate if the client is bursting.";
22
+ }
23
+ if (/\b403\b/.test(message) ||
24
+ /forbidden/i.test(message) ||
25
+ /insufficient_scope/i.test(message)) {
26
+ return "check token scopes and GITLAB_PERMISSION_MODE; grant read_user or User:Read for whoami.";
27
+ }
28
+ if (/\b404\b/.test(message) || /404 not found/i.test(message)) {
29
+ return "check project_id (numeric ID or group%2Fproject) and the resource iid.";
30
+ }
31
+ return undefined;
32
+ }
33
+ export function appendRecoveryHint(message) {
34
+ if (hasRecoveryHint(message)) {
35
+ return message;
36
+ }
37
+ const hint = recoveryHintFor(message);
38
+ if (hint === undefined) {
39
+ return message;
40
+ }
41
+ return `${message}${NEXT_PREFIX}${hint}`;
42
+ }
@@ -0,0 +1,90 @@
1
+ /** MCP-only argument; stripped before GitLab handlers run. */
2
+ export const LIST_SUMMARY_ARGUMENT = "summary";
3
+ export const LIST_SUMMARY_ARGUMENT_DESCRIPTION = "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.";
4
+ const SUMMARY_FIELDS = [
5
+ "id",
6
+ "iid",
7
+ "title",
8
+ "name",
9
+ "state",
10
+ "status",
11
+ "ref",
12
+ "web_url",
13
+ "path_with_namespace",
14
+ "username",
15
+ "short_id",
16
+ "key",
17
+ "tag_name",
18
+ "slug",
19
+ "filename",
20
+ "new_path",
21
+ ];
22
+ const NATIVE_SUMMARY_TOOLS = new Set(["list_webhook_events"]);
23
+ export function toolAcceptsDecoratedSummary(toolName) {
24
+ if (NATIVE_SUMMARY_TOOLS.has(toolName)) {
25
+ return false;
26
+ }
27
+ return toolName.startsWith("list_") || toolName === "mr_discussions";
28
+ }
29
+ export function readListSummaryRequested(args) {
30
+ if (!args) {
31
+ return false;
32
+ }
33
+ const raw = args[LIST_SUMMARY_ARGUMENT];
34
+ return raw === true || raw === "true";
35
+ }
36
+ export function omitListSummaryArgument(args) {
37
+ if (!(LIST_SUMMARY_ARGUMENT in args)) {
38
+ return args;
39
+ }
40
+ const { [LIST_SUMMARY_ARGUMENT]: _omit, ...rest } = args;
41
+ return rest;
42
+ }
43
+ function isRecord(value) {
44
+ return typeof value === "object" && value !== null && !Array.isArray(value);
45
+ }
46
+ function summarizeItem(item) {
47
+ if (!isRecord(item)) {
48
+ return item;
49
+ }
50
+ const summarized = {};
51
+ for (const field of SUMMARY_FIELDS) {
52
+ if (field in item) {
53
+ summarized[field] = item[field];
54
+ }
55
+ }
56
+ return Object.keys(summarized).length > 0 ? summarized : item;
57
+ }
58
+ export function summarizeListPayload(data) {
59
+ if (Array.isArray(data)) {
60
+ return data.map(summarizeItem);
61
+ }
62
+ if (isRecord(data) && Array.isArray(data.items)) {
63
+ return { ...data, items: data.items.map(summarizeItem) };
64
+ }
65
+ return data;
66
+ }
67
+ function isTextContentBlock(value) {
68
+ return typeof value === "object" && value !== null;
69
+ }
70
+ export function applyListSummaryToToolResult(result, requested) {
71
+ if (!requested || result.isError) {
72
+ return result;
73
+ }
74
+ if (!Array.isArray(result.content)) {
75
+ return result;
76
+ }
77
+ const content = result.content.map(block => {
78
+ if (!isTextContentBlock(block) || block.type !== "text" || typeof block.text !== "string") {
79
+ return block;
80
+ }
81
+ try {
82
+ const parsed = JSON.parse(block.text);
83
+ return { ...block, text: JSON.stringify(summarizeListPayload(parsed)) };
84
+ }
85
+ catch {
86
+ return block;
87
+ }
88
+ });
89
+ return { ...result, content };
90
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.3.8-next.145",
3
+ "version": "2.3.8-next.147",
4
4
  "mcpName": "io.github.zereight/gitlab-mcp",
5
5
  "description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
6
6
  "keywords": [