opencode-gitlab-plugin 2.4.0 → 2.6.0
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 +30 -0
- package/dist/index.js +180 -39
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +190 -49
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +1 -1
package/dist/mcp-server.cjs
CHANGED
|
@@ -3945,7 +3945,7 @@ var require_core = __commonJS({
|
|
|
3945
3945
|
constructor(opts = {}) {
|
|
3946
3946
|
this.schemas = {};
|
|
3947
3947
|
this.refs = {};
|
|
3948
|
-
this.formats =
|
|
3948
|
+
this.formats = /* @__PURE__ */ Object.create(null);
|
|
3949
3949
|
this._compilations = /* @__PURE__ */ new Set();
|
|
3950
3950
|
this._loading = {};
|
|
3951
3951
|
this._cache = /* @__PURE__ */ new Map();
|
|
@@ -10507,7 +10507,6 @@ ZodNaN.create = (params) => {
|
|
|
10507
10507
|
...processCreateParams(params)
|
|
10508
10508
|
});
|
|
10509
10509
|
};
|
|
10510
|
-
var BRAND = Symbol("zod_brand");
|
|
10511
10510
|
var ZodBranded = class extends ZodType {
|
|
10512
10511
|
_parse(input) {
|
|
10513
10512
|
const { ctx } = this._processInputParams(input);
|
|
@@ -10987,7 +10986,7 @@ function $constructor(name, initializer3, params) {
|
|
|
10987
10986
|
Object.defineProperty(_, "name", { value: name });
|
|
10988
10987
|
return _;
|
|
10989
10988
|
}
|
|
10990
|
-
var $brand = Symbol("zod_brand");
|
|
10989
|
+
var $brand = /* @__PURE__ */ Symbol("zod_brand");
|
|
10991
10990
|
var $ZodAsyncError = class extends Error {
|
|
10992
10991
|
constructor() {
|
|
10993
10992
|
super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
|
|
@@ -11132,7 +11131,7 @@ function floatSafeRemainder2(val, step) {
|
|
|
11132
11131
|
const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
|
|
11133
11132
|
return valInt % stepInt / 10 ** decCount;
|
|
11134
11133
|
}
|
|
11135
|
-
var EVALUATING = Symbol("evaluating");
|
|
11134
|
+
var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
|
|
11136
11135
|
function defineLazy(object3, key, getter) {
|
|
11137
11136
|
let value = void 0;
|
|
11138
11137
|
Object.defineProperty(object3, key, {
|
|
@@ -19977,8 +19976,8 @@ function yo_default() {
|
|
|
19977
19976
|
}
|
|
19978
19977
|
|
|
19979
19978
|
// node_modules/zod/v4/core/registries.js
|
|
19980
|
-
var $output = Symbol("ZodOutput");
|
|
19981
|
-
var $input = Symbol("ZodInput");
|
|
19979
|
+
var $output = /* @__PURE__ */ Symbol("ZodOutput");
|
|
19980
|
+
var $input = /* @__PURE__ */ Symbol("ZodInput");
|
|
19982
19981
|
var $ZodRegistry = class {
|
|
19983
19982
|
constructor() {
|
|
19984
19983
|
this._map = /* @__PURE__ */ new WeakMap();
|
|
@@ -24820,7 +24819,7 @@ function isTerminal(status) {
|
|
|
24820
24819
|
}
|
|
24821
24820
|
|
|
24822
24821
|
// node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
24823
|
-
var ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
24822
|
+
var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
|
|
24824
24823
|
var defaultOptions = {
|
|
24825
24824
|
name: void 0,
|
|
24826
24825
|
$refStrategy: "root",
|
|
@@ -27796,7 +27795,7 @@ var Server = class extends Protocol {
|
|
|
27796
27795
|
};
|
|
27797
27796
|
|
|
27798
27797
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
27799
|
-
var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
27798
|
+
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
27800
27799
|
function isCompletable(schema) {
|
|
27801
27800
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
27802
27801
|
}
|
|
@@ -28791,7 +28790,13 @@ var GitLabApiClient = class {
|
|
|
28791
28790
|
}
|
|
28792
28791
|
return projectId;
|
|
28793
28792
|
}
|
|
28794
|
-
|
|
28793
|
+
/**
|
|
28794
|
+
* Core HTTP request used by all REST helpers.
|
|
28795
|
+
*
|
|
28796
|
+
* Returns the raw `Response` after validating the status code so callers can
|
|
28797
|
+
* inspect headers (e.g. for pagination) before parsing the body.
|
|
28798
|
+
*/
|
|
28799
|
+
async rawFetch(method, path2, body) {
|
|
28795
28800
|
const url2 = `${this.instanceUrl}/api/v4${path2}`;
|
|
28796
28801
|
const response = await fetch(url2, {
|
|
28797
28802
|
method,
|
|
@@ -28802,12 +28807,53 @@ var GitLabApiClient = class {
|
|
|
28802
28807
|
const errorText = await response.text();
|
|
28803
28808
|
throw new Error(`GitLab API error ${response.status}: ${errorText}`);
|
|
28804
28809
|
}
|
|
28810
|
+
return response;
|
|
28811
|
+
}
|
|
28812
|
+
async fetch(method, path2, body) {
|
|
28813
|
+
const response = await this.rawFetch(method, path2, body);
|
|
28805
28814
|
const text = await response.text();
|
|
28806
28815
|
if (!text) {
|
|
28807
28816
|
return {};
|
|
28808
28817
|
}
|
|
28809
28818
|
return JSON.parse(text);
|
|
28810
28819
|
}
|
|
28820
|
+
/**
|
|
28821
|
+
* Parse a numeric pagination header, guarding against empty strings.
|
|
28822
|
+
*
|
|
28823
|
+
* GitLab returns `""` (rather than omitting the header) for `X-Next-Page` and
|
|
28824
|
+
* `X-Prev-Page` when there is no next/prev page, and bare `parseInt` without
|
|
28825
|
+
* a radix on an empty string yields `NaN`. Treat empty/missing as `undefined`.
|
|
28826
|
+
*/
|
|
28827
|
+
parsePaginationHeader(response, name) {
|
|
28828
|
+
const raw = response.headers.get(name);
|
|
28829
|
+
if (raw == null || raw === "") return void 0;
|
|
28830
|
+
const value = parseInt(raw, 10);
|
|
28831
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
28832
|
+
}
|
|
28833
|
+
/**
|
|
28834
|
+
* Pagination info extracted from GitLab API response headers
|
|
28835
|
+
*/
|
|
28836
|
+
extractPaginationInfo(response) {
|
|
28837
|
+
return {
|
|
28838
|
+
total: this.parsePaginationHeader(response, "X-Total"),
|
|
28839
|
+
totalPages: this.parsePaginationHeader(response, "X-Total-Pages"),
|
|
28840
|
+
page: this.parsePaginationHeader(response, "X-Page"),
|
|
28841
|
+
perPage: this.parsePaginationHeader(response, "X-Per-Page"),
|
|
28842
|
+
nextPage: this.parsePaginationHeader(response, "X-Next-Page"),
|
|
28843
|
+
prevPage: this.parsePaginationHeader(response, "X-Prev-Page")
|
|
28844
|
+
};
|
|
28845
|
+
}
|
|
28846
|
+
/**
|
|
28847
|
+
* Fetch with pagination info from response headers.
|
|
28848
|
+
* Use this for list endpoints where knowing if more data exists is important.
|
|
28849
|
+
*/
|
|
28850
|
+
async fetchWithPagination(method, path2, body) {
|
|
28851
|
+
const response = await this.rawFetch(method, path2, body);
|
|
28852
|
+
const text = await response.text();
|
|
28853
|
+
const data = text ? JSON.parse(text) : [];
|
|
28854
|
+
const pagination = this.extractPaginationInfo(response);
|
|
28855
|
+
return { data, pagination };
|
|
28856
|
+
}
|
|
28811
28857
|
async fetchText(method, path2) {
|
|
28812
28858
|
const url2 = `${this.instanceUrl}/api/v4${path2}`;
|
|
28813
28859
|
const response = await fetch(url2, {
|
|
@@ -29071,6 +29117,7 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
29071
29117
|
async listMergeRequests(options) {
|
|
29072
29118
|
const params = new URLSearchParams();
|
|
29073
29119
|
params.set("per_page", String(options.limit || 20));
|
|
29120
|
+
if (options.page) params.set("page", String(options.page));
|
|
29074
29121
|
if (options.state) params.set("state", options.state);
|
|
29075
29122
|
if (options.scope) params.set("scope", options.scope);
|
|
29076
29123
|
if (options.search) params.set("search", options.search);
|
|
@@ -29082,7 +29129,7 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
29082
29129
|
} else {
|
|
29083
29130
|
path2 = `/merge_requests?${params}`;
|
|
29084
29131
|
}
|
|
29085
|
-
return this.
|
|
29132
|
+
return this.fetchWithPagination("GET", path2);
|
|
29086
29133
|
}
|
|
29087
29134
|
async getMrChanges(projectId, mrIid) {
|
|
29088
29135
|
const encodedProject = this.encodeProjectId(projectId);
|
|
@@ -29203,6 +29250,14 @@ var MergeRequestsClient = class extends GitLabApiClient {
|
|
|
29203
29250
|
{ body }
|
|
29204
29251
|
);
|
|
29205
29252
|
}
|
|
29253
|
+
async updateMrNote(projectId, mrIid, noteId, body) {
|
|
29254
|
+
const encodedProject = this.encodeProjectId(projectId);
|
|
29255
|
+
return this.fetch(
|
|
29256
|
+
"PUT",
|
|
29257
|
+
`/projects/${encodedProject}/merge_requests/${mrIid}/notes/${noteId}`,
|
|
29258
|
+
{ body }
|
|
29259
|
+
);
|
|
29260
|
+
}
|
|
29206
29261
|
async createMergeRequest(projectId, options) {
|
|
29207
29262
|
const encodedProject = this.encodeProjectId(projectId);
|
|
29208
29263
|
return this.fetch(
|
|
@@ -29486,6 +29541,7 @@ var IssuesClient = class extends GitLabApiClient {
|
|
|
29486
29541
|
async listIssues(options) {
|
|
29487
29542
|
const params = new URLSearchParams();
|
|
29488
29543
|
params.set("per_page", String(options.limit || 20));
|
|
29544
|
+
if (options.page) params.set("page", String(options.page));
|
|
29489
29545
|
if (options.state) params.set("state", options.state);
|
|
29490
29546
|
if (options.scope) params.set("scope", options.scope);
|
|
29491
29547
|
if (options.search) params.set("search", options.search);
|
|
@@ -29498,7 +29554,7 @@ var IssuesClient = class extends GitLabApiClient {
|
|
|
29498
29554
|
} else {
|
|
29499
29555
|
path2 = `/issues?${params}`;
|
|
29500
29556
|
}
|
|
29501
|
-
return this.
|
|
29557
|
+
return this.fetchWithPagination("GET", path2);
|
|
29502
29558
|
}
|
|
29503
29559
|
/**
|
|
29504
29560
|
* List notes on an issue using GraphQL API with pagination support
|
|
@@ -29581,6 +29637,14 @@ var IssuesClient = class extends GitLabApiClient {
|
|
|
29581
29637
|
`/projects/${encodedProject}/issues/${issueIid}/notes/${noteId}`
|
|
29582
29638
|
);
|
|
29583
29639
|
}
|
|
29640
|
+
async updateIssueNote(projectId, issueIid, noteId, body) {
|
|
29641
|
+
const encodedProject = this.encodeProjectId(projectId);
|
|
29642
|
+
return this.fetch(
|
|
29643
|
+
"PUT",
|
|
29644
|
+
`/projects/${encodedProject}/issues/${issueIid}/notes/${noteId}`,
|
|
29645
|
+
{ body }
|
|
29646
|
+
);
|
|
29647
|
+
}
|
|
29584
29648
|
};
|
|
29585
29649
|
|
|
29586
29650
|
// src/client/work-items.ts
|
|
@@ -30915,6 +30979,14 @@ var EpicsClient = class extends GitLabApiClient {
|
|
|
30915
30979
|
`/groups/${encodedGroup}/epics/${epicIid}/notes/${noteId}`
|
|
30916
30980
|
);
|
|
30917
30981
|
}
|
|
30982
|
+
async updateEpicNote(groupId, epicIid, noteId, body) {
|
|
30983
|
+
const encodedGroup = encodeURIComponent(groupId);
|
|
30984
|
+
return this.fetch(
|
|
30985
|
+
"PUT",
|
|
30986
|
+
`/groups/${encodedGroup}/epics/${epicIid}/notes/${noteId}`,
|
|
30987
|
+
{ body }
|
|
30988
|
+
);
|
|
30989
|
+
}
|
|
30918
30990
|
};
|
|
30919
30991
|
|
|
30920
30992
|
// src/client/snippets.ts
|
|
@@ -31043,6 +31115,14 @@ var SnippetsClient = class extends GitLabApiClient {
|
|
|
31043
31115
|
{ body }
|
|
31044
31116
|
);
|
|
31045
31117
|
}
|
|
31118
|
+
async updateSnippetNote(projectId, snippetId, noteId, body) {
|
|
31119
|
+
const encodedProject = this.encodeProjectId(projectId);
|
|
31120
|
+
return this.fetch(
|
|
31121
|
+
"PUT",
|
|
31122
|
+
`/projects/${encodedProject}/snippets/${snippetId}/notes/${noteId}`,
|
|
31123
|
+
{ body }
|
|
31124
|
+
);
|
|
31125
|
+
}
|
|
31046
31126
|
};
|
|
31047
31127
|
|
|
31048
31128
|
// src/client/discussions.ts
|
|
@@ -31386,26 +31466,31 @@ Returns: title, description, state, author, assignees, reviewers, labels, diff s
|
|
|
31386
31466
|
}),
|
|
31387
31467
|
gitlab_list_merge_requests: tool({
|
|
31388
31468
|
description: `List merge requests for a project or search globally.
|
|
31389
|
-
Can filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels
|
|
31469
|
+
Can filter by state (opened, closed, merged, all), scope (assigned_to_me, created_by_me), and labels.
|
|
31470
|
+
|
|
31471
|
+
IMPORTANT: Response includes pagination info. If nextPage exists, there are more results.
|
|
31472
|
+
Always paginate until you get an empty response or no nextPage to ensure you have all data.`,
|
|
31390
31473
|
args: {
|
|
31391
31474
|
project_id: z.string().optional().describe("The project ID or path. If not provided, searches globally."),
|
|
31392
31475
|
state: z.enum(["opened", "closed", "merged", "all"]).optional().describe("Filter by MR state (default: opened)"),
|
|
31393
31476
|
scope: z.enum(["assigned_to_me", "created_by_me", "all"]).optional().describe("Filter by scope"),
|
|
31394
31477
|
search: z.string().optional().describe("Search MRs by title or description"),
|
|
31395
31478
|
labels: z.string().optional().describe("Comma-separated list of labels to filter by"),
|
|
31396
|
-
limit: z.number().optional().describe("Maximum number of results (default: 20)")
|
|
31479
|
+
limit: z.number().optional().describe("Maximum number of results per page (default: 20)"),
|
|
31480
|
+
page: z.number().optional().describe("Page number for pagination (default: 1)")
|
|
31397
31481
|
},
|
|
31398
31482
|
execute: async (args, _ctx) => {
|
|
31399
31483
|
const client = getGitLabClient();
|
|
31400
|
-
const
|
|
31484
|
+
const result = await client.listMergeRequests({
|
|
31401
31485
|
projectId: args.project_id,
|
|
31402
31486
|
state: args.state,
|
|
31403
31487
|
scope: args.scope,
|
|
31404
31488
|
search: args.search,
|
|
31405
31489
|
labels: args.labels,
|
|
31406
|
-
limit: args.limit
|
|
31490
|
+
limit: args.limit,
|
|
31491
|
+
page: args.page
|
|
31407
31492
|
});
|
|
31408
|
-
return JSON.stringify(
|
|
31493
|
+
return JSON.stringify(result, null, 2);
|
|
31409
31494
|
}
|
|
31410
31495
|
}),
|
|
31411
31496
|
gitlab_get_mr_changes: tool({
|
|
@@ -31736,7 +31821,10 @@ Returns: title, description, state, author, assignees, labels, milestone, weight
|
|
|
31736
31821
|
}),
|
|
31737
31822
|
gitlab_list_issues: tool({
|
|
31738
31823
|
description: `List issues for a project or search globally.
|
|
31739
|
-
Can filter by state, labels, assignee, milestone
|
|
31824
|
+
Can filter by state, labels, assignee, milestone.
|
|
31825
|
+
|
|
31826
|
+
IMPORTANT: Response includes pagination info. If nextPage exists, there are more results.
|
|
31827
|
+
Always paginate until you get an empty response or no nextPage to ensure you have all data.`,
|
|
31740
31828
|
args: {
|
|
31741
31829
|
project_id: z2.string().optional().describe("The project ID or path. If not provided, searches globally."),
|
|
31742
31830
|
state: z2.enum(["opened", "closed", "all"]).optional().describe("Filter by issue state (default: opened)"),
|
|
@@ -31744,20 +31832,22 @@ Can filter by state, labels, assignee, milestone.`,
|
|
|
31744
31832
|
search: z2.string().optional().describe("Search issues by title or description"),
|
|
31745
31833
|
labels: z2.string().optional().describe("Comma-separated list of labels to filter by"),
|
|
31746
31834
|
milestone: z2.string().optional().describe("Filter by milestone title"),
|
|
31747
|
-
limit: z2.number().optional().describe("Maximum number of results (default: 20)")
|
|
31835
|
+
limit: z2.number().optional().describe("Maximum number of results per page (default: 20)"),
|
|
31836
|
+
page: z2.number().optional().describe("Page number for pagination (default: 1)")
|
|
31748
31837
|
},
|
|
31749
31838
|
execute: async (args, _ctx) => {
|
|
31750
31839
|
const client = getGitLabClient();
|
|
31751
|
-
const
|
|
31840
|
+
const result = await client.listIssues({
|
|
31752
31841
|
projectId: args.project_id,
|
|
31753
31842
|
state: args.state,
|
|
31754
31843
|
scope: args.scope,
|
|
31755
31844
|
search: args.search,
|
|
31756
31845
|
labels: args.labels,
|
|
31757
31846
|
milestone: args.milestone,
|
|
31758
|
-
limit: args.limit
|
|
31847
|
+
limit: args.limit,
|
|
31848
|
+
page: args.page
|
|
31759
31849
|
});
|
|
31760
|
-
return JSON.stringify(
|
|
31850
|
+
return JSON.stringify(result, null, 2);
|
|
31761
31851
|
}
|
|
31762
31852
|
})
|
|
31763
31853
|
};
|
|
@@ -33247,19 +33337,22 @@ function filterNotesByResolved(result, resolved) {
|
|
|
33247
33337
|
}
|
|
33248
33338
|
};
|
|
33249
33339
|
}
|
|
33250
|
-
var
|
|
33251
|
-
var
|
|
33340
|
+
var NOTE_RESOURCE_TYPES = ["merge_request", "issue", "epic", "snippet"];
|
|
33341
|
+
var GET_NOTE_RESOURCE_TYPES = ["issue", "epic"];
|
|
33252
33342
|
function validationError3(param, resourceType) {
|
|
33253
33343
|
return new Error(
|
|
33254
33344
|
`Missing required parameter: '${param}' is required for resource_type '${resourceType}'`
|
|
33255
33345
|
);
|
|
33256
33346
|
}
|
|
33257
|
-
function
|
|
33258
|
-
if (!
|
|
33347
|
+
function validateNoteParams(resourceType, args, opts) {
|
|
33348
|
+
if (!opts.allowedTypes.includes(resourceType)) {
|
|
33259
33349
|
throw new Error(
|
|
33260
|
-
`Invalid resource_type '${resourceType}'. Must be one of: ${
|
|
33350
|
+
`Invalid resource_type '${resourceType}'. Must be one of: ${opts.allowedTypes.join(", ")}`
|
|
33261
33351
|
);
|
|
33262
33352
|
}
|
|
33353
|
+
if (opts.requireNoteId && args.note_id == null) {
|
|
33354
|
+
throw validationError3("note_id", resourceType);
|
|
33355
|
+
}
|
|
33263
33356
|
switch (resourceType) {
|
|
33264
33357
|
case "merge_request":
|
|
33265
33358
|
case "issue":
|
|
@@ -33276,24 +33369,6 @@ function validateListCreateParams(resourceType, args) {
|
|
|
33276
33369
|
break;
|
|
33277
33370
|
}
|
|
33278
33371
|
}
|
|
33279
|
-
function validateGetNoteParams(resourceType, args) {
|
|
33280
|
-
if (!VALID_GET_NOTE_TYPES.includes(resourceType)) {
|
|
33281
|
-
throw new Error(
|
|
33282
|
-
`Invalid resource_type '${resourceType}'. Must be one of: ${VALID_GET_NOTE_TYPES.join(", ")}`
|
|
33283
|
-
);
|
|
33284
|
-
}
|
|
33285
|
-
if (args.note_id == null) throw validationError3("note_id", resourceType);
|
|
33286
|
-
switch (resourceType) {
|
|
33287
|
-
case "issue":
|
|
33288
|
-
if (!args.project_id) throw validationError3("project_id", resourceType);
|
|
33289
|
-
if (args.iid == null) throw validationError3("iid", resourceType);
|
|
33290
|
-
break;
|
|
33291
|
-
case "epic":
|
|
33292
|
-
if (!args.group_id) throw validationError3("group_id", resourceType);
|
|
33293
|
-
if (args.iid == null) throw validationError3("iid", resourceType);
|
|
33294
|
-
break;
|
|
33295
|
-
}
|
|
33296
|
-
}
|
|
33297
33372
|
var notesUnifiedTools = {
|
|
33298
33373
|
/**
|
|
33299
33374
|
* List notes/comments for any GitLab resource type
|
|
@@ -33329,7 +33404,7 @@ Examples:
|
|
|
33329
33404
|
before: z14.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
33330
33405
|
},
|
|
33331
33406
|
execute: async (args, _ctx) => {
|
|
33332
|
-
|
|
33407
|
+
validateNoteParams(args.resource_type, args, { allowedTypes: NOTE_RESOURCE_TYPES });
|
|
33333
33408
|
const client = getGitLabClient();
|
|
33334
33409
|
const paginationOptions = {
|
|
33335
33410
|
first: args.first,
|
|
@@ -33383,7 +33458,10 @@ Examples:
|
|
|
33383
33458
|
iid: z14.number().describe("Internal ID of the issue or epic")
|
|
33384
33459
|
},
|
|
33385
33460
|
execute: async (args, _ctx) => {
|
|
33386
|
-
|
|
33461
|
+
validateNoteParams(args.resource_type, args, {
|
|
33462
|
+
allowedTypes: GET_NOTE_RESOURCE_TYPES,
|
|
33463
|
+
requireNoteId: true
|
|
33464
|
+
});
|
|
33387
33465
|
const client = getGitLabClient();
|
|
33388
33466
|
switch (args.resource_type) {
|
|
33389
33467
|
case "issue":
|
|
@@ -33427,7 +33505,7 @@ Examples:
|
|
|
33427
33505
|
snippet_id: z14.number().optional().describe("Snippet ID (required for snippet)")
|
|
33428
33506
|
},
|
|
33429
33507
|
execute: async (args, _ctx) => {
|
|
33430
|
-
|
|
33508
|
+
validateNoteParams(args.resource_type, args, { allowedTypes: NOTE_RESOURCE_TYPES });
|
|
33431
33509
|
const client = getGitLabClient();
|
|
33432
33510
|
switch (args.resource_type) {
|
|
33433
33511
|
case "merge_request":
|
|
@@ -33458,6 +33536,68 @@ Examples:
|
|
|
33458
33536
|
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
33459
33537
|
}
|
|
33460
33538
|
}
|
|
33539
|
+
}),
|
|
33540
|
+
/**
|
|
33541
|
+
* Update an existing note/comment on any GitLab resource
|
|
33542
|
+
*/
|
|
33543
|
+
gitlab_update_note: tool({
|
|
33544
|
+
description: `Update an existing note/comment on any GitLab resource.
|
|
33545
|
+
Modifies the body content of an existing note. You can only update notes you authored.
|
|
33546
|
+
|
|
33547
|
+
Examples:
|
|
33548
|
+
- MR note: resource_type="merge_request", project_id="group/project", iid=123, note_id=456, body="Updated comment"
|
|
33549
|
+
- Issue note: resource_type="issue", project_id="group/project", iid=456, note_id=789, body="Updated comment"
|
|
33550
|
+
- Epic note: resource_type="epic", group_id="my-group", iid=1, note_id=456, body="Updated comment"
|
|
33551
|
+
- Snippet note: resource_type="snippet", project_id="group/project", snippet_id=789, note_id=123, body="Updated comment"`,
|
|
33552
|
+
args: {
|
|
33553
|
+
resource_type: z14.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
|
|
33554
|
+
note_id: z14.number().describe("The ID of the note to update"),
|
|
33555
|
+
body: z14.string().describe("The new content for the note (supports Markdown)"),
|
|
33556
|
+
project_id: z14.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
|
|
33557
|
+
group_id: z14.string().optional().describe("Group ID or path. Required for epic"),
|
|
33558
|
+
iid: z14.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
|
|
33559
|
+
snippet_id: z14.number().optional().describe("Snippet ID (required for snippet)")
|
|
33560
|
+
},
|
|
33561
|
+
execute: async (args, _ctx) => {
|
|
33562
|
+
validateNoteParams(args.resource_type, args, {
|
|
33563
|
+
allowedTypes: NOTE_RESOURCE_TYPES,
|
|
33564
|
+
requireNoteId: true
|
|
33565
|
+
});
|
|
33566
|
+
const client = getGitLabClient();
|
|
33567
|
+
switch (args.resource_type) {
|
|
33568
|
+
case "merge_request":
|
|
33569
|
+
return JSON.stringify(
|
|
33570
|
+
await client.updateMrNote(args.project_id, args.iid, args.note_id, args.body),
|
|
33571
|
+
null,
|
|
33572
|
+
2
|
|
33573
|
+
);
|
|
33574
|
+
case "issue":
|
|
33575
|
+
return JSON.stringify(
|
|
33576
|
+
await client.updateIssueNote(args.project_id, args.iid, args.note_id, args.body),
|
|
33577
|
+
null,
|
|
33578
|
+
2
|
|
33579
|
+
);
|
|
33580
|
+
case "epic":
|
|
33581
|
+
return JSON.stringify(
|
|
33582
|
+
await client.updateEpicNote(args.group_id, args.iid, args.note_id, args.body),
|
|
33583
|
+
null,
|
|
33584
|
+
2
|
|
33585
|
+
);
|
|
33586
|
+
case "snippet":
|
|
33587
|
+
return JSON.stringify(
|
|
33588
|
+
await client.updateSnippetNote(
|
|
33589
|
+
args.project_id,
|
|
33590
|
+
args.snippet_id,
|
|
33591
|
+
args.note_id,
|
|
33592
|
+
args.body
|
|
33593
|
+
),
|
|
33594
|
+
null,
|
|
33595
|
+
2
|
|
33596
|
+
);
|
|
33597
|
+
default:
|
|
33598
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
33599
|
+
}
|
|
33600
|
+
}
|
|
33461
33601
|
})
|
|
33462
33602
|
};
|
|
33463
33603
|
|
|
@@ -33897,7 +34037,8 @@ function adaptToolsToMcp(server, tools) {
|
|
|
33897
34037
|
server.tool(name, def.description, def.args, async (args) => {
|
|
33898
34038
|
try {
|
|
33899
34039
|
const result = await def.execute(args, {});
|
|
33900
|
-
|
|
34040
|
+
const text = typeof result === "string" ? result : result.output;
|
|
34041
|
+
return { content: [{ type: "text", text }] };
|
|
33901
34042
|
} catch (err) {
|
|
33902
34043
|
const message = err instanceof Error ? err.message : String(err);
|
|
33903
34044
|
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
@@ -33934,7 +34075,7 @@ async function main() {
|
|
|
33934
34075
|
...auditTools,
|
|
33935
34076
|
...awardEmojiTools
|
|
33936
34077
|
};
|
|
33937
|
-
const version2 = true ? "2.
|
|
34078
|
+
const version2 = true ? "2.6.0" : "0.0.0";
|
|
33938
34079
|
const server = new McpServer({ name: "gitlab", version: version2 });
|
|
33939
34080
|
adaptToolsToMcp(server, allTools);
|
|
33940
34081
|
const transport = new StdioServerTransport();
|