Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,11 @@ jobs:
# Only the committed dynamic artifacts. .semantic-release-version is a
# release-time-only file and must not be committed. The root
# package.json (../../) carries the mirrored release version.
git add package.json README.md server.json ../../package.json
# prepare-release.sh renders the README to all three shipping locations
# (core npm page, GitHub repo landing, db npm page) -- stage every one so
# the public counts/version never drift between them. Missing the root and
# db READMEs here previously left them stuck a release behind the core page.
git add package.json README.md server.json ../../README.md ../../package.json ../gitlab-mcp-db/README.md
if git diff --cached --quiet; then
echo "No metadata drift; nothing to commit."
else
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Advanced GitLab MCP server — 58 CQRS tools exposing 230 GitLab operations across 26 entity types. The tool catalog and parameters are filtered to each instance's GitLab version, tier, and token scopes, so the agent sees only what the connected instance actually supports.

[![Install in Claude Desktop](https://img.shields.io/badge/Claude_Desktop-Install_Extension-F97316?style=for-the-badge)](https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-9.0.0.mcpb)
[![Install in Claude Desktop](https://img.shields.io/badge/Claude_Desktop-Install_Extension-F97316?style=for-the-badge)](https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-9.1.0.mcpb)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_MCP_Server-007ACC?style=for-the-badge&logo=visualstudiocode&logoColor=white)](vscode:mcp/install?%7B%22name%22%3A%22gitlab-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40structured-world%2Fgitlab-mcp%22%5D%7D)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_MCP_Server-24bfa5?style=for-the-badge&logo=visualstudiocode&logoColor=white)](vscode-insiders:mcp/install?%7B%22name%22%3A%22gitlab-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40structured-world%2Fgitlab-mcp%22%5D%7D)

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"@hono/node-server": "1.19.14",
"diff": "4.0.4",
"esbuild": ">=0.28.1",
"tmp": ">=0.2.7"
"tmp": ">=0.2.7",
"form-data": "^4.0.6"
},
"scripts": {
"build": "nx run-many -t build",
Expand Down
2 changes: 1 addition & 1 deletion packages/gitlab-mcp-db/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Advanced GitLab MCP server — 58 CQRS tools exposing 230 GitLab operations across 26 entity types. The tool catalog and parameters are filtered to each instance's GitLab version, tier, and token scopes, so the agent sees only what the connected instance actually supports.

[![Install in Claude Desktop](https://img.shields.io/badge/Claude_Desktop-Install_Extension-F97316?style=for-the-badge)](https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-9.0.0.mcpb)
[![Install in Claude Desktop](https://img.shields.io/badge/Claude_Desktop-Install_Extension-F97316?style=for-the-badge)](https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-9.1.0.mcpb)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_MCP_Server-007ACC?style=for-the-badge&logo=visualstudiocode&logoColor=white)](vscode:mcp/install?%7B%22name%22%3A%22gitlab-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40structured-world%2Fgitlab-mcp%22%5D%7D)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_MCP_Server-24bfa5?style=for-the-badge&logo=visualstudiocode&logoColor=white)](vscode-insiders:mcp/install?%7B%22name%22%3A%22gitlab-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40structured-world%2Fgitlab-mcp%22%5D%7D)

Expand Down
2 changes: 1 addition & 1 deletion packages/gitlab-mcp-db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"devDependencies": {
"@structured-world/gitlab-mcp": "workspace:^",
"@types/jest": "^30.0.0",
"@types/node": "^25.9.3",
"@types/node": "^25.9.4",
"jest": "^30.4.2",
"ts-jest": "^29.4.11",
"typescript": "^6.0.3"
Expand Down
10 changes: 5 additions & 5 deletions packages/gitlab-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -558,11 +558,11 @@
"build:mcpb": "./scripts/build-mcpb.sh"
},
"dependencies": {
"@clack/prompts": "^1.5.1",
"@clack/prompts": "^1.6.0",
"@modelcontextprotocol/sdk": "^1.29.0",
"express": "^5.2.1",
"graphql": "^16.14.2",
"graphql-tag": "^2.12.6",
"graphql": "^17.0.0",
"graphql-tag": "^2.12.7",
"open": "^11.0.0",
"picomatch": "^4.0.4",
"pino": "^10.3.1",
Expand All @@ -574,13 +574,13 @@
"zod": "^4.4.3"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260616.1",
"@cloudflare/workers-types": "^4.20260621.1",
"@eslint/js": "^10.0.1",
"@graphql-typed-document-node/core": "^3.2.0",
"@structured-world/vue-privacy": "^1.10.0",
"@types/express": "^5.0.6",
"@types/jest": "^30.0.0",
"@types/node": "^25.9.3",
"@types/node": "^25.9.4",
"@types/picomatch": "^4.0.3",
"@typescript-eslint/eslint-plugin": "^8.61.1",
"@typescript-eslint/parser": "^8.61.1",
Expand Down
10 changes: 7 additions & 3 deletions packages/gitlab-mcp/scripts/prepare-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ fi

echo "prepare-release: v${VERSION}, ${TOOL_COUNT} tools (${READONLY_TOOL_COUNT} read-only, ${ACTION_COUNT} actions), ${ENTITY_COUNT} entities"

# Update server.json: version + description
# Update server.json: version + description.
# The description is the public marketing line shown on the MCP Registry listing,
# so it mirrors the README hero sentence (tools / operations / entity types) instead
# of a generic blurb. The MCP Registry schema caps description at 100 chars; this
# phrasing stays well under that even with 3-digit counts.
# Note: set -e ensures script exits on jq failure; leftover server.tmp is benign
# (gitignored, cleaned by next successful run, doesn't affect release)
jq --arg v "$VERSION" --arg tc "$TOOL_COUNT" \
'.version = $v | .packages[0].version = $v | .description = "GitLab MCP server with " + $tc + " tools for projects, MRs, pipelines, and more"' \
jq --arg v "$VERSION" --arg tc "$TOOL_COUNT" --arg ac "$ACTION_COUNT" --arg ec "$ENTITY_COUNT" \
'.version = $v | .packages[0].version = $v | .description = $tc + " CQRS tools exposing " + $ac + " GitLab operations across " + $ec + " entity types"' \
server.json > server.tmp && mv server.tmp server.json

# Generate README.md from the template for each location it ships to. __REPO_BASE__
Expand Down
2 changes: 1 addition & 1 deletion packages/gitlab-mcp/server.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"$comment": "Schema version 2025-12-11 is the current MCP Registry standard. Only essential env vars are exposed here; USE_* feature flags are documented at websiteUrl and available via MCPB toggles.",
"name": "io.github.structured-world/gitlab-mcp",
"title": "Advanced GitLab MCP server",
"description": "GitLab MCP server with 58 tools for projects, MRs, pipelines, and more",
"description": "58 CQRS tools exposing 230 GitLab operations across 26 entity types",
"websiteUrl": "https://gitlab-mcp.sw.foundation",
"repository": {
"url": "https://github.com/structured-world/gitlab-mcp",
Expand Down
32 changes: 17 additions & 15 deletions packages/gitlab-mcp/src/entities/runners/schema-readonly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,24 @@ const ListRunnerJobsSchema = z.object({
action: z.literal('list_jobs').describe('List jobs that have run on a runner'),
runner_id: runnerIdField,
statuses: z
.enum([
'CREATED',
'PENDING',
'RUNNING',
'FAILED',
'SUCCESS',
'CANCELED',
'SKIPPED',
'MANUAL',
'SCHEDULED',
'WAITING_FOR_RESOURCE',
'PREPARING',
'CANCELING',
])
.array(
z.enum([
'CREATED',
'PENDING',
'RUNNING',
'FAILED',
'SUCCESS',
'CANCELED',
'SKIPPED',
'MANUAL',
'SCHEDULED',
'WAITING_FOR_RESOURCE',
'PREPARING',
'CANCELING',
]),
)
.optional()
.describe('Filter jobs by status'),
.describe('Filter jobs by one or more statuses (e.g. ["FAILED", "CANCELED"])'),
first: firstField,
after: afterField,
});
Expand Down
4 changes: 2 additions & 2 deletions packages/gitlab-mcp/src/graphql/runners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,12 @@ export interface ListRunnerJobsResult {
}
export interface ListRunnerJobsVars {
id: string;
statuses?: string | null;
statuses?: string[] | null;
first?: number | null;
after?: string | null;
}
export const LIST_RUNNER_JOBS: TypedDocumentNode<ListRunnerJobsResult, ListRunnerJobsVars> = gql`
query ListRunnerJobs($id: CiRunnerID!, $statuses: CiJobStatus, $first: Int, $after: String) {
query ListRunnerJobs($id: CiRunnerID!, $statuses: [CiJobStatus!], $first: Int, $after: String) {
runner(id: $id) {
id
jobs(statuses: $statuses, first: $first, after: $after) {
Expand Down
12 changes: 10 additions & 2 deletions packages/gitlab-mcp/tests/unit/entities/runners/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,18 @@ describe('runners registry', () => {

it('list_jobs queries the runner jobs connection', async () => {
mockClient.request.mockResolvedValueOnce({ runner: { id: RUNNER_GID, jobs: { nodes: [] } } });
await browse().handler({ action: 'list_jobs', runner_id: 7, statuses: 'FAILED' });
await browse().handler({
action: 'list_jobs',
runner_id: 7,
statuses: ['FAILED', 'CANCELED'],
});
const [doc, vars] = mockClient.request.mock.calls[0];
expect(doc).toBe(LIST_RUNNER_JOBS);
expect(vars).toMatchObject({ id: RUNNER_GID, statuses: 'FAILED' });
// GitLab's jobs(statuses:) argument is [CiJobStatus!]; the schema takes a
// list so callers can filter by several statuses at once. Declaring the
// variable as a bare enum made GitLab reject the query with
// "List dimension mismatch on variable $statuses".
expect(vars).toMatchObject({ id: RUNNER_GID, statuses: ['FAILED', 'CANCELED'] });
});

it('list_jobs throws when the runner is missing', async () => {
Expand Down
87 changes: 48 additions & 39 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,13 @@ __metadata:
languageName: node
linkType: hard

"@clack/core@npm:1.4.1":
version: 1.4.1
resolution: "@clack/core@npm:1.4.1"
"@clack/core@npm:1.4.2":
version: 1.4.2
resolution: "@clack/core@npm:1.4.2"
dependencies:
fast-wrap-ansi: "npm:^0.2.0"
sisteransi: "npm:^1.0.5"
checksum: 10c0/7e7e02f0c423c457aff9acc09f9ffbae3d2841b18f543c614b5b8eaa2c11c9f146bf68b3078d1daa4dea9d3131ccfa514edbe8d29ced18446933567188b2543c
checksum: 10c0/390a0c650dbd4c406029e32fd6a0b704bad3a172cab96e77989a1d376ddeee5f4b0500edb093375b202ae35acfc94fbd2fb11fe3ad9e47724acae4b7ff1d68b6
languageName: node
linkType: hard

Expand All @@ -471,22 +471,22 @@ __metadata:
languageName: node
linkType: hard

"@clack/prompts@npm:^1.5.1":
version: 1.5.1
resolution: "@clack/prompts@npm:1.5.1"
"@clack/prompts@npm:^1.6.0":
version: 1.6.0
resolution: "@clack/prompts@npm:1.6.0"
dependencies:
"@clack/core": "npm:1.4.1"
"@clack/core": "npm:1.4.2"
fast-string-width: "npm:^3.0.2"
fast-wrap-ansi: "npm:^0.2.0"
sisteransi: "npm:^1.0.5"
checksum: 10c0/423b1958d28a25703130c2dd6a236413d210446fd36e980dcf106f9165e5c579494214aaca5185269e918488c6d4f93c4de44a7dc5f902add8874486b2624c22
checksum: 10c0/b288a1085ce75a06a739f4907b38187d9b3121a53e4a86541383df3e2348276fa00903a5d2220d7b2c821a55b81ad11af9cadb3760e3212dac27fe2001555ab1
languageName: node
linkType: hard

"@cloudflare/workers-types@npm:^4.20260616.1":
version: 4.20260616.1
resolution: "@cloudflare/workers-types@npm:4.20260616.1"
checksum: 10c0/ce02ec49826740e35de0c22c45b4fe18e819a890c26c17261f81a1de5f7b7e59824182bff4775ce50b6614d5cd468d1b1393b76956467404ba62f69aaa3305d8
"@cloudflare/workers-types@npm:^4.20260621.1":
version: 4.20260621.1
resolution: "@cloudflare/workers-types@npm:4.20260621.1"
checksum: 10c0/5f220aa5feff5b4e20dc549b82f80740c0daa25cb001e8d8a5aac51ab2aba1123096276ec880887c6fd37cc396beb43ebe4ab3c23ae32d31993fa2230c1e4ed7
languageName: node
linkType: hard

Expand Down Expand Up @@ -2136,7 +2136,7 @@ __metadata:
"@prisma/client": "npm:^7.8.0"
"@structured-world/gitlab-mcp": "workspace:^"
"@types/jest": "npm:^30.0.0"
"@types/node": "npm:^25.9.3"
"@types/node": "npm:^25.9.4"
jest: "npm:^30.4.2"
prisma: "npm:^7.8.0"
ts-jest: "npm:^29.4.11"
Expand All @@ -2148,15 +2148,15 @@ __metadata:
version: 0.0.0-use.local
resolution: "@structured-world/gitlab-mcp@workspace:packages/gitlab-mcp"
dependencies:
"@clack/prompts": "npm:^1.5.1"
"@cloudflare/workers-types": "npm:^4.20260616.1"
"@clack/prompts": "npm:^1.6.0"
"@cloudflare/workers-types": "npm:^4.20260621.1"
"@eslint/js": "npm:^10.0.1"
"@graphql-typed-document-node/core": "npm:^3.2.0"
"@modelcontextprotocol/sdk": "npm:^1.29.0"
"@structured-world/vue-privacy": "npm:^1.10.0"
"@types/express": "npm:^5.0.6"
"@types/jest": "npm:^30.0.0"
"@types/node": "npm:^25.9.3"
"@types/node": "npm:^25.9.4"
"@types/picomatch": "npm:^4.0.3"
"@typescript-eslint/eslint-plugin": "npm:^8.61.1"
"@typescript-eslint/parser": "npm:^8.61.1"
Expand All @@ -2166,8 +2166,8 @@ __metadata:
eslint: "npm:^10.5.0"
eslint-plugin-prettier: "npm:^5.5.6"
express: "npm:^5.2.1"
graphql: "npm:^16.14.2"
graphql-tag: "npm:^2.12.6"
graphql: "npm:^17.0.0"
graphql-tag: "npm:^2.12.7"
jest: "npm:^30.4.2"
open: "npm:^11.0.0"
picomatch: "npm:^4.0.4"
Expand Down Expand Up @@ -2460,12 +2460,12 @@ __metadata:
languageName: node
linkType: hard

"@types/node@npm:^25.9.3":
version: 25.9.3
resolution: "@types/node@npm:25.9.3"
"@types/node@npm:^25.9.4":
version: 25.9.4
resolution: "@types/node@npm:25.9.4"
dependencies:
undici-types: "npm:>=7.24.0 <7.24.7"
checksum: 10c0/72d3aece9d42c2c641bcd3f3cb2dc2828b4bd384dfcbd910c404b8859a68bd69d50c4769ce7defd4ff5e049768e23e615f09407ea2cbbb5f44b90d75a7c6b8ca
checksum: 10c0/4b19670ef5dbefa836a2d4a9ed0b5ac6befbc0844bfdd12833234ff8fa68da1f65e6362d2ef87acf7e7da9d6ff649bf81c454d12e802b7e7fa9246a15c0edcf6
languageName: node
linkType: hard

Expand Down Expand Up @@ -4953,16 +4953,16 @@ __metadata:
languageName: node
linkType: hard

"form-data@npm:4.0.5, form-data@npm:^4.0.5":
version: 4.0.5
resolution: "form-data@npm:4.0.5"
"form-data@npm:^4.0.6":
version: 4.0.6
resolution: "form-data@npm:4.0.6"
dependencies:
asynckit: "npm:^0.4.0"
combined-stream: "npm:^1.0.8"
es-set-tostringtag: "npm:^2.1.0"
hasown: "npm:^2.0.2"
mime-types: "npm:^2.1.12"
checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b
hasown: "npm:^2.0.4"
mime-types: "npm:^2.1.35"
checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff
languageName: node
linkType: hard

Expand Down Expand Up @@ -5224,21 +5224,21 @@ __metadata:
languageName: node
linkType: hard

"graphql-tag@npm:^2.12.6":
version: 2.12.6
resolution: "graphql-tag@npm:2.12.6"
"graphql-tag@npm:^2.12.7":
version: 2.12.7
resolution: "graphql-tag@npm:2.12.7"
dependencies:
tslib: "npm:^2.1.0"
peerDependencies:
graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
checksum: 10c0/7763a72011bda454ed8ff1a0d82325f43ca6478e4ce4ab8b7910c4c651dd00db553132171c04d80af5d5aebf1ef6a8a9fd53ccfa33b90ddc00aa3d4be6114419
graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
checksum: 10c0/c5b973b6b0477d3f734a0df7ebea2061790e268774d7fea310fde64820c1686c3b43f3e7262e4224d689917f42ae8e84c67f32772c003c308d38896ed960c5ec
languageName: node
linkType: hard

"graphql@npm:^16.14.2":
version: 16.14.2
resolution: "graphql@npm:16.14.2"
checksum: 10c0/a95a96961eaff55cc9fe9d31fae6f33499ac988b972d07ea5085024cb1333f515b902f376e7393a5489aa82200a8aff3eb96580e4d1b69d702ed19b6eb1ce97a
"graphql@npm:^17.0.0":
version: 17.0.1
resolution: "graphql@npm:17.0.1"
checksum: 10c0/95e4766eefa97bbc37cb4452527d24e12068f170e03c564611a3911f30a77361dfcfbdbfeea00f643c82585c02312c1f41ba6a6263049996d279c49951454980
languageName: node
linkType: hard

Expand Down Expand Up @@ -5292,6 +5292,15 @@ __metadata:
languageName: node
linkType: hard

"hasown@npm:^2.0.4":
version: 2.0.4
resolution: "hasown@npm:2.0.4"
dependencies:
function-bind: "npm:^1.1.2"
checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506
languageName: node
linkType: hard

"hast-util-to-html@npm:^9.0.5":
version: 9.0.5
resolution: "hast-util-to-html@npm:9.0.5"
Expand Down Expand Up @@ -6631,7 +6640,7 @@ __metadata:
languageName: node
linkType: hard

"mime-types@npm:2.1.35, mime-types@npm:^2.1.12":
"mime-types@npm:2.1.35, mime-types@npm:^2.1.35":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
Expand Down
Loading