MCP server for discovering and analyzing GitLab service dependencies using Cartographer metadata
cartographer-mcp demonstrates solid fundamentals: all 6 tools follow verb_noun naming (list_services, get_dependencies, refresh_cache, etc.), all have non-trivial descriptions (65-85 chars), and input schemas are properly defined with typed parameters. However, output schemas are undocumented, tools return JSON responses but no formal output schema is declared. Parameter descriptions are present but minimal (5-40 chars), lacking actionable detail on formats, constraints, and expected values. Error handling is present but generic ('service not found', 'failed to marshal') without recovery guidance. No tool annotations (readOnlyHint/destructiveHint) despite clear READ_ONLY vs WRITE semantics. Missing pagination guidance for list_services despite domain patterns suggesting large result sets. Composition is strong, tools are single-responsibility and chain well (search_services → get_service → get_dependencies). Security is acceptable for a read-mostly server with one WRITE operation (refresh_cache).
Get forward dependencies of a service (what it depends on)
Get reverse dependencies (what depends on this service)
Get full details for a specific service by name or path
List all discovered services, optionally filtered
Trigger a full cache refresh from GitLab
Search services by keyword across names, descriptions, tags, and outputs
Output schemas are not documented. Tools return JSON (via mcp.NewToolResultText), but no formal schema is declared for response structure. LLMs cannot plan downstream calls or extract fields without knowing expected response shape.
Parameter descriptions lack actionable constraints and format guidance. Example: 'groups' in refresh_cache is described as 'Comma-separated GitLab group paths (overrides config)' but does not specify max count, validation rules, or error behavior if invalid. 'type' and 'lifecycle' filters in list_services lack enum values, LLM must guess valid options.
Tool annotations missing. refresh_cache is a WRITE operation (triggers GitLab API calls) but carries no destructiveHint or idempotentHint annotation. Other tools are READ_ONLY but lack readOnlyHint. LLMs cannot infer safety/retry behavior without explicit annotations.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 59 | 2026-07-28+ | v2 |
| 2026-03-09 | D | 53 | - | v1 |
Error messages lack recovery guidance. Examples from code: 'service not found: ' + name, 'failed to marshal response'. These tell the LLM nothing about what to do next, should it retry? Call search_services() instead? Are suggestions available? Code at internal/mcp/tools_detail.go shows fuzzyMatch() generating suggestions but not surfaced in the error message.
Pagination not documented or enforced. list_services has no page/offset/limit parameters. For a service catalog potentially containing hundreds of services, returning all results risks context window explosion. No indication of result count limits in description.