Pod

Yes, this is on purpose. Pod is built for agents, so the default page is plain HTML.
Human? View the normal website.
Agent? You probably prefer /mcp/gitlab-mcp-server/issues.md or /mcp/gitlab-mcp-server/issues.json, or Pod over MCP.

Reported issues for GitLab MCP Server

Pod holds 12 of 12 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to GitLab MCP Server.

Most discussed

A rejected GraphQL document is reported to the model as an empty result, and five tools are in that state today

A GraphQL document this server sends can be rejected by GitLab and the caller is told the project has nothing, not that the question was malformed. Two registered tools are in that state today, and one of them reports on vulnerabilities.

The mechanism

GitLab answers a document that fails validation with HTTP 200, data: null and a top-level errors array. client-go's GraphQL.Do only builds a GraphQLResponseError when the underlying HTTP call itself returned an error…

Read the thread · 2026-09-06 · closed · 3 comments

GraphQL mocks answer what GitLab would refuse, so four broken documents shipped with green tests

Our GraphQL tests cannot fail for the reason that matters. Every domain test answers the request from an httptest handler that returns whatever the test wrote, so the document itself is never judged by anything. GitLab is the only party that would refuse it, and no test ever asks GitLab.

That is not a theoretical gap. I posted all 30 raw GraphQL documents this server sends to https://gitlab.com/api/graphql and four are rejected outright, so four registered tools cannot work on any current…

Read the thread · 2026-09-06 · closed · 1 comment

cmd/server's stdio shutdown test hangs the Windows suite for thirty minutes, intermittently

The 🖥️ Cross-platform (windows-latest) job fails by timing out the whole cmd/server package, not by an assertion. The panic names what was still running:

panic: test timed out after 30m0s
	running tests:
		TestServeStdio_TheTwoDocumentedShutdowns_ExitCleanly (29m29s)
		TestServeStdio_TheTwoDocumentedShutdowns_ExitCleanly/a_signal_cancels_the_context (29m29s)
FAIL	github.com/jmrplens/gitlab-mcp-server/v2/cmd/server	1800s

Every other test in the package is then reported as failed…

Read the thread · 2026-09-08 · open · 0 comments

A blocked address is refused before its credential is read, so one token sprayer behind a shared IP cuts off every legitimate neighbour

In HTTP mode an address is refused before its credential is read, so a client spraying invalid tokens from behind a shared public IP takes every legitimate neighbour down with it. cmd/server/auth_gate.go:449 checks blockedByBudget first and only then extracts the token; bearer_guard.go does the same in OAuth mode. The budget is authFailureLimit, ten failed authentications per address inside authFailureWindow, one minute, and the block answers 429 to everything from that address for…

Read the thread · 2026-09-08 · open · 0 comments

Read-only and safe mode reach the tools outside the catalog only inside cmd/server, so the evaluator and the suite keep their real handlers

Read-only mode, safe mode, the token-scope narrowing and --exclude-tools act in two places. The catalog-backed tools receive them per action from FilterActionCatalog, inside the catalog that every assembler shares. The tools registered outside the catalog receive them from applyToolVisibilityConfig at cmd/server/main.go:2048, a pass that runs after registration over the tools the server holds: it removes the names --exclude-tools lists, removes what the token's scopes cannot call…

Read the thread · 2026-09-08 · open · 0 comments

The e2e suite assembles the meta surface on its own and drives one tool fewer than the binary serves

test/e2e/suite/setup_test.go:203 builds the meta session with tools.RegisterAllMeta, which asks the catalog for no MCP group, so the surface the suite drives has no gitlab_server. That is 33 tools in the suite against 34 in the binary on Free, 39 against 40 on Premium, 50 against 51 on self-managed Ultimate and 51 against 52 on GitLab.com. The doc comment on RegisterAllMeta in internal/tools/register_meta.go:12 says exactly this, and the suite is now the function's only caller outside…

Read the thread · 2026-09-08 · open · 0 comments

approval_config publishes nine fields a live GitLab never sends, and 1:1 parity with the SDK is why nothing notices

gitlab_merge_request approval_config publishes an output schema promising nine fields that a live GitLab CE never sends, and nothing in the repository can currently notice.

What is declared and what arrives

mrapprovals.ConfigOutput in internal/tools/mrapprovals/mr_approvals.go mirrors client-go's MergeRequestApprovals field for field, which is the 1:1 norm working as intended: 24 fields, 11 of them carrying tier:"premium" so a Free client never sees them in the model-facing…

Read the thread · 2026-09-07 · closed · 0 comments

A meta-tool description is checked only against a snapshot regenerated from itself, so it cannot go stale loudly

The description a model reads for a meta-tool is prose that enumerates the tool's parameters, and nothing connects it to the parameters. It cannot go stale loudly, because its only source is a file regenerated from itself.

internal/tools/action_catalog.go:386 fills a group's description from catalogGroupDescription, whose signature is:

func catalogGroupDescription(toolName string, _ toolutil.ActionMap) string

The actions are passed in and discarded. The text comes from…

Read the thread · 2026-09-06 · closed · 0 comments

Most recent

Eight GraphQL domains advertise backward pagination and silently discard it

toolutil.GraphQLPaginationInput offers a model four cursor parameters and describes two of them as backward pagination:

Last   *int   `json:"last,omitempty"   jsonschema:"Number of items from the end (backward pagination)"`
Before string `json:"before,omitempty" jsonschema:"Cursor for backward pagination (from previous response start_cursor)"`

Variables() duly puts them in the variables map. But not one of the eight domains that use the helper declares $before or $last in…

Read the thread · 2026-09-06 · closed · 0 comments

Pool eviction can take a subscribed credential, and what that costs an attacker is undocumented

When the pool is at --max-http-clients and a new credential arrives, lruVictimLocked walks the LRU from the tail looking for an entry that WithInUse does not report as busy, and returns the tail anyway when every entry is busy. Eviction is not gentle: dropEntry fires WithOnEvict under the pool's write lock, the credential's session IDs stop being accepted at once, and on another goroutine its watchers stop, its subscriptions/listen streams are cancelled and the sessions no…

Read the thread · 2026-09-06 · closed · 0 comments

The integration read path drifted from the shared renderer, so a titleless integration reads as an empty heading

internal/tools/integrations/markdown.go renders a single integration twice, from two places that were once the same code and no longer are.

formatIntegrationItemString, which the set and upsert paths use, writes its heading as fallback(i.Title, i.Slug): an integration whose title is empty is named by its slug. formatGetMarkdownString, which gitlab_get_integration uses, writes i.Title raw. The rest of the two bodies is line for line identical: the id, the slug, the active badge, the…

Read the thread · 2026-09-06 · open · 0 comments

Two markdown formatters register for one type, so a runner authentication token renders as a registration token

internal/tools/runners/markdown.go registers two formatters for the same Go type:

toolutil.RegisterMarkdown(FormatAuthTokenMarkdown) // func(AuthTokenOutput) string
toolutil.RegisterMarkdown(FormatRegTokenMarkdown)  // func(AuthTokenOutput) string

RegisterMarkdown keys a sync.Map on reflect.TypeOf and calls Store, so the second registration replaces the first. Every value of that type therefore renders through FormatRegTokenMarkdown, and the result of resetting a…

Read the thread · 2026-09-06 · open · 0 comments

The remaining reports are on the project's issue tracker.