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
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gitlab-mcp",
"description": "GitLab MCP server with GraphQL discovery and team activity tools",
"version": "1.15.1",
"version": "1.15.2",
"icon": "assets/logo.svg",
"author": {
"name": "Tim Pearson"
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,17 @@ jobs:
# for a short-lived registry token at publish time.
run: npm publish --access public --provenance

- name: Create GitHub Release
- name: Build MCPB bundle
run: node scripts/build-mcpb.mjs

- name: Create GitHub Release with MCPB asset
env:
GH_TOKEN: ${{ github.token }}
run: gh release create ${{ github.ref_name }} --generate-notes
run: |
VERSION="${GITHUB_REF_NAME#v}"
gh release create "${GITHUB_REF_NAME}" \
--generate-notes \
"gitlab-mcp-community-${VERSION}.mcpb#GitLab (community, read-only) — Claude Desktop / MCPB bundle"

docker:
name: Build and push container image
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
node_modules/
dist/
dist-mcpb/
*.mcpb
docs/superpowers/
.env
.env.local
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.15.2] - 2026-05-07

### Added

- MCPB (Claude Desktop / MCP Bundle) build. `npm run build:mcpb`
produces `gitlab-mcp-community-${VERSION}.mcpb` — a self-contained
zip with `manifest.json` + pruned `node_modules/`. The Release
workflow now attaches the bundle to each GitHub Release alongside
the existing npm and GHCR artifacts, so users can install via
one-click drag-and-drop into Claude Desktop. The bundle ships as
**read-only** (`GITLAB_READ_TOKEN` only) and is labeled
"GitLab (community, read-only)" to disambiguate from GitLab Inc.'s
first-party MCP server. Users who need write access should install
via npm or GHCR.

## [1.15.1] - 2026-05-07

### Fixed
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,15 @@ npm install -g @ttpears/gitlab-mcp-server

### Claude Desktop

Add to `claude_desktop_config.json`:
**Option A — MCPB one-click install (read-only):** download
`gitlab-mcp-community-${VERSION}.mcpb` from the
[latest GitHub Release](https://github.com/ttpears/gitlab-mcp/releases/latest)
and drag it onto the Claude Desktop window. Fill in your GitLab URL and a
read-only PAT (`read_api` scope) when prompted; the token is stored in your
OS keychain. This bundle is intentionally read-only — use Option B if you need
to create/update issues or MRs.

**Option B — manual config (read or write):** add to `claude_desktop_config.json`:

```json
{
Expand Down
48 changes: 48 additions & 0 deletions mcpb/manifest.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"manifest_version": "0.3",
"name": "gitlab-mcp-community",
"display_name": "GitLab (community, read-only)",
"version": "__VERSION__",
"description": "Community GitLab MCP server with GraphQL discovery and team-activity analytics. Read-only build. Not affiliated with GitLab Inc.'s first-party MCP server.",
"author": {
"name": "Tim Pearson",
"url": "https://github.com/ttpears/gitlab-mcp"
},
"homepage": "https://github.com/ttpears/gitlab-mcp",
"repository": {
"type": "git",
"url": "https://github.com/ttpears/gitlab-mcp"
},
"license": "MIT",
"keywords": ["mcp", "gitlab", "graphql", "community"],
"server": {
"type": "node",
"entry_point": "node_modules/@ttpears/gitlab-mcp-server/dist/index.js",
"mcp_config": {
"command": "node",
"args": [
"${__dirname}/node_modules/@ttpears/gitlab-mcp-server/dist/index.js"
],
"env": {
"GITLAB_URL": "${user_config.gitlab_url}",
"GITLAB_READ_TOKEN": "${user_config.gitlab_read_token}"
}
}
},
"user_config": {
"gitlab_url": {
"type": "string",
"title": "GitLab URL",
"description": "Base URL of your GitLab instance (e.g. https://gitlab.com or your self-hosted host).",
"default": "https://gitlab.com",
"required": true
},
"gitlab_read_token": {
"type": "string",
"title": "GitLab Read-Only PAT",
"description": "Personal access token with read_api scope. Stored in your OS keychain. Writes (create_issue, create_merge_request, etc.) will be rejected by this bundle — install via npm/GHCR if you need write access.",
"sensitive": true,
"required": true
}
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "@ttpears/gitlab-mcp-server",
"version": "1.15.1",
"version": "1.15.2",
"description": "GitLab MCP Server with GraphQL discovery",
"main": "dist/index.js",
"module": "./src/index.ts",
"type": "module",
"scripts": {
"build": "tsc && chmod +x dist/index.js",
"build:mcpb": "npm run build && node scripts/build-mcpb.mjs",
"dev": "tsx src/index.ts",
"start": "node dist/index.js",
"test": "jest",
Expand Down
47 changes: 47 additions & 0 deletions scripts/build-mcpb.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env node
import { execSync } from 'node:child_process';
import { mkdirSync, rmSync, readFileSync, writeFileSync, existsSync, unlinkSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const pkg = JSON.parse(readFileSync(resolve(repoRoot, 'package.json'), 'utf8'));
const version = pkg.version;
const stageDir = resolve(repoRoot, 'dist-mcpb');
const bundleName = `gitlab-mcp-community-${version}.mcpb`;
const bundlePath = resolve(repoRoot, bundleName);

const run = (cmd, opts = {}) =>
execSync(cmd, { cwd: repoRoot, stdio: 'inherit', ...opts });

rmSync(stageDir, { recursive: true, force: true });
if (existsSync(bundlePath)) unlinkSync(bundlePath);
mkdirSync(stageDir, { recursive: true });

const tarball = execSync('npm pack --silent', { cwd: repoRoot, encoding: 'utf8' }).trim();
const tarballPath = resolve(repoRoot, tarball);

try {
run(
`npm install --prefix "${stageDir}" --omit=dev --no-audit --no-fund --no-package-lock --ignore-scripts "${tarballPath}"`
);
} finally {
if (existsSync(tarballPath)) unlinkSync(tarballPath);
}

// Drop the install scaffold (package.json/lock) — we only ship manifest + node_modules.
for (const f of ['package.json', 'package-lock.json']) {
const p = resolve(stageDir, f);
if (existsSync(p)) unlinkSync(p);
}

const manifestTemplate = JSON.parse(
readFileSync(resolve(repoRoot, 'mcpb/manifest.template.json'), 'utf8')
);
manifestTemplate.version = version;
writeFileSync(resolve(stageDir, 'manifest.json'), JSON.stringify(manifestTemplate, null, 2) + '\n');

run(`zip -qr "${bundlePath}" manifest.json node_modules`, { cwd: stageDir });

const sizeMb = (execSync(`stat -c %s "${bundlePath}"`, { encoding: 'utf8' }).trim() / 1024 / 1024).toFixed(2);
console.log(`Built ${bundleName} (${sizeMb} MB)`);
Loading