MCP server: structuredContent should include actual tool output, not just pagination metadata

Checklist

  • I'm using the latest version of the extension (Run glab --version)
    • Extension version: 1.80.4 (f4b518e9)
  • Operating system and version: macOS Darwin 24.6.0 arm64
  • Gitlab.com or self-managed instance? self-managed instance
  • GitLab version (if self-managed): N/A (issue is with MCP server, not GitLab API)
  • I have performed glab auth status to check for authentication issues
  • Run the command in debug mode and attach any useful output (see logs below)

Summary

When using glab mcp serve with MCP clients that prioritize structuredContent (like Claude Code), the actual tool output is not displayed. This is because glab's structuredContent only contains pagination metadata, not the actual command output.

MCP clients like Claude Code prioritize structuredContent over content for agent performance. Since glab only puts pagination info in structuredContent, users see pagination metadata instead of the actual data (e.g., MR list).

Environment

  • OS: Darwin 24.6.0 arm64
  • SHELL: /bin/zsh
  • TERM: xterm-256color (via tmux)
  • GLAB: glab 1.80.4 (f4b518e9)

Other: Using Claude Code 2.0.67 as MCP client

Steps to reproduce

  1. Configure glab mcp serve as an MCP server in Claude Code (stdio transport)
  2. Call any glab tool, e.g., glab_mr_list
  3. Observe that only pagination metadata is displayed, not the actual MR list

What is the current bug behavior?

glab MCP server returns:

{
  "result": {
    "content": [
      {"type": "text", "text": "Showing 8 open merge requests...\n\n!1359\t..."}
    ],
    "structuredContent": {
      "pagination": {
        "actual_end": 1006,
        "actual_size": 1006,
        "actual_start": 0,
        "limit": 50000,
        "offset": 0,
        "total_size": 1006,
        "truncated": false
      }
    }
  }
}

Claude Code (and other MCP clients following the spec) prioritizes structuredContent, so users only see:

{"pagination":{"actual_end":1006,"actual_size":1006,...}}

The actual MR list in content is never displayed.

What is the expected correct behavior?

According to the MCP specification and Claude Code's documented behavior (https://github.com/anthropics/claude-code/issues/9962), structuredContent should include the actual tool output:

Option 1: Include actual output in structuredContent

{
  "structuredContent": {
    "output": "Showing 8 open merge requests...",
    "items": [...],
    "pagination": {...}
  }
}

Option 2: Only return content, don't return structuredContent if it's just metadata

{
  "content": [
    {"type": "text", "text": "Showing 8 open merge requests..."}
  ]
}

Option 3: Add a flag to control behavior

glab mcp serve --no-structured-content

Relevant logs and/or screenshots

MCP server log captured via wrapper script showing the full response:

Request:

{"method":"tools/call","params":{"name":"glab_mr_list","arguments":{}},"jsonrpc":"2.0","id":2}

Response from glab:

{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"Showing 8 open merge requests on synology/OrangeDrive. (Page 1)\n\n!1359\tsynology/OrangeDrive!1359\tfeat: support complex share paths in PathConvertHelper\t(master) ← (WP159)\n!1354\tsynology/OrangeDrive!1354\tfeat: refactor msstore\t(master) ← (appstore)\n..."}],"structuredContent":{"pagination":{"actual_end":1006,"actual_size":1006,"actual_start":0,"limit":50000,"offset":0,"total_size":1006,"truncated":false}}}}

What Claude Code displays:

{"pagination":{"actual_end":1006,"actual_size":1006,"actual_start":0,"limit":50000,"offset":0,"total_size":1006,"truncated":false}}

Possible fixes

Code location: internal/commands/mcp/serve/server.go:277-286

return &mcp.CallToolResult{
    Content: []mcp.Content{
        mcp.TextContent{
            Type: "text",
            Text: processedOutput,
        },
    },
    StructuredContent: map[string]any{
        "pagination": metadata,  // <-- Only pagination, missing actual output
    },
}, nil

Suggested fix: Include the actual output in StructuredContent:

StructuredContent: map[string]any{
    "output":     processedOutput,  // Add actual output here
    "pagination": metadata,
},

Or remove StructuredContent entirely if it's only used for pagination metadata.

References:

  • MCP Specification: https://modelcontextprotocol.io/specification/2025-11-25/server/tools
  • Claude Code issue explaining client behavior: https://github.com/anthropics/claude-code/issues/9962
Assignee Loading
Time tracking Loading