@zereight/mcp-gitlab 2.1.25 → 2.1.27

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,62 @@
1
+ function getLastHeaderValue(value) {
2
+ const raw = Array.isArray(value) ? value[value.length - 1] : value;
3
+ if (!raw)
4
+ return undefined;
5
+ const parts = raw.split(",").map(part => part.trim()).filter(Boolean);
6
+ return parts.length > 0 ? parts[parts.length - 1] : undefined;
7
+ }
8
+ function unquoteHeaderValue(value) {
9
+ if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
10
+ return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
11
+ }
12
+ return value;
13
+ }
14
+ function trimTrailingSlashes(value) {
15
+ let end = value.length;
16
+ while (end > 0 && value[end - 1] === "/")
17
+ end--;
18
+ return value.slice(0, end);
19
+ }
20
+ export function getForwardedPublicBaseUrl(req, trustProxy) {
21
+ if (!trustProxy)
22
+ return undefined;
23
+ const forwarded = getLastHeaderValue(req.headers.forwarded);
24
+ const forwardedValues = {};
25
+ if (forwarded) {
26
+ for (const part of forwarded.split(";")) {
27
+ const separator = part.indexOf("=");
28
+ if (separator <= 0)
29
+ continue;
30
+ const key = part.slice(0, separator).trim().toLowerCase();
31
+ const value = unquoteHeaderValue(part.slice(separator + 1).trim());
32
+ if (key && value)
33
+ forwardedValues[key] = value;
34
+ }
35
+ }
36
+ const proto = (forwardedValues.proto || getLastHeaderValue(req.headers["x-forwarded-proto"]))?.toLowerCase();
37
+ const host = forwardedValues.host || getLastHeaderValue(req.headers["x-forwarded-host"]);
38
+ if (!proto || !host || !/^https?$/.test(proto))
39
+ return undefined;
40
+ if (/[\s/\\]/.test(host))
41
+ return undefined;
42
+ const prefix = getLastHeaderValue(req.headers["x-forwarded-prefix"]);
43
+ const safePrefix = prefix &&
44
+ prefix.startsWith("/") &&
45
+ !prefix.startsWith("//") &&
46
+ !prefix.includes("://") &&
47
+ !/[\s\\]/.test(prefix)
48
+ ? trimTrailingSlashes(prefix)
49
+ : undefined;
50
+ try {
51
+ const baseUrl = new URL(`${proto}://${host}`);
52
+ if (baseUrl.username || baseUrl.password || baseUrl.pathname !== "/" || baseUrl.search || baseUrl.hash) {
53
+ return undefined;
54
+ }
55
+ if (safePrefix)
56
+ baseUrl.pathname = safePrefix;
57
+ return baseUrl.toString().replace(/\/$/, "");
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ }
@@ -86,5 +86,19 @@ export const toJSONSchema = (schema) => {
86
86
  }
87
87
  return obj;
88
88
  }
89
- return fixNullableOptional(jsonSchema, true);
89
+ const fixedSchema = fixNullableOptional(jsonSchema, true);
90
+ if (!fixedSchema.properties && Array.isArray(fixedSchema.anyOf)) {
91
+ const variants = fixedSchema.anyOf.filter((item) => item?.type === "object" && item.properties);
92
+ if (variants.length === fixedSchema.anyOf.length) {
93
+ fixedSchema.type = "object";
94
+ fixedSchema.properties = variants.reduce((properties, item) => {
95
+ Object.entries(item.properties).forEach(([key, value]) => {
96
+ if (!properties[key])
97
+ properties[key] = value;
98
+ });
99
+ return properties;
100
+ }, {});
101
+ }
102
+ }
103
+ return fixedSchema;
90
104
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.1.25",
3
+ "version": "2.1.27",
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": [
@@ -51,7 +51,7 @@
51
51
  "changelog": "auto-changelog -p",
52
52
  "test": "npm run test:all",
53
53
  "test:all": "npm run build && npm run test:mock && npm run test:live",
54
- "test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && node --import tsx/esm --test test/test-oauth-proxy-rate-limit.ts && node --import tsx/esm --test test/streamable-http-static-token-auth.test.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-issues.ts && node --import tsx/esm --test test/test-merge-request-pipelines.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-upload-markdown.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-remote-downloads.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-protected-branches.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-ci-lint.ts && node --import tsx/esm --test test/test-todos.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/test-issue-description-patch.ts && node --import tsx/esm --test test/test-geteffectiveprojectid.ts && node --import tsx/esm --test test/test-get-file-blame.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts && node --import tsx/esm --test test/utils/tool-args.test.ts && node --import tsx/esm --test test/utils/proxy-client-ip.test.ts && node --import tsx/esm --test test/utils/graphql-query.test.ts && node --import tsx/esm --test test/utils/wiki-title.test.ts && node --import tsx/esm --test test/utils/merge-request-position.test.ts && node --import tsx/esm --test test/nullish-tool-arguments-schema.test.ts && node --import tsx/esm --test test/test-ci-variables.ts && node --import tsx/esm --test test/test-dependency-proxy.ts",
54
+ "test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/dynamic-api-url-allowlist.test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && node --import tsx/esm --test test/test-oauth-proxy-rate-limit.ts && node --import tsx/esm --test test/streamable-http-static-token-auth.test.ts && node --import tsx/esm --test test/sse-auth-guard.test.ts && node --import tsx/esm --test test/streamable-http-concurrent-session.test.ts && node --import tsx/esm --test test/streamable-http-unauthenticated-discovery.test.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-issues.ts && node --import tsx/esm --test test/test-create-repository.ts && node --import tsx/esm --test test/test-update-project.ts && node --import tsx/esm --test test/test-merge-request-pipelines.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-upload-markdown.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-remote-downloads.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-protected-branches.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-ci-lint.ts && node --import tsx/esm --test test/test-ci-catalog.ts && node --import tsx/esm --test test/test-todos.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/test-issue-description-patch.ts && node --import tsx/esm --test test/test-geteffectiveprojectid.ts && node --import tsx/esm --test test/test-get-file-blame.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts && node --import tsx/esm --test test/utils/tool-args.test.ts && node --import tsx/esm --test test/utils/proxy-client-ip.test.ts && node --import tsx/esm --test test/utils/forwarded-public-base-url.test.ts && node --import tsx/esm --test test/utils/graphql-query.test.ts && node --import tsx/esm --test test/utils/wiki-title.test.ts && node --import tsx/esm --test test/utils/merge-request-position.test.ts && node --import tsx/esm --test test/nullish-tool-arguments-schema.test.ts && node --import tsx/esm --test test/test-ci-variables.ts && node --import tsx/esm --test test/test-dependency-proxy.ts",
55
55
  "test:stateless": "npm run build && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
56
56
  "test:mcp-oauth": "npm run build && node --import tsx/esm --test test/mcp-oauth-tests.ts",
57
57
  "test:live": "node test/validate-api.js",