perf-mcp-interpretation
Skill308 starsChanged 38 days agoApache-2.0View on GitHub
Interpret the mecatl perf MCP server's output to diagnose latency, goroutine leaks, GC pressure, allocation churn, and memory growth in a running mecatl harness. Use when connected to the mecatl perf MCP server (the perf:// resources or the query_metric / top_cpu_functions / capture_cpu_profile / top_allocations / list_slow_turns / capture_flight_recorder tools) and investigating why mecatl is slow, leaking, or growing. Covers tool routing/cost, reading pprof rankings and runtime metrics, and the leak/contention/GC signatures. NOT for generic Go profiling or non-mecatl MCP servers.
In this repository12 other files it gives its agents.
- AGENTS.mdAGENTS.md
- engine/AGENTS.mdAGENTS.md
- internal/AGENTS.mdAGENTS.md
- user-docs/AGENTS.mdAGENTS.md
- website/AGENTS.mdAGENTS.md
- cut-releaseSkill
- mecak8s-kind-manual-verifySkill
- mecatl-learning-configSkill
- mecatl-model-router-configSkill
- panel-reviewSkill
- perf-optimizationSkill
- tech-writerSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 91
Every histogram quantile this server returns (in perf://metrics/summary, query_metric, and gc_pause_p99_upper_bound_ns) is the upper bound …
- Very specific: line 120
User-felt latency = TTFT vs inter-token, split: Read ttft_seconds and inter_token_max_seconds separately (the mean hides both).
- Very specific: line 143
Read perf://runtime/summary and perf://metrics/summary.
- Very specific: line 147
Only if you need function-level CPU attribution, spend the rate-limited top_cpu_functions / capture_cpu_profile once.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Interpreting mecatl perf MCP output
mecatl is a streaming agentic loop. Its time is dominated by off-CPU waiting (on the model and on tool I/O), so the usual "run a CPU profile first" instinct measures the wrong thing. Diagnose by reading cheap numeric state first, and reach for the perturbing CPU tools only with a hypothesis to confirm.
Cost discipline — what to call, in what order
- Start cheap, read state.
perf://runtime/summary(goroutines, heap, GC, RSS, uptime) andperf://metrics/summary(latency-histogram quantiles) are free, point-in-time reads. Read them first, and re-readperf://runtime/summarya few times to see trends — a single snapshot rarely diagnoses anything. - Cheap tools next.
query_metric(one curated metric; omitmetric_nameto list names),top_allocations(heap rankings, no profiling window),list_slow_turns(per-turn timing) are all cheap and unlimited. - Perturbing tools last.
top_cpu_functionsandcapture_cpu_profilestart a live CPU profile that PERTURBS the process forduration_seconds, and are rate limited to one capture per cooldown window across both tools. Call them only to confirm a hypothesis, not to explore. A rate-limit hit comes back as anisErrorresult saying to retry — wait, do not retry-spam. - Never ingest raw blobs.
capture_cpu_profile(withinclude_raw_link) andcapture_flight_recorderreturn a user-audienceresource_linkto a loopback/debug/...endpoint. That link now surfaces as a TYPED BLOCK the model can see (URI + name + description) rather than a bare URI — but the model still receives only the reduced summary, never the raw blob bytes. A human downloads the linked artifact (withgo tool pprof/go tool trace); if the link ishttps://the model MAY fetch it via theFetchMcpResourcetool (SSRF-validated throughValidateMediaURL). Theperf://resources on this server are NOT https and stay server-readonly viaReadMcpResource. Do NOT try to read a linked raw artifact into model context; report the summary and point the user at the link (or fetch an https link only if you genuinely need its contents). If a perf tool's JSON result is large and you only need a subset of fields, filter it in memory withCallMcpWithQuery(server + tool +jq_filter) rather than narrowing the call — it runs the remote tool and applies a jq filter before the result enters context.
The MCP surface (what is actually there)
Resources (cheap, read-only, JSON):
perf://runtime/summary— goroutines, num_cpu, gomaxprocs, heap_allocs_total_bytes, heap_objects, total_memory_bytes, heap_object_bytes, gc_pause_count,gc_pause_p99_upper_bound_ns,rss_bytes, uptime_seconds,available[]. Note:heap_allocs_total_bytesis a cumulative COUNTER (bytes ever allocated) — a huge value (100+ GB on a long-lived process) is normal, not a leak; the leak signal is therss_bytes/heap_object_bytesslope.perf://runtime/memstats— memory-focused projection (heap_allocs_total_bytes, heap_objects, heap_object_bytes, total_memory_bytes, rss_bytes, available[]).perf://metrics/summary— every curated metric reduced: histograms → count + p50/p90/p99 bucket upper bounds (seconds); counters/gauges → a scalar value. Histograms and thetool_calls_total/tokens/turns_total/turn_empty_total/active_runscounters also carry a boundedby_rolebreakdown over the CLOSED engine role familymain|subagent|member|parallel|usermodel|child(the main engine vs the delegation children — the axis for "which agent family is burning latency/tokens"; never a session id or agent-def name).perf://pprof/{profile}— template,{profile}∈heap|goroutine|allocs|mutex|block; reduced top-15 functions (function, file basename, flat/cum values).
Tools (all read-only):
query_metric{metric_name?, quantile?, role?}— one curated metric; aggregated across all roles by default, or one role family's share withrole.top_cpu_functions{duration_seconds?, limit?}— perturbs, rate-limited.capture_cpu_profile{duration_seconds?, limit?, include_raw_link?}— perturbs, rate-limited.top_allocations{limit?}— heap top-N + total_heap_bytes.list_slow_turns{threshold_ms?, limit?, cursor?, role?}— cursor-paginated, newest first; each turn carries its bounded role family.capture_flight_recorder{}— size + one-line summary + user link (needs--flight-recorder).
See references/output-shapes.md for the exact field names of every tool's output (FuncStat, AllocStat, SlowTurn, MetricSummaryEntry).
Honest-precision caveat — do not over-trust the numbers
Every histogram quantile this server returns (in perf://metrics/summary,
query_metric, and gc_pause_p99_upper_bound_ns) is the upper bound of the
bucket the quantile rank falls in — NOT an interpolated exact quantile. The
field is literally named upper_bound for this reason. Read p99 as "at worst this
bucket's ceiling," not an exact value. Report it as an upper bound.
Interpreting the signatures
The full signature → diagnosis → next-step table is in references/signatures.md. Read it when you have a symptom to match. The essentials:
- Off-CPU workload. This loop mostly waits on the model/IO, so high CPU in
JSON decode/marshal, markdown render, or chunk decode is the real signal in
a CPU profile — that is on-CPU work on the hot streaming path. Rank by
flat(self time) for the hot leaf; usecum(includes callees) to find the responsible caller. - Goroutine leak.
goroutinesrising monotonically across successiveperf://runtime/summaryreads (not just spiking during a run) = a leak. Readperf://pprof/goroutineto see which functions hold the stuck goroutines; this corroborates the live goroutine watchdog. - Off-heap growth (the WASM-leak signature).
rss_bytesclimbing whileheap_object_bytes/total_memory_bytesstay flat = growth off the Go heap, invisible to pprof/heap and runtime metrics. (The historical cause was the RepoMap/tree-sitter WASM tool, since removed, but the pattern still stands for any off-heap consumer.) - GC-driven jitter.
gc_pause_p99_upper_bound_nsspikes and a risinggc_pause_count, alongside hightop_allocationson the streaming/chunk-decode path, explain inter-token jitter — GC pauses land between tokens. - User-felt latency = TTFT vs inter-token, split. Read
ttft_secondsandinter_token_max_secondsseparately (the mean hides both). Highttft= slow first byte; highinter_token_max= stutter the user feels mid-stream. - Dispatch contention.
mecatl_tool_queue_seconds(short nametool_queue_seconds) rising together withtool_duration_secondsp99 = the read-parallel / mutate-serial dispatcher is queueing: a slow mutating tool serially blocks queued mutations. Queue time without duration is just load; both together is the contention signal. - Tail latency. Averages lie. Use
list_slow_turnsto find the actual tail turns, thencapture_flight_recorderright after a slow turn to hand the human a trace window covering it.
Presence vs a real zero
available[] in the runtime/memstats snapshots lists which runtime/metrics fields
were actually published by this toolchain. A field absent from available[] was
not measured; a field present with value 0 is a real zero. gc_pause_count
is legitimately 0 before the first GC. query_metric returns an isError
"not present yet" for a metric with no observations — that means no relevant
activity has happened, not that the metric is broken.
Workflow
- Read
perf://runtime/summaryandperf://metrics/summary. - Match the symptom against the signatures above /
references/signatures.md. - Confirm with the cheap tool for that signature (
top_allocations,query_metric,list_slow_turns,perf://pprof/goroutine). - Only if you need function-level CPU attribution, spend the rate-limited
top_cpu_functions/capture_cpu_profileonce. - Report findings as numbers + an upper-bound caveat; point the user at any raw
resource_linkrather than ingesting it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

