-
Notifications
You must be signed in to change notification settings - Fork 1
feat(cli): Interactive setup wizard (gitlab-mcp init) #62
Description
Summary
Add interactive setup wizard (gitlab-mcp init) for streamlined onboarding with support for PAT, OAuth, Docker deployment, and one-click Claude integration via Deep Links.
Motivation
Current setup requires:
- Reading documentation
- Finding token creation page
- Creating token with correct scopes
- Manually configuring environment variables
- Copying JSON config to MCP client
- Restarting MCP client
This takes 15-30 minutes and is error-prone. The wizard reduces this to ~2 minutes.
Deep Links reduce web-based setup to seconds.
MCP Client Configuration Paths
Research of popular MCP clients and their configuration methods:
| Client | Config Path | Format | Transport |
|---|---|---|---|
| Claude Desktop | macOS: ~/Library/Application Support/Claude/claude_desktop_config.jsonWindows: %APPDATA%\Claude\claude_desktop_config.json |
JSON | stdio, SSE, HTTP |
| Claude Code | CLI: claude mcp add <name> <command> [args...] |
CLI | stdio, SSE |
| Cursor | Global: ~/.cursor/mcp.jsonProject: .cursor/mcp.json |
JSON | stdio, SSE, HTTP |
| VS Code Copilot | .vscode/mcp.json |
JSON | stdio |
| Cline | GUI → cline_mcp_settings.json |
JSON | stdio, SSE |
| Roo Code | Global: mcp_settings.jsonProject: .roo/mcp.json |
JSON | stdio |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
JSON | stdio |
| JetBrains | Settings → Tools → AI Assistant → MCP | JSON | stdio, HTTP |
| Zed | Extensions / Command Palette | JSON | stdio |
| Codex | ~/.codex/config.toml |
TOML | stdio |
Key Findings
- 90% of clients use identical
mcpServersJSON format - Claude Code supports CLI-based setup via
claude mcp add - Deep Links - Claude Desktop supports
claude://settings/mcp/add?config=BASE64 - Project-level configs - Cursor (
.cursor/), Roo Code (.roo/), VS Code (.vscode/) - Env interpolation - Cursor supports
${env:VAR},${workspaceFolder}
NEW: One-Click Deploy Methods
Claude Code CLI Integration
Claude Code supports adding MCP servers directly via CLI:
# Add gitlab-mcp to Claude Code
claude mcp add gitlab-mcp npx @structured-world/gitlab-mcp stdio
# With environment variables
claude mcp add gitlab-mcp \
-e GITLAB_API_URL=https://gitlab.com \
-e GITLAB_TOKEN=glpat-xxx \
npx @structured-world/gitlab-mcp stdio
# With preset
claude mcp add gitlab-mcp npx @structured-world/gitlab-mcp stdio --preset developerImplementation for gitlab-mcp install --claude-code
// src/cli/commands/install.ts
import { execSync } from "child_process";
export async function installClaudeCode(options: {
host: string;
token?: string;
preset?: string;
}) {
const args = [
"npx",
"@structured-world/gitlab-mcp",
"stdio",
...(options.preset ? ["--preset", options.preset] : []),
];
const envArgs: string[] = [];
envArgs.push("-e", `GITLAB_API_URL=${options.host}`);
if (options.token) {
envArgs.push("-e", `GITLAB_TOKEN=${options.token}`);
}
const cmd = `claude mcp add gitlab-mcp ${envArgs.join(" ")} ${args.join(" ")}`;
try {
execSync(cmd, { stdio: "inherit" });
console.log("✓ GitLab MCP added to Claude Code");
} catch {
console.log("Claude Code CLI not found. Install with: npm i -g @anthropic-ai/claude-code");
}
}Claude Desktop Deep Link
Claude Desktop supports claude:// protocol for adding MCP servers:
claude://settings/mcp/add?config=BASE64_ENCODED_CONFIG
Implementation
// src/cli/utils/deep-link.ts
interface McpServerConfig {
command: string;
args: string[];
env?: Record<string, string>;
}
function generateClaudeDeepLink(config: McpServerConfig): string {
const configJson = JSON.stringify({
mcpServers: {
gitlab: config
}
});
const base64 = Buffer.from(configJson).toString('base64url');
return `claude://settings/mcp/add?config=${base64}`;
}
// Usage
const deepLink = generateClaudeDeepLink({
command: 'npx',
args: ['@structured-world/gitlab-mcp', 'stdio'],
env: {
GITLAB_API_URL: 'https://gitlab.com',
GITLAB_TOKEN: '${GITLAB_TOKEN}' // Placeholder
}
});Web Landing Page
Create a simple landing page at gitlab-mcp.sw.foundation/setup:
<!DOCTYPE html>
<html>
<head>
<title>GitLab MCP - One-Click Setup</title>
</head>
<body>
<h1>Add GitLab MCP to Claude</h1>
<div class="setup-options">
<!-- Option 1: gitlab.com -->
<div class="option">
<h3>gitlab.com (Public)</h3>
<p>For personal projects on gitlab.com</p>
<a href="claude://settings/mcp/add?config=..." class="btn">
Add to Claude Desktop
</a>
</div>
<!-- Option 2: Self-hosted -->
<div class="option">
<h3>Self-Hosted GitLab</h3>
<form id="self-hosted-form">
<input type="url" placeholder="https://gitlab.company.com" id="host">
<button type="submit">Generate Link</button>
</form>
<a href="#" id="self-hosted-link" class="btn hidden">
Add to Claude Desktop
</a>
</div>
</div>
<h2>After Adding</h2>
<ol>
<li>Set your GitLab token: <code>export GITLAB_TOKEN=glpat-xxx</code></li>
<li>Restart Claude Desktop</li>
<li>Ask Claude: "List my GitLab projects"</li>
</ol>
</body>
</html>README Badge
[](https://gitlab-mcp.sw.foundation/setup)NPX One-Liner with Deep Link
# Generate and open deep link
npx @structured-world/gitlab-mcp setup --claude-link
# Output:
# Opening Claude Desktop with GitLab MCP configuration...
#
# If browser didn't open, copy this link:
# claude://settings/mcp/add?config=eyJtY3BTZXJ2ZXJz...
#
# After adding:
# 1. Set GITLAB_TOKEN environment variable
# 2. Restart Claude DesktopCommands
gitlab-mcp init - Global Setup Wizard
One-time setup for connecting to GitLab.
$ gitlab-mcp init
╭─────────────────────────────────────────────────────────────╮
│ GitLab MCP Setup │
╰─────────────────────────────────────────────────────────────╯
? Where is your GitLab instance?
● gitlab.com
○ Self-hosted (enter URL)
○ Detect from current directory (.git)
? Authentication method:
● Personal Access Token (PAT) - simple, single GitLab
○ OAuth - multiple GitLabs, team sharing, persistent sessions
Opening browser to create PAT token...
→ https://gitlab.com/-/user_settings/personal_access_tokens?name=gitlab-mcp&scopes=api,read_user
? Paste your token: glpat-xxxxxxxxxxxxxxxxxxxx
? Select your role:
○ readonly - Safe exploration, no modifications
● developer - Standard development workflow
○ devops - CI/CD and infrastructure
○ admin - Full access
Testing connection... ✓ Connected as @username
? Install to MCP client?
● Claude Desktop
○ Claude Code
○ Cursor
○ VS Code
○ Cline
○ Roo Code
○ Windsurf
○ Show config only
✓ Config added to Claude Desktop
✓ Please restart Claude Desktop
Done! Try: "List my GitLab projects"gitlab-mcp init with Docker + OAuth
For multi-GitLab setups with OAuth authentication.
$ gitlab-mcp init
? Authentication method:
○ Personal Access Token (PAT)
● OAuth - multiple GitLabs, team sharing
✓ Docker detected (v24.0.7)
? How to run OAuth server?
● Docker container (recommended)
○ System service
○ Manual setup
? Port: 3333
Setting up Docker...
✓ Creating ~/.config/gitlab-mcp/docker-compose.yml
✓ Pulling ghcr.io/structured-world/gitlab-mcp:latest
✓ Starting container on localhost:3333
? Add GitLab instance:
Host: gitlab.com
Opening browser to create OAuth Application...
→ https://gitlab.com/-/admin/applications/new
Required settings:
Name: GitLab MCP (local)
Redirect URI: http://localhost:3333/auth/callback
Scopes: [x] api [x] read_user
Confidential: [x] Yes
? OAuth Client ID: abc123
? OAuth Client Secret: ****
Testing OAuth...
→ Opening http://localhost:3333/auth/login?instance=gitlab.com
✓ Logged in as @username
? Add another GitLab instance? [Y/n] y
Host: gitlab.company.com
...
╭─────────────────────────────────────────────────────────────╮
│ ✓ Setup complete! │
│ │
│ Instances: gitlab.com, gitlab.company.com │
│ Endpoint: http://localhost:3333/sse │
│ Auth: http://localhost:3333/auth │
╰─────────────────────────────────────────────────────────────╯gitlab-mcp init-project - Project Configuration
Creates .gitlab-mcp/ directory with project-specific config.
$ cd /path/to/my-project
$ gitlab-mcp init-project
Detected: [email protected]:myteam/backend.git
? Restrict scope to this project? [Y/n]
? Project type:
○ Frontend (web/mobile)
● Backend (API/services)
○ DevOps (infrastructure)
○ Library (shared code)
Creating .gitlab-mcp/
✓ preset.yaml (scope: myteam/backend)
✓ profile.yaml (extends: senior-dev, +pipelines, +variables)
? Add to .gitignore? [Y/n]gitlab-mcp doctor - Health Check
Diagnose configuration and connection issues.
$ gitlab-mcp doctor
╭─────────────────────────────────────────────────────────────╮
│ GitLab MCP Health Check │
╰─────────────────────────────────────────────────────────────╯
Configuration:
✓ Profile: work (gitlab.company.com)
✓ Preset: developer (24 tools)
✓ Project config: .gitlab-mcp/
Connection:
✓ API: https://gitlab.company.com/api/v4
✓ Token valid (expires: 2025-12-31)
✓ User: @username (Developer role)
MCP Clients:
✓ Claude Desktop - configured
✓ Claude Code - configured
✗ Cursor - not configured
Recommendations:
⚠ Token expires in 30 days
ℹ Run: gitlab-mcp install --cursorgitlab-mcp docker - Container Management
Manage Docker-based OAuth server.
gitlab-mcp docker status # Container + instances status
gitlab-mcp docker logs # Tail container logs
gitlab-mcp docker restart # Restart container
gitlab-mcp docker upgrade # Pull latest image + restart
gitlab-mcp docker stop # Stop container
gitlab-mcp docker add-instance <host> # Add GitLab instancegitlab-mcp install - MCP Client Installation
Install configuration to MCP clients.
gitlab-mcp install --claude-desktop # Claude Desktop (JSON config)
gitlab-mcp install --claude-code # Claude Code (via `claude mcp add`)
gitlab-mcp install --cursor # Cursor
gitlab-mcp install --vscode # VS Code Copilot
gitlab-mcp install --cline # Cline
gitlab-mcp install --roo-code # Roo Code
gitlab-mcp install --windsurf # Windsurf
gitlab-mcp install --all # All detected clients
gitlab-mcp install --show # Show config onlyNEW: gitlab-mcp setup - Quick Setup Commands
# Generate Claude deep link and open
gitlab-mcp setup --claude-link
# Generate deep link for specific host
gitlab-mcp setup --claude-link --host gitlab.company.com
# Output URL only (for scripts/docs)
gitlab-mcp setup --claude-link --url-only
# Generate QR code for mobile/sharing
gitlab-mcp setup --claude-link --qrImplementation
CLI Framework: @clack/prompts
Using clack for minimalist, performant CLI UX.
import * as p from '@clack/prompts';
async function init() {
p.intro('GitLab MCP Setup');
const host = await p.select({
message: 'Where is your GitLab instance?',
options: [
{ value: 'gitlab.com', label: 'gitlab.com' },
{ value: 'self-hosted', label: 'Self-hosted (enter URL)' },
{ value: 'detect', label: 'Detect from current directory' },
],
});
// ... rest of flow
}Deep Link Generator
// src/cli/utils/deep-link.ts
import open from 'open';
export function generateClaudeDeepLink(options: {
host: string;
transport?: 'stdio' | 'sse';
preset?: string;
}): string {
const { host, transport = 'stdio', preset } = options;
const config = transport === 'stdio'
? {
mcpServers: {
gitlab: {
command: 'npx',
args: [
'@structured-world/gitlab-mcp',
'stdio',
...(preset ? ['--preset', preset] : [])
],
env: {
GITLAB_API_URL: host.startsWith('http') ? host : `https://${host}`,
GITLAB_TOKEN: '${GITLAB_TOKEN}'
}
}
}
}
: {
mcpServers: {
gitlab: {
url: `http://localhost:3333/sse`
}
}
};
const base64 = Buffer.from(JSON.stringify(config)).toString('base64url');
return `claude://settings/mcp/add?config=${base64}`;
}
export async function openClaudeDeepLink(options: Parameters<typeof generateClaudeDeepLink>[0]) {
const link = generateClaudeDeepLink(options);
console.log('Opening Claude Desktop...');
console.log('');
console.log('If browser didn't open, copy this link:');
console.log(link);
await open(link);
}Docker Compose Template
# ~/.config/gitlab-mcp/docker-compose.yml
version: '3.8'
services:
gitlab-mcp:
image: ghcr.io/structured-world/gitlab-mcp:latest
container_name: gitlab-mcp
ports:
- "${PORT:-3333}:3333"
environment:
- TRANSPORT=sse
- PORT=3333
- OAUTH_ENABLED=true
- OAUTH_SESSION_SECRET=${OAUTH_SESSION_SECRET}
- DATABASE_URL=file:/data/sessions.db
volumes:
- gitlab-mcp-data:/data
- ./instances.yml:/app/config/instances.yml:ro
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3333/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
gitlab-mcp-data:Multi-Instance Configuration
# ~/.config/gitlab-mcp/instances.yml
instances:
gitlab.com:
name: "GitLab.com"
oauth:
client_id: "abc123"
client_secret_env: "GITLAB_COM_SECRET"
default_preset: "gitlab-com"
gitlab.company.com:
name: "Company GitLab"
oauth:
client_id: "xyz789"
client_secret_env: "GITLAB_COMPANY_SECRET"
default_preset: "developer"File Structure
src/
├── cli/
│ ├── index.ts # CLI entry point
│ ├── commands/
│ │ ├── init.ts # gitlab-mcp init
│ │ ├── init-project.ts # gitlab-mcp init-project
│ │ ├── doctor.ts # gitlab-mcp doctor
│ │ ├── docker.ts # gitlab-mcp docker *
│ │ ├── install.ts # gitlab-mcp install
│ │ └── setup.ts # gitlab-mcp setup (deep links)
│ ├── templates/
│ │ ├── docker-compose.yml
│ │ └── mcp-configs/
│ │ ├── claude-desktop.json
│ │ ├── cursor.json
│ │ ├── vscode.json
│ │ ├── cline.json
│ │ ├── roo-code.json
│ │ └── windsurf.json
│ └── utils/
│ ├── deep-link.ts # Claude deep link generator
│ ├── claude-code.ts # Claude Code CLI integration
│ ├── detect-docker.ts
│ ├── detect-git.ts
│ ├── open-browser.ts
│ └── mcp-client-installer.ts
├── web/ # Landing page (optional)
│ └── setup/
│ ├── index.html
│ └── setup.js
Quick Start Documentation
## Quick Setup
### One-Click (Fastest)
Click the button or visit: **[gitlab-mcp.sw.foundation/setup](https://gitlab-mcp.sw.foundation/setup)**
[](https://gitlab-mcp.sw.foundation/setup)
### Command Line
```bash
# Interactive wizard
npx @structured-world/gitlab-mcp init
# Generate Claude deep link
npx @structured-world/gitlab-mcp setup --claude-link
# Add directly to Claude Code
claude mcp add gitlab-mcp npx @structured-world/gitlab-mcp stdioOne-Liner (for scripts)
# gitlab.com + developer preset
npx @structured-world/gitlab-mcp init \
--host gitlab.com \
--preset developer \
--install claude-desktop
# Self-hosted + Docker OAuth
npx @structured-world/gitlab-mcp init \
--host gitlab.company.com \
--oauth \
--docker \
--install allLet Claude Set It Up
Ask your AI assistant:
"Setup GitLab MCP for my projects"
"Add GitLab MCP to Claude Desktop for gitlab.com"
---
## Tasks
### Phase 1: Core Wizard
- [ ] Add @clack/prompts dependency
- [ ] Implement `gitlab-mcp init` base flow
- [ ] PAT authentication flow
- [ ] Browser auto-open for token creation
- [ ] Connection testing
- [ ] Role → preset mapping
- [ ] Config file generation
### Phase 2: MCP Client Installation
- [ ] Detect installed MCP clients
- [ ] Claude Desktop config installer (JSON)
- [ ] **Claude Code installer (via `claude mcp add`)**
- [ ] Cursor config installer
- [ ] VS Code Copilot config installer
- [ ] Cline config installer
- [ ] Roo Code config installer
- [ ] Windsurf config installer
- [ ] Backup existing configs before modification
### Phase 3: Docker + OAuth
- [ ] Docker detection
- [ ] docker-compose.yml generation
- [ ] Container startup/management
- [ ] Multi-instance configuration
- [ ] OAuth flow testing
- [ ] `gitlab-mcp docker` subcommands
### Phase 4: Project Configuration
- [ ] Implement `gitlab-mcp init-project`
- [ ] Git remote detection
- [ ] Project type → profile mapping
- [ ] .gitlab-mcp/ scaffold generation
### Phase 5: Diagnostics
- [ ] Implement `gitlab-mcp doctor`
- [ ] Config validation
- [ ] Connection testing
- [ ] Token expiration check
- [ ] MCP client detection
### Phase 6: One-Click Deploy (Deep Links)
- [ ] Implement `generateClaudeDeepLink()` function
- [ ] Add `gitlab-mcp setup --claude-link` command
- [ ] Support custom host in deep link
- [ ] Support preset selection in deep link
- [ ] Create web landing page (gitlab-mcp.sw.foundation/setup)
- [ ] Add "Add to Claude" badge to README
- [ ] QR code generation for sharing
### Phase 7: Documentation
- [ ] Quick Start guide with deep link
- [ ] One-liner examples
- [ ] Troubleshooting section
- [ ] Video/GIF demos
### Phase 8: Client-Specific Guides
- [ ] docs/clients/claude-desktop.md
- [ ] docs/clients/claude-code.md
- [ ] docs/clients/cursor.md
- [ ] docs/clients/vscode.md
- [ ] docs/clients/cline.md
- [ ] docs/clients/roo-code.md
- [ ] docs/clients/windsurf.md
- [ ] docs/clients/jetbrains.md
---
## Acceptance Criteria
- [ ] `gitlab-mcp init` completes setup in <2 minutes
- [ ] Browser opens correct pages for token/OAuth creation
- [ ] Connection is tested before saving config
- [ ] MCP client configs are correctly generated
- [ ] **`gitlab-mcp install --claude-code` uses `claude mcp add` CLI**
- [ ] Docker container starts and persists across restarts
- [ ] Multi-GitLab OAuth works seamlessly
- [ ] `gitlab-mcp doctor` identifies common issues
- [ ] **Deep link opens Claude Desktop and adds server config**
- [ ] **Web landing page generates correct deep links**
- [ ] Works on macOS, Linux, Windows
## Priority
**HIGH** - Critical for user adoption
## Dependencies
- #54 - Profiles infrastructure ✅
- #55 - Built-in presets ✅
- #61 - Project-level configs
## Related
- #24 - Documentation (Quick Start section)
- #57 - Auto-discovery (reuse git detection)