Skip to content

Commit 1e23bdd

Browse files
authored
Merge pull request #18 from structured-world/refactor/#17-unified-gitlab-api-client
refactor(api): add unified GitLab REST API client and OAuth storage backends
2 parents 81e6c19 + aa47e12 commit 1e23bdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+10300
-6404
lines changed

.github/workflows/ci-cd.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ jobs:
5252
- name: Install dependencies
5353
run: yarn install --frozen-lockfile
5454

55+
- name: Generate Prisma client
56+
run: yarn prisma generate
57+
5558
- name: Run linting
5659
run: yarn lint
5760

.github/workflows/npm-publish.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,28 @@ jobs:
1010
steps:
1111
- name: Checkout code
1212
uses: actions/checkout@v4
13+
1314
- name: Setup Node.js
1415
uses: actions/setup-node@v4
1516
with:
16-
node-version: '20'
17+
node-version: '22'
1718
registry-url: 'https://registry.npmjs.org/'
19+
20+
- name: Enable Corepack
21+
run: corepack enable
22+
23+
- name: Install Yarn
24+
run: corepack prepare [email protected] --activate
25+
1826
- name: Install dependencies
19-
run: npm ci
27+
run: yarn install --frozen-lockfile
28+
29+
- name: Generate Prisma client
30+
run: yarn prisma generate
31+
32+
- name: Build project
33+
run: yarn build
34+
2035
- name: Publish to npm
2136
env:
2237
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/pr-test.yml

