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
4 changes: 2 additions & 2 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
uses: actions/checkout@v7

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '22'

Expand Down Expand Up @@ -138,7 +138,7 @@ jobs:
token: ${{ steps.app-token.outputs.token }}

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '22'

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ jobs:
uses: actions/checkout@v7

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v4.37.4
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@v4
uses: github/codeql-action/autobuild@v4.37.4

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v4.37.4
with:
category: "/language:${{ matrix.language }}"
2 changes: 1 addition & 1 deletion .github/workflows/coverage-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: 24

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
with:
fetch-depth: 0

- uses: actions/setup-node@v6
- uses: actions/setup-node@v7
with:
node-version: 24

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
uses: actions/checkout@v7

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: "22"

Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
uses: actions/checkout@v7

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}

Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
uses: actions/checkout@v7

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: "22"

Expand Down Expand Up @@ -145,7 +145,7 @@ jobs:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: "22"

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ jobs:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'
# NO registry-url — it creates .npmrc with NODE_AUTH_TOKEN placeholder
Expand Down Expand Up @@ -366,7 +366,7 @@ jobs:
token: ${{ steps.app-token.outputs.token }}

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upstream-monitor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: '24'

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
"lint": "nx run-many -t lint"
},
"devDependencies": {
"nx": "^23.0.0"
"nx": "^23.1.1"
}
}
6 changes: 3 additions & 3 deletions packages/gitlab-mcp-db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
"postinstall": "node -e \"if (require('fs').existsSync('prisma/schema.prisma')) require('child_process').execSync('prisma generate', { stdio: 'inherit' })\""
},
"dependencies": {
"@prisma/client": "^7.8.0",
"prisma": "^7.8.0"
"@prisma/client": "^7.9.1",
"prisma": "^7.9.1"
},
"devDependencies": {
"@structured-world/gitlab-mcp": "workspace:^",
"@types/jest": "^30.0.0",
"@types/node": "^25.9.4",
"jest": "^30.4.2",
"ts-jest": "^29.4.11",
"ts-jest": "^29.4.12",
"typescript": "^6.0.3"
},
"publishConfig": {
Expand Down
21 changes: 21 additions & 0 deletions packages/gitlab-mcp/docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,29 @@ See [Customization](/advanced/customization) for schema mode details.
|----------|---------|-------------|
| `LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `LOG_JSON` | `false` | Output logs as JSON (NDJSON) for log aggregators |
| `LOG_FORMAT` | `%msg` | Which fields appear in plain-text logs: `%time`, `%level`, `%name`. Tokens toggle field visibility only; the line always renders in pino-pretty's fixed `[time] LEVEL (name): msg` order, and the message itself is always included regardless of `%msg` (e.g. `[%time] %level (%name): %msg` enables all fields) |
| `LOG_DESTINATION` | auto | `stdout` or `stderr`. HTTP mode only; see [Log Destinations](#log-destinations-stdout-vs-stderr) |
| `LOG_FILTER` | Claude Code filter | JSON array of filter rules to skip access logging |

### Log Destinations (stdout vs stderr)

Where log lines are written depends on the transport mode:

| Mode | Plain text (default) | `LOG_JSON=true` |
|------|----------------------|-----------------|
| stdio (no `PORT`) | stderr (always) | stderr (always) |
| HTTP (`PORT` set) | stderr | stdout |

**In stdio mode all logs always go to stderr.** stdout is reserved for MCP JSON-RPC
protocol frames ([MCP spec](https://modelcontextprotocol.io/specification/basic/transports#stdio)),
so any log line on stdout would corrupt the client connection. `LOG_DESTINATION` is
ignored in stdio mode.

In HTTP mode the defaults follow the container convention: JSON logs go to stdout for
log-driver ingestion, human-readable logs go to stderr. Set `LOG_DESTINATION=stdout`
or `LOG_DESTINATION=stderr` to override. Docker's `docker logs` and journald capture
both streams either way.

### Plain Text Mode (default)

Human-readable single-line format suitable for journald, systemd, and console viewing:
Expand Down
30 changes: 30 additions & 0 deletions packages/gitlab-mcp/docs/troubleshooting/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,36 @@ Find your npx path: `which npx`
- **Settings location**: Inside VS Code extension storage
- **Update path**: If extension ID changes, config path changes too

## Startup Log Spam {#jsonrpc-parse-errors}

### "Failed to parse JSONRPC message from server"

**Symptom**: On startup the MCP client prints a burst of parse errors such as:

```
Failed to parse JSONRPC message from server
pydantic_core._pydantic_core.ValidationError: 1 validation error for JSONRPCMessage
Invalid JSON: expected value at line 1 column 5
```

**Cause**: The server version being launched writes log lines to stdout, which the
MCP stdio protocol reserves for JSON-RPC frames. Current releases always log to
stderr in stdio mode; this symptom means an outdated package build is running,
usually from a stale `npx` cache (`npx -y` reuses a previously downloaded version).

**Fix**:
```bash
# Clear the npx cache so the latest release is fetched
# (cache lives in ~/.npm/_npx)
npm cache clean --force

# Or pin the latest release explicitly in your client config
npx -y @structured-world/gitlab-mcp@latest
```

See [Log Destinations](/guide/configuration#log-destinations-stdout-vs-stderr) for
how log output is routed per transport mode.

## Permission Issues

### "EACCES: permission denied"
Expand Down
1 change: 1 addition & 0 deletions packages/gitlab-mcp/docs/troubleshooting/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Solutions for common issues with GitLab MCP.
| "No clients detected" | Client not installed or not detected | [Clients](/troubleshooting/clients) |
| Server not appearing in client | Config file issue | [Clients](/troubleshooting/clients#config-not-loaded) |
| Docker container won't start | Port conflict or missing env vars | [Docker](/troubleshooting/docker) |
| "Failed to parse JSONRPC message" spam on startup | Outdated build from stale npx cache logging to stdout | [Clients](/troubleshooting/clients#jsonrpc-parse-errors) |
| Tools not available | Feature flags or read-only mode | [Connection](/troubleshooting/connection#tools-missing) |

## General Steps
Expand Down
26 changes: 13 additions & 13 deletions packages/gitlab-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -558,42 +558,42 @@
"build:mcpb": "./scripts/build-mcpb.sh"
},
"dependencies": {
"@clack/prompts": "^1.6.0",
"@modelcontextprotocol/sdk": "^1.29.0",
"@clack/prompts": "^1.7.0",
"@modelcontextprotocol/sdk": "^1.30.0",
"express": "^5.2.1",
"graphql": "^17.0.0",
"graphql": "^17.0.2",
"graphql-tag": "^2.12.7",
"open": "^11.0.0",
"picomatch": "^4.0.4",
"picomatch": "^4.0.5",
"pino": "^10.3.1",
"pino-pretty": "^13.1.3",
"transliteration": "^2.6.1",
"undici": "^8.5.0",
"xstate": "^5.32.1",
"undici": "^8.10.0",
"xstate": "^5.32.5",
"yaml": "^2.9.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260623.1",
"@cloudflare/workers-types": "^5.20260808.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.4",
"@types/picomatch": "^4.0.3",
"@typescript-eslint/eslint-plugin": "^8.62.0",
"@typescript-eslint/parser": "^8.62.0",
"@typescript-eslint/eslint-plugin": "^8.66.0",
"@typescript-eslint/parser": "^8.66.0",
"auto-changelog": "^2.6.0",
"cross-env": "^10.1.0",
"dotenv": "^17.4.2",
"eslint": "^10.5.0",
"eslint": "^10.8.1",
"eslint-plugin-prettier": "^5.5.6",
"jest": "^30.4.2",
"prettier": "^3.8.4",
"ts-jest": "^29.4.11",
"prettier": "^3.9.6",
"ts-jest": "^29.4.12",
"ts-node": "^10.9.2",
"typescript": "^6.0.3",
"vitepress": "2.0.0-alpha.17"
"vitepress": "2.0.0-alpha.19"
}
}
8 changes: 1 addition & 7 deletions packages/gitlab-mcp/src/cli/docker/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@ export interface ContainerRuntimeInfo {
* Docker container status
*/
export type ContainerStatus =
| 'running'
| 'stopped'
| 'paused'
| 'restarting'
| 'created'
| 'exited'
| 'dead';
'running' | 'stopped' | 'paused' | 'restarting' | 'created' | 'exited' | 'dead';

/**
* Docker container info
Expand Down
6 changes: 1 addition & 5 deletions packages/gitlab-mcp/src/entities/context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,7 @@ export type { ProfileInfo };
* Token type classification
*/
export type WhoamiTokenType =
| 'personal_access_token'
| 'project_access_token'
| 'group_access_token'
| 'oauth'
| 'unknown';
'personal_access_token' | 'project_access_token' | 'group_access_token' | 'oauth' | 'unknown';

/**
* User identity information
Expand Down
12 changes: 5 additions & 7 deletions packages/gitlab-mcp/src/entities/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ const isReadOnly = process.env.GITLAB_READONLY === 'true';
const coreToolsFromRegistry = getFilteredCoreTools(isReadOnly);

// Convert enhanced tool definitions to regular tool definitions for backward compatibility
export const coreTools: ToolDefinition[] = coreToolsFromRegistry.map(
(tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}),
);
export const coreTools: ToolDefinition[] = coreToolsFromRegistry.map((tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}));

// Export read-only tool names for backward compatibility
export const coreReadOnlyTools = getCoreReadOnlyToolNames();
12 changes: 5 additions & 7 deletions packages/gitlab-mcp/src/entities/files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ const isReadOnly = process.env.GITLAB_READONLY === 'true';
const filesToolsFromRegistry = getFilteredFilesTools(isReadOnly);

// Convert enhanced tool definitions to regular tool definitions for backward compatibility
export const filesTools: ToolDefinition[] = filesToolsFromRegistry.map(
(tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}),
);
export const filesTools: ToolDefinition[] = filesToolsFromRegistry.map((tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}));

// Export read-only tool names for backward compatibility
export const filesReadOnlyTools = getFilesReadOnlyToolNames();
12 changes: 5 additions & 7 deletions packages/gitlab-mcp/src/entities/mrs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ const isReadOnly = process.env.GITLAB_READONLY === 'true';
const mrsToolsFromRegistry = getFilteredMrsTools(isReadOnly);

// Convert enhanced tool definitions to regular tool definitions for backward compatibility
export const mrsTools: ToolDefinition[] = mrsToolsFromRegistry.map(
(tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}),
);
export const mrsTools: ToolDefinition[] = mrsToolsFromRegistry.map((tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}));

// Export read-only tool names for backward compatibility
export const mrsReadOnlyTools = getMrsReadOnlyToolNames();
12 changes: 5 additions & 7 deletions packages/gitlab-mcp/src/entities/wiki/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ const isReadOnly = process.env.GITLAB_READONLY === 'true';
const wikiToolsFromRegistry = getFilteredWikiTools(isReadOnly);

// Convert enhanced tool definitions to regular tool definitions for backward compatibility
export const wikiTools: ToolDefinition[] = wikiToolsFromRegistry.map(
(tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}),
);
export const wikiTools: ToolDefinition[] = wikiToolsFromRegistry.map((tool): ToolDefinition => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
}));

// Export read-only tool names for backward compatibility
export const wikiReadOnlyTools = getWikiReadOnlyToolNames();
9 changes: 1 addition & 8 deletions packages/gitlab-mcp/src/graphql/workItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,7 @@ export type WorkItemState = 'OPEN' | 'CLOSED';

// Work Item Type enum - defines all available work item types
export type WorkItemTypeEnum =
| 'EPIC'
| 'ISSUE'
| 'TASK'
| 'INCIDENT'
| 'TEST_CASE'
| 'REQUIREMENT'
| 'OBJECTIVE'
| 'KEY_RESULT';
'EPIC' | 'ISSUE' | 'TASK' | 'INCIDENT' | 'TEST_CASE' | 'REQUIREMENT' | 'OBJECTIVE' | 'KEY_RESULT';

// Work Item Widget Type constants
export const WorkItemWidgetTypes = {
Expand Down
Loading
Loading