Environment
|
|
| Server version |
@zereight/mcp-gitlab 2.1.46 (latest release; bug also present on main) |
| Client |
Claude Code 2.1.229 — plus a raw JSON-RPC probe, below, to isolate it from the client |
| Transport |
stdio |
| Env vars |
GITLAB_TOOLSETS=pipelines, GITLAB_API_URL, GITLAB_PERSONAL_ACCESS_TOKEN (self-hosted GitLab) |
| Node |
22.21.1 |
discover_tools activates a toolset server-side and returns success, but no spec-conformant MCP client will ever pick up the new tools — because the server never declares the capability that makes notifications/tools/list_changed meaningful.
This is the root cause of #477, which was closed as a VS Code / Roo Code caching problem with "not something gitlab-mcp can fix by only changing server behavior". It is fixable by changing server behaviour, in one line.
The declaration
index.ts:647-649 (current main, and shipped in v2.1.46):
capabilities: {
tools: {},
},
Per the spec, a server that changes its tool list must declare tools: { listChanged: true }. Clients are only obliged to honour notifications/tools/list_changed from a server that advertised it, so the notification sent at index.ts (build/index.js:307) is dropped.
Steps to reproduce
- Start the server over stdio with
GITLAB_TOOLSETS=pipelines.
- Send
initialize, then notifications/initialized.
- Send
tools/call for discover_tools with {"category": "issues"}.
- Read the frames the server writes back.
Result — the capability is absent from the handshake, yet the notification is sent:
← initialize result: "capabilities":{"tools":{}} # listChanged not declared
← after discover_tools: {"method":"notifications/tools/list_changed"} # sent regardless
So the server both (a) fails to advertise the capability and (b) emits the notification anyway.
Observed in Claude Code 2.1.229: discover_tools returns {"activated":"issues","totalTools":44}, and the very next call fails with No such tool available: mcp__gitlab__list_issues. The client does implement notifications/tools/list_changed; it correctly ignores one from a server that never declared support.
Why the SDK doesn't catch it
Server.sendToolListChanged() is guarded by assertNotificationCapability, but the check is one level too coarse:
case 'notifications/tools/list_changed':
if (!this._capabilities.tools) { throw ... }
{} is truthy, so the guard passes. The try {} catch {} around the call in discover_tools ("Client may not support notifications - safe to ignore") then ensures nothing surfaces even if it did throw — the tool reports success either way.
Fix
capabilities: {
tools: { listChanged: true },
},
Worth considering alongside it: dropping the bare catch {} so a genuine notification failure is visible rather than reported as {"activated": ...}.
Happy to open a PR if useful.
Environment
@zereight/mcp-gitlab2.1.46 (latest release; bug also present onmain)GITLAB_TOOLSETS=pipelines,GITLAB_API_URL,GITLAB_PERSONAL_ACCESS_TOKEN(self-hosted GitLab)discover_toolsactivates a toolset server-side and returns success, but no spec-conformant MCP client will ever pick up the new tools — because the server never declares the capability that makesnotifications/tools/list_changedmeaningful.This is the root cause of #477, which was closed as a VS Code / Roo Code caching problem with "not something gitlab-mcp can fix by only changing server behavior". It is fixable by changing server behaviour, in one line.
The declaration
index.ts:647-649(currentmain, and shipped in v2.1.46):Per the spec, a server that changes its tool list must declare
tools: { listChanged: true }. Clients are only obliged to honournotifications/tools/list_changedfrom a server that advertised it, so the notification sent atindex.ts(build/index.js:307) is dropped.Steps to reproduce
GITLAB_TOOLSETS=pipelines.initialize, thennotifications/initialized.tools/callfordiscover_toolswith{"category": "issues"}.Result — the capability is absent from the handshake, yet the notification is sent:
So the server both (a) fails to advertise the capability and (b) emits the notification anyway.
Observed in Claude Code 2.1.229:
discover_toolsreturns{"activated":"issues","totalTools":44}, and the very next call fails withNo such tool available: mcp__gitlab__list_issues. The client does implementnotifications/tools/list_changed; it correctly ignores one from a server that never declared support.Why the SDK doesn't catch it
Server.sendToolListChanged()is guarded byassertNotificationCapability, but the check is one level too coarse:{}is truthy, so the guard passes. Thetry {} catch {}around the call indiscover_tools("Client may not support notifications - safe to ignore") then ensures nothing surfaces even if it did throw — the tool reports success either way.Fix
Worth considering alongside it: dropping the bare
catch {}so a genuine notification failure is visible rather than reported as{"activated": ...}.Happy to open a PR if useful.