Lines changed: 86 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -8,159 +8,174 @@ on:
88
jobs:
99
test:
1010
runs-on: ubuntu-latest
11-
11+
1212
strategy:
1313
matrix:
14-
node-version: [18.x, 20.x, 22.x]
15-
14+
node-version: [20.x, 22.x, 24.x]
15+
1616
steps:
1717
- name: Checkout code
1818
uses: actions/checkout@v4
19-
19+
2020
- name: Setup Node.js ${{ matrix.node-version }}
2121
uses: actions/setup-node@v4
2222
with:
2323
node-version: ${{ matrix.node-version }}
24-
cache: 'npm'
25-
24+
25+
- name: Enable Corepack
26+
run: corepack enable
27+
28+
- name: Install Yarn
29+
run: corepack prepare [email protected] --activate
30+
2631
- name: Install dependencies
27-
run: npm ci
28-
32+
run: yarn install --frozen-lockfile
33+
34+
- name: Generate Prisma client
35+
run: yarn prisma generate
36+
2937
- name: Build project
30-
run: npm run build
31-
38+
run: yarn build
39+
3240
- name: Run tests
33-
run: npm test
41+
run: yarn test
3442
env:
3543
GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }}
3644
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN_TEST }}
3745
GITLAB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITLAB_PERSONAL_ACCESS_TOKEN }}
3846
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
39-
47+
4048
- name: Type check
41-
run: npx tsc --noEmit
42-
49+
run: yarn tsc --noEmit
50+
4351
- name: Lint check
44-
run: npm run lint || echo "No lint script found"
45-
52+
run: yarn lint
53+
4654
- name: Check package size
4755
run: |
48-
npm pack --dry-run
56+
yarn pack --dry-run
4957
echo "Package created successfully"
50-
51-
- name: Security audit
52-
run: npm audit --production || echo "Some vulnerabilities found"
53-
continue-on-error: true
54-
55-
- name: Test MCP server startup
56-
run: |
57-
echo "MCP server startup test temporarily disabled for debugging"
58-
echo "GITLAB_PERSONAL_ACCESS_TOKEN is: ${GITLAB_PERSONAL_ACCESS_TOKEN:0:10}..."
59-
env:
60-
GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }}
61-
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN_TEST }}
62-
GITLAB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITLAB_PERSONAL_ACCESS_TOKEN }}
63-
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
6458
6559
integration-test:
6660
runs-on: ubuntu-latest
6761
needs: test
6862
if: github.event.pull_request.draft == false
69-
63+
7064
steps:
7165
- name: Checkout code
7266
uses: actions/checkout@v4
73-
67+
7468
- name: Setup Node.js
7569
uses: actions/setup-node@v4
7670
with:
77-
node-version: '20.x'
78-
cache: 'npm'
79-
71+
node-version: '22.x'
72+
73+
- name: Enable Corepack
74+
run: corepack enable
75+
76+
- name: Install Yarn
77+
run: corepack prepare [email protected] --activate
78+
8079
- name: Install dependencies
81-
run: npm ci
82-
80+
run: yarn install --frozen-lockfile
81+
82+
- name: Generate Prisma client
83+
run: yarn prisma generate
84+
8385
- name: Build project
84-
run: npm run build
85-
86+
run: yarn build
87+
8688
- name: Run integration tests
8789
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
8890
run: |
8991
echo "Running integration tests with real GitLab API..."
90-
npm run test:integration || echo "No integration test script found"
92+
yarn test:integration || echo "No integration test script found"
9193
env:
9294
GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }}
9395
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN_TEST }}
9496
GITLAB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITLAB_PERSONAL_ACCESS_TOKEN }}
9597
PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
96-
98+
9799
- name: Test Docker build
98100
run: |
99101
docker build -t mcp-gitlab-test .
100-
docker run --rm mcp-gitlab-test node build/index.js --version || echo "Version check passed"
102+
docker run --rm mcp-gitlab-test node dist/src/main.js --version || echo "Version check passed"
101103
102104
code-quality:
103105
runs-on: ubuntu-latest
104-
106+
105107
steps:
106108
- name: Checkout code
107109
uses: actions/checkout@v4
108110
with:
109111
fetch-depth: 0
110-
112+
111113
- name: Setup Node.js
112114
uses: actions/setup-node@v4
113115
with:
114-
node-version: '20.x'
115-
cache: 'npm'
116-
116+
node-version: '22.x'
117+
118+
- name: Enable Corepack
119+
run: corepack enable
120+
121+
- name: Install Yarn
122+
run: corepack prepare [email protected] --activate
123+
117124
- name: Install dependencies
118-
run: npm ci
119-
125+
run: yarn install --frozen-lockfile
126+
120127
- name: Check code formatting
121128
run: |
122-
npx prettier --check "**/*.{js,ts,json,md}" || echo "Some files need formatting"
123-
129+
yarn prettier --check "**/*.{js,ts,json,md}" || echo "Some files need formatting"
130+
124131
- name: Check for console.log statements
125132
run: |
126-
if grep -r "console\.log" --include="*.ts" --exclude-dir=node_modules --exclude-dir=build --exclude="test*.ts" .; then
127-
echo "⚠️ Found console.log statements in source code"
133+
if grep -r "console\.log" --include="*.ts" --exclude-dir=node_modules --exclude-dir=dist --exclude="test*.ts" .; then
134+
echo "Warning: Found console.log statements in source code"
128135
else
129-
echo "No console.log statements found"
136+
echo "No console.log statements found"
130137
fi
131-
138+
132139
- name: Check for TODO comments
133140
run: |
134-
if grep -r "TODO\|FIXME\|XXX" --include="*.ts" --exclude-dir=node_modules --exclude-dir=build .; then
135-
echo "⚠️ Found TODO/FIXME comments"
141+
if grep -r "TODO\|FIXME\|XXX" --include="*.ts" --exclude-dir=node_modules --exclude-dir=dist .; then
142+
echo "Warning: Found TODO/FIXME comments"
136143
else
137-
echo "No TODO/FIXME comments found"
144+
echo "No TODO/FIXME comments found"
138145
fi
139146
140147
coverage:
141148
runs-on: ubuntu-latest
142149
if: github.event.pull_request.draft == false
143-
150+
144151
steps:
145152
- name: Checkout code
146153
uses: actions/checkout@v4
147-
154+
148155
- name: Setup Node.js
149156
uses: actions/setup-node@v4
150157
with:
151-
node-version: '20.x'
152-
cache: 'npm'
153-
158+
node-version: '22.x'
159+
160+
- name: Enable Corepack
161+
run: corepack enable
162+
163+
- name: Install Yarn
164+
run: corepack prepare [email protected] --activate
165+
154166
- name: Install dependencies
155-
run: npm ci
156-
167+
run: yarn install --frozen-lockfile
168+
169+
- name: Generate Prisma client
170+
run: yarn prisma generate
171+
157172
- name: Build project
158-
run: npm run build
159-
160-
- name: Run tests
161-
run: npm test
173+
run: yarn build
174+
175+
- name: Run tests with coverage
176+
run: yarn test:cov
162177
env:
163178
GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }}
164179
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN_TEST }}
165180
GITLAB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITLAB_PERSONAL_ACCESS_TOKEN }}
166-
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}
181+
TEST_PROJECT_ID: ${{ secrets.TEST_PROJECT_ID }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ coverage/
2525
scripts/
2626
!scripts/cleanup-test-groups.js
2727
!scripts/test_mcp.sh
28+
!scripts/deploy.sh
2829

2930
# Keep assets
3031
!assets/
32+
33+
/generated/prisma

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ COPY --from=dependencies /app/.yarn ./.yarn
4242
# Copy source code and config files
4343
COPY tsconfig*.json ./
4444
COPY src ./src
45+
COPY prisma ./prisma
46+
COPY prisma.config.ts ./
4547

4648
# Build the application
4749
RUN yarn build

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,13 @@ GitLab MCP Server supports OAuth 2.1 authentication for use as a **Claude Custom
259259
1. In GitLab, navigate to **User Settings > Applications** (or **Admin > Applications** for instance-wide)
260260
2. Create a new application:
261261
- **Name**: `GitLab MCP Server`
262-
- **Redirect URI**: `https://your-mcp-server.com/oauth/callback`
263-
- **Confidential**: `No` (required for device flow)
262+
- **Redirect URI**: `https://your-mcp-server.com/oauth/callback` (required for Authorization Code Flow)
263+
- **Confidential**: `No` (PKCE provides security without client secret)
264264
- **Scopes**: Select `api` and `read_user`
265265
3. Save and copy the **Application ID**
266266

267+
> **Note**: The redirect URI is used by Claude.ai Custom Connectors (Authorization Code Flow). CLI clients use Device Flow which doesn't require redirect URI.
268+
267269
#### Step 2: Configure gitlab-mcp Server
268270

269271
```bash
@@ -399,15 +401,28 @@ For GitLab instances on private networks (not internet-accessible):
399401
| Security | Token in config | No tokens in config |
400402
| Best for | Personal use, CI/CD | Teams, shared access |
401403

404+
### OAuth Flows
405+
406+
The server supports two OAuth flows automatically:
407+
408+
| Flow | Trigger | Used By | How It Works |
409+
|------|---------|---------|--------------|
410+
| **Authorization Code Flow** | `redirect_uri` present | Claude.ai Custom Connectors | Redirects to GitLab OAuth, then back to client |
411+
| **Device Flow** | No `redirect_uri` | CLI clients, Claude Desktop | Shows device code page for manual entry |
412+
413+
The flow is selected automatically based on the presence of `redirect_uri` in the authorization request.
414+
402415
### OAuth Endpoints
403416

404417
When OAuth is enabled, the following endpoints are available:
405418

406419
| Endpoint | Method | Description |
407420
|----------|--------|-------------|
408421
| `/.well-known/oauth-authorization-server` | GET | OAuth metadata discovery |
409-
| `/authorize` | GET | Start authorization (device flow) |
410-
| `/oauth/poll` | GET | Poll for authorization completion |
422+
| `/.well-known/oauth-protected-resource` | GET | Protected resource metadata (RFC 9470) |
423+
| `/authorize` | GET | Start authorization (auto-selects flow) |
424+
| `/oauth/callback` | GET | GitLab callback (Auth Code Flow only) |
425+
| `/oauth/poll` | GET | Poll for completion (Device Flow only) |
411426
| `/token` | POST | Exchange code for tokens |
412427
| `/health` | GET | Health check endpoint |
413428

0 commit comments

Comments
 (0)