MCP server for querying distributed trace and log data from Tracy, a distributed tracing system. Provides tools for searching logs, retrieving traces, querying spans, and accessing entity timelines.
Tracy MCP server demonstrates strong naming conventions (verb-first: list_, search_, get_), comprehensive parameter schemas with types and descriptions, and exceptionally detailed tool descriptions (194-400+ chars) that explain WHEN to use each tool and what it returns. All 7 tools have input schemas with typed parameters. However, output schemas are not explicitly documented in the visible code, only inferred from Kotlin data classes (McpLogLine, McpSearchResult, McpEntryContent). Error handling is present but minimal; descriptions focus on data semantics rather than recovery guidance. Tool composition is excellent (each tool has one clear responsibility), and parameter naming is precise (since/until/limit/service/level). No security issues detected in parameter design, no secrets exposed. Descriptions are LLM-optimized and include dependency hints ('prefer get_entity if you hold a precise key'). Baseline: avg tool description ~250 chars (p90=392), all params typed, but output schemas not formally declared.
The history of one business entity across every service and trace — the entry point when support arrives with an orderId or a userId. References are complete; bodies are sampled, so an `entryId` of null means "this was touched, the body was not kept", NOT "nothing happened". If `suppressedSince` is present, the write-side breaker tripped for this key and everything after that moment is unknown rather than absent. An unindexed key is refused, not answered empty.
Phase two. Refuses unless the report holds up, and screens every value it does release — the gate can only tighten, never unlock what the screen withheld.
The whole chain behind one traceId: a tree of spans with durations across every service, with log records placed inside the span they were made in. Read the computed flags — `noRemoteData` means the call happened and the far side never arrived (a lost link, not a call that did not happen), `unattributedMs` is time inside a span that nothing accounts for, `orphan` means the parent never arrived. A trace covers one request; an order handled by a worker an hour later lives in a different trace — use `get_entity` for that.
Services reporting to tracy: instances, last activity, clock skew, indexed entity keys, and two byte counts. `producedBytes` is what the service made, `storedRecords` is what tracy kept after sampling — the gap between them is expected, not a fault.
Output schemas not formally documented. Tool descriptions explain what is returned (e.g., 'tree of spans with durations'), but JSON Schema output definitions are absent from visible code. LLMs cannot plan downstream calls without knowing exact response field names and types.
get_entry_content description is vague ('Phase two. Refuses unless the report holds up...') and lacks actionable context. Does not explain when to call it, what 'checked' parameter means, or what fields are returned. Violates 10-1024 char guideline for clarity.
Error handling is minimal. No recovery guidance in tool descriptions. E.g., search_logs says 'absence here is not evidence of absence' but does not tell LLM what to do if a result is empty or truncated. Missing pattern:recovery-guide implementation.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
Structure of log records in a window: time, service, level, logger, message template, traceId and the *keys* of fields — never their values, which are largely written by whoever called the service. Use `get_entry_content` for values. The result is a SAMPLE: all WARN+ and all spans are kept, INFO bodies only at `sampleRate`, so absence here is not evidence of absence. If you hold a precise key such as an orderId, prefer `get_entity`.
Spans across all services in a window: name, duration, service, whether it errored. A span is a unit of work inside a trace; use `get_trace` to see the tree and the logs inside each span. The result is a SAMPLE: all errors are kept, success only at `sampleRate`.
The message templates that appear most often in a window, with counts and error rates. A template is what the developer wrote; an interpolated message is data. Use this to find the shape of the load, then `search_logs` with a `templateId` to read one.
Parameter 'templateId' in search_logs is numeric but its semantics are unclear. Description does not explain how to obtain a templateId or whether it is required. Violates param-validation-rules pattern.
Transport mechanism not visible in provided code. Dockerfile and Kotlin source show server implementation but no explicit MCP transport binding (HTTP, SSE, STDIO). Cannot verify protocol readiness without seeing transport layer.