fix: return structured JSON in all list-* tool responses - #96
Conversation
All formatters previously returned two content items — a summary string
('Found N items') and a separate JSON array. MCP clients/gateways that
only read the first content item received zero data.
Change all 20 formatters to return a single content item containing
structured JSON: { count, items: [...] }. This matches the format
already used by search_repositories and is parseable by all clients.
- Extracted shared jsonResponse() helper to eliminate duplication
- Added tests for formatIssuesResponse, formatEventsResponse,
formatWikiPageResponse, formatWikiAttachmentResponse
- All existing tests updated for new single-item response format
- 90 unit tests pass
Fixes yoda-digital#95
Signed-off-by: Olivier Gintrand <olivier.gintrand@forterro.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the GitLab response formatters to provide a consistent, structured JSON output compatible with the Model Context Protocol (MCP). A central jsonResponse helper was introduced to wrap all formatter outputs into a single content item, moving metadata like item counts directly into the JSON payload. The test suite has been updated to reflect these structural changes and includes new test cases for issues, events, and wiki-related formatters. I have no feedback to provide as there were no review comments.
|
@ecthelion77 First, the genuinely good news: the architectural direction you proposed here is correct. I asked four independent reviewers (code-quality, type-design, silent-failure, and a philosophical-council review applying Postel/Hyrum/Torvalds/Carmack lenses) to walk this PR in depth, and they converged: collapsing the list-* response to a single content item with a I'm landing this via Path B reincarnation in #103 - same pattern we used for #62→#80, #63→#81, and #86→#99. Your four-file commit lands on The architectural completion ( The E2E suite migration ( The scope completion ( The contract documentation ( The structured-coverage extension ( Why Path B not Path A: the architectural completion was the load-bearing decision (whether to use Release plan: cut 0.10.0 immediately after #103 merges (semver-minor signals the breaking shape change under 0.x). Closing #96 with this comment as it merges into #103. Thanks for the catch on the gateway-compatibility class of bug - your issue #95 reproduced a real problem that needed the protocol-correct fix to land properly. The shape decision lives in If you want to keep working on the open |
Problem
All
list-*tools (issues, merge requests, notes, discussions, pipelines, jobs, etc.) return their response as two separate MCP content items:"Found N items"MCP clients/gateways that only read the first content item (which is common — e.g. ContextForge, some Copilot integrations) receive zero useful data — just a count string.
Meanwhile,
search_repositoriesalready returns a single content item with{ count, items }and works correctly everywhere.Fix
Unify all 20 formatters to return a single structured JSON content item:
{ count, items: [...] }.Changes
src/formatters.ts: extracted sharedjsonResponse()helper, all formatters now return one content item with{ count, items }(or a single object for entity responses likeformatWikiPageResponse)src/formatters.test.ts: updated all tests for new format, added coverage forformatIssuesResponse,formatEventsResponse,formatWikiPageResponse,formatWikiAttachmentResponseBefore/After
Before (broken for single-item clients):
{ "content": [ { "type": "text", "text": "Found 1 issues" }, { "type": "text", "text": "[{\"id\": 100, ...}]" } ] }After (consistent with
search_repositories):{ "content": [ { "type": "text", "text": "{\"count\": 1, \"items\": [{\"id\": 100, ...}]}" } ] }Fixes #95