@memlab/mcp-server
MCP server for MemLab heap snapshot analysis — gives AI coding assistants tools to explore JavaScript heap snapshots, find memory leaks, and identify optimization opportunities
Versions
2.18.1latest2.3.02.1.12.1.02.0.3+ show 3 moreshow less
2.0.22.0.12.0.0Tools 93
memlab_eval Execute arbitrary JavaScript code against the loaded heap snapshot.
memlab_property_names Index the heap
memlab_array_group_by Iterate through array (or Map/Set) elements, extract a named property from each, and
memlab_search_strings Search the content (stringValue) of all string nodes in the heap snapshot.
memlab_find_by_shape Find all objects that have a specific set of property names (multi-property intersection search). Unlike find_by_property which searches for a single property, this finds objects matching a
memlab_identify Name a minified structure from its property shape. In a production bundle nearly every class is `t`, `e`, `s` or `Object`, so the first — and often longest — step of an investigation is working out what a population actually IS: a listener record, an LRU node, a React update record, an editor-history entry. This matches a node (or a bare shape) against a library of known fingerprints and reports what it is, why it matters, and what to check next.\n\n
memlab_sliced_strings Find V8 sliced and concatenated string nodes and identify the parent strings they reference. Sliced strings share backing storage with a parent string — if the parent is a large string (e.g., a multi-MB CSV response), all slices keep the entire parent alive. This is a common cause of hidden memory leaks where small substring references retain massive parent strings. Shows parent strings ranked by parent string size.
memlab_get_property Look up a specific property (outgoing edge) of a heap node by name and return the target node with full details. Useful for traversing the object graph step by step (e.g., get the __proto__, stateNode, or memoizedState of a node).
memlab_largest_objects Find the top N objects by retained size in the loaded heap snapshot. Filters out internal/meta objects. Use node_type to filter to a specific type (e.g.,
memlab_match_object Find the object in ANOTHER loaded snapshot that corresponds to a given object in the current one.
memlab_finding_index Fingerprint a leak finding by its retainer path and check it against findings from previous rounds, so a hunt does not spend itself re-discovering a known or already-fixed leak.
memlab_metric Record a measurement under a name and keep it across sessions, so a number measured today can be compared with one measured next week.\n\n
... memlab_app_config Read the feature flags and config values the app was actually running with, out of the snapshot itself.\n\n
memlab_async_census Census PENDING ASYNC WORK: React-scheduler task queues (with a live-vs-cancelled split), timer callback closures, and unsettled Promises with their owner shapes.
memlab_app_heap Report APP-ATTRIBUTABLE heap: total self size minus bundle/code memory, minus dev-build artifacts, minus measurement-harness content — the part of the heap that is actually the application.
memlab_snapshot_header Peek a .heapsnapshot
memlab_get_value Decode the actual numeric value of a V8 SMI (Small Integer) or heap number node.
memlab_object_cost_breakdown Show per-instance V8 memory cost breakdown for a class or shape. Reports: object header overhead, heap number vs SMI property costs, property backing store costs, and collection storage overhead. Compares current cost to theoretical minimum. Use when a cache or array of objects uses more memory than expected — the gap is often V8 overhead, not a code bug.
memlab_reports Run curated memory analysis reports — like Chrome DevTools Memory panel views. Use
memlab_aggregate Aggregate heap nodes by type, name, or name prefix. Returns grouped statistics (count, total self size, aggregate retained size) sorted by retained size. Retained size uses dominator-aware aggregation (no double-counting).
memlab_object_shape Show the shape/structure of one or more heap objects: all named properties with target node types and sizes. Filters out internal/hidden edges to show only user-visible properties. Supports batch inspection via node_ids to compare multiple objects side-by-side in a single call.
memlab_next_measurement What can the snapshots currently loaded actually support — and which capture would change that?\n\n
memlab_diff_snapshots Compare two heap snapshots by class histogram. Shows classes that grew, shrunk, appeared, or disappeared between
memlab_settle_check Separate RETENTION from in-flight BACKLOG by comparing a busy snapshot against one captured after the app settled (idle + forced GC).
memlab_collection_trend Track named collections ACROSS a snapshot ladder: entry counts per rung, with per-cycle growth. memlab_cache_analysis, memlab_stale_collections and memlab_growth_signals all answer
memlab_ladder_probe Run ONE numeric probe across an ORDERED ladder of snapshots and report the series, the per-cycle rate and a linear fit.
memlab_global_variables Find non-built-in global variables on the Window object (browser) or global object (Node.js), sorted by retained size. These are application-specific globals that may indicate memory issues.
memlab_cache_analysis Detect unbounded caches — Map, Set, and Array objects that are large and likely missing eviction logic. The #1 cause of Node.js memory leaks. Reports entry count, retained size, owner object, and whether entries use WeakRef. Use this after memlab_auto_investigate or memlab_check_health flags suspicious collections.
memlab_quick_diagnosis Combined diagnosis tool that returns snapshot summary, top objects by retained size, class histogram, and duplicated strings in a single call. Saves 3-4 round trips and reduces token overhead from repeated headers. Use this as the first analysis tool after memlab_load_snapshot for an immediate comprehensive overview.
memlab_trace_dominators Auto-walk the dominator tree from a starting node, following the largest dominated child at each level until reaching leaf data or a depth limit. Returns the full chain with size annotations in a single call — eliminates the 10+ sequential get_references calls typically needed to trace from a top retainer to the actual data. Collapses repetitive Promise/PromiseReaction chains. Shows top children at the terminal node. Use as the primary tool after identifying a large retainer via auto_investigate or largest_objects.
memlab_analyze_run Point at a leak hunt
memlab_retainer_summary Trace retainer paths for multiple instances of a class (or a specific set of node IDs) and group by common patterns. Instead of tracing one node at a time, this samples N instances and shows how many share each retainer path pattern. Essential for confirming whether leaked objects share a single root cause. Use node_ids to cluster retainer patterns for specific nodes (e.g., example_node_ids from duplicated_strings). Set compact=true for abbreviated paths that use 50-70% fewer tokens.
memlab_dev_artifacts Classify large retainers as production-relevant vs. dev/automation-only (browser snapshots). Flags any object retained ONLY through a dev/extension global (__REACT_DEVTOOLS_GLOBAL_HOOK__, __REDUX_DEVTOOLS_EXTENSION__, window.Debug, …), through a Blink accessibility cache (AXObjectCacheImpl/AXNodeObject/AXDirtyObject) inflated by CDP-driven automation building the a11y tree, OR through the attached inspector\
memlab_explain_delta Explain WHERE a heap grew between two loaded snapshots, attributed by dominator (who owns the new bytes) rather than by class (what the new bytes are).
memlab_dominator_attribution Given several candidate retainers, measure how much of a population each one actually DOMINATES — i.e. what would really be freed by releasing it. Answers
memlab_for_each Structured map/filter/reduce over all heap nodes.
memlab_search_nodes General-purpose search for heap nodes by combining filters: name pattern (regex), node type, minimum retained/self size, and detachment status. Results sorted by retained size. Supports count-only and ids-only modes for large result sets.
memlab_intern_opportunities Identify string interning opportunities by grouping duplicated strings by the property name and parent object shape that holds them. Shows total savings per (property × shape) combination — the key metric for deciding where to add a string interning pool. Also surfaces ARRAY-ELEMENT / columnar duplication (strings held as elements of a rowsAsArray / string[][] result buffer — a common Nest mysql2/Drizzle shape) as first-class groups keyed by column index and array-owner shape, folded into the within-load headline; these are marked with a filled square and fixed by interning at the array-construction/parse site. The within-load figure is split at the canonical 128-char intern cap into cappable (<=128 chars, what the recommended fix reclaims) vs over-cap (longer strings the cap skips), so the headline matches what a compliant fix actually reclaims. Replaces the manual workflow of: duplicated_strings → retainer_summary → codebase grep.
memlab_duplicate_objects Find structurally-identical DUPLICATE objects — instances that carry the same content repeated many times, which a class histogram or shape histogram cannot see (they group by class or by property-NAME set, not by VALUE). Groups object instances by a shallow content signature (sorted property names + each scalar value; object-valued props marked generically) and reports, per signature, the instance count and the reclaimable own-bytes of the redundant copies.
memlab_get_node Look up a heap node by its numeric ID. Returns full details including size, type, detachment status, dominator, location, and string value if applicable.
memlab_map_entries Enumerate the entries of ONE Map or Set (node_id is REQUIRED — this is not a global scan). The companion to memlab_weakmap_entries for strongly-held collections. The KEYS are usually the whole diagnosis of an unbounded cache: a Store/singleton Map keyed by
memlab_hypothesis Test one hypothesis against EVERY rung of a snapshot ladder in a single call: supply a JavaScript predicate over heap nodes and get its match count, total self size, and trend per rung.
memlab_leak_report One-call leak triage across an ORDERED ladder of >=2 heap snapshots: runs the growth-trend pass, then gathers per-class EVIDENCE from the final snapshot and returns a single table — class, per-rung counts, Δ and Δ/cycle, how much of it is dev/automation-retained, the dominant retainer, and a verdict hint.
memlab_get_referrers Get incoming edges (referrers) to a heap node, sorted by source retained size. Shows what objects hold references to this node. Supports edge_filter (match by edge name) and offset (pagination) so a widely-referenced singleton can be explored beyond the first page — e.g.
memlab_load_snapshot Load and parse a .heapsnapshot file. This builds indexes, computes the dominator tree, and calculates retained sizes. Returns a quick diagnosis highlighting potential issues. Accepts a local absolute path, a manifold:// URL, or a bare snapshot filename (resolved against the nest_server_nodejs_heap_snapshots bucket and fetched automatically). Multiple snapshots can be kept resident — pass keep_previous:true to load several for diffing/comparison; switch between them with memlab_snapshots. Cost note: the load working set is several× the file size and the dominator pass runs uninterruptibly, so large/deep snapshots are memory- and time-heavy — run the server with NODE_OPTIONS=
memlab_sequence_analysis Trend analysis across an ORDERED sequence of >=2 heap snapshots (the canonical
memlab_script_census Census the retained JS SOURCE TEXT in the heap, and flag the same bundle being retained more than once.
memlab_string_patterns Group strings by common prefix and show aggregate counts and sizes. Instead of seeing 20 individual histogram entries for CSV strings that all start with the same header, see them grouped:
memlab_class_histogram Show per-constructor/class instance count and total self size. Useful for identifying which types of objects dominate memory.
memlab_growth_signals Heuristically flag collections that look like they grow without bound, from a SINGLE snapshot (no baseline needed). Detects Maps/Sets keyed by timestamps or sequential integers (time-series / append-only logs) and large ever-growing Arrays. Use when you have only one snapshot and want to guess what is accumulating, before confirming with a diff against a later capture.
memlab_retainer_trace Get the shortest path from a GC root to a specific heap node. This shows why the object is retained in memory by walking the pathEdge chain. Use memlab_retainer_summary to trace multiple instances of a class and group by common retainer patterns. Use memlab_get_referrers / memlab_get_references to explore incoming/outgoing edges from a node.
memlab_property_distribution For a given object class/shape and property, report the value cardinality plus the top-K most frequent values with their counts. The key tool for diagnosing cardinality explosions (e.g., an OpenTelemetry metric attribute, a cache key, or a per-record field whose unbounded distinct values blow up memory). Complements memlab_shape_histogram (which groups by property *names*) by showing the distribution of a single property
memlab_auto_investigate One-shot deep analysis: finds the top retained objects, traces each retainer chain to the GC root, identifies pinch points (small objects retaining large subtrees), and detects unbounded caches. Returns a structured report with root causes and suggested fixes. Use this as the first tool after loading a snapshot to get immediate actionable findings.
memlab_verify_fix Decide whether a fix actually worked, by comparing the per-cycle growth RATE of one metric between a before ladder and an after ladder. hunt_runner --ab drives both arms but nothing analyses them, which is why fix write-ups stall at
memlab_hunt_report Render a leak hunt
memlab_identity_diff Same objects, or just the same number of objects? Matches a population across two snapshots by CONTENT rather than by node id, which is not comparable across captures.\n\n
memlab_dominator_subtree Show the direct children in the dominator tree for a given node — i.e., objects whose retained size is exclusively attributed to this node. These are the objects that would be freed if this node were garbage collected. Useful for understanding what composes a large retained size.
memlab_event_listener_leaks Detect EventEmitter-style listener accumulation — the #1 cause of memory leaks in
memlab_pinch_points Find
memlab_event_registry Detector for per-model event registries (Backbone/Marionette/observer style): objects mapping event names to arrays of {callback, context} listeners, e.g. `{
memlab_artifact_budget ONE number for
memlab_batch Run several memlab tools against ONE snapshot load, in order, and return all their outputs together.
memlab_module_attribution Attribute heap bytes to the MODULE that owns them, by walking the dominator tree up to the nearest module-registry export.
memlab_tools Index of every memlab tool, grouped by the QUESTION it answers (
memlab_get_references Get outgoing edges (references) from a heap node, sorted by target retained size. Shows what objects this node points to — its properties, elements, and closure captures. Supports edge_filter (match by edge name) and offset (pagination) so a node with thousands of references can be explored beyond the first page. Complements memlab_get_referrers (incoming edges). Use memlab_object_shape for a quick property overview, or memlab_closure_inspection for closure-specific analysis.
memlab_find_nodes_by_class Find heap nodes by constructor/class name, exactly (class_name) or by case-insensitive regex/substring (name_pattern). Matches ANY node type by default (object, closure, array, string, native, …) — pass node_type to narrow. Ordering is controlled by order: the biggest by retained size (default), or the newest by node id. If the exact name matches nothing, reports near-miss names and the types they exist under instead of a bare
memlab_ladder Name a snapshot ladder once and reference it as `ladder:<name>` from the trend tools (memlab_sequence_analysis, memlab_leak_report, memlab_hypothesis) instead of re-typing its paths on every call.
memlab_server_status Cheap liveness/health check: returns instantly with the server process RSS, uptime, and the resident snapshots. Use it to confirm the server is responsive (vs. stuck behind a heavy scan) and to watch RSS against the snapshot-size ceiling. Scan tools are time-budgeted (timeout_ms) so a heavy scan returns cleanly instead of wedging the server; if a call ever seems hung, this check should still answer immediately.
memlab_trace_all Retainer-trace an ENTIRE population and cluster the paths server-side, instead of sampling a handful and hoping they are representative.\n\n
memlab_find_by_property Find all objects that have a specific property name (outgoing edge). Useful for identifying
memlab_collection_diff Find WHICH collections grew across a snapshot ladder, WITHOUT being told their names. Censuses every Map/Set/WeakMap/WeakSet/Array on every rung, keys each by a per-capture-STABLE `<Owner>.<property>` signature, and diffs the entry counts.
memlab_retainer_layers Counterfactual retainer analysis: answer
memlab_shape_histogram Group objects by their property structure (shape/hidden class). Objects with the same set of property names are grouped together, revealing distinct record types. Much more useful than class_histogram when most objects are generic
memlab_closure_inspection Inspect a closure (function) OR a suspended generator/async frame to show its captured/live variables.
memlab_census_diff Take the detached-DOM and listener-record census at TWO rungs and diff them per class / per callback in one call.
memlab_duplicated_strings Find duplicated string instances in the heap. Shows strings that appear multiple times, ranked by total retained size — a common source of memory waste. Use after memlab_class_histogram shows high string counts.
memlab_snapshots Manage the multi-snapshot session: list resident snapshots, switch the active one, or unload one to free memory. Also toggles session-level output controls (quiet header, suppress suggestions) to trim repeated boilerplate tokens. Load several snapshots with memlab_load_snapshot({keep_previous:true}) then switch between them by handle. Node ids are only valid within the snapshot they came from.
memlab_weakmap_entries Enumerate the key-value pairs of ONE WeakMap (node_id is REQUIRED — this is not a global scan). WeakMaps back DataStore, private fields, and metadata caches; since keys are weakly held, their entries reveal which objects are associated and what metadata is stored. First locate a WeakMap with memlab_find_nodes_by_class(
memlab_population_diff Compare the COMPOSITION of a population between two loaded snapshots, not just its size. Equal totals are not identity: a round that strands N objects and frees N others reports the same count at both ends, and reading that as
memlab_check_health Run all heuristic health checks in one call and return a prioritized list of findings. This is the recommended first step after loading a snapshot — it replaces calling 4-5 individual tools to triage.
memlab_stale_collections Find Map, Set, and Array collections holding stale references. Detects: (1) detached DOM /
memlab_snapshot_summary Get an overview of the loaded heap snapshot: total nodes, edges, size, and per-node-type breakdown with count and self size.
memlab_eval_across Run ONE `memlab_eval` program against SEVERAL resident snapshots and return the results side by side.
memlab_weakref_census Census every WeakRef in the heap, split LIVE vs EMPTY (referent already collected), and group by the shape of the object holding them.
memlab_get_string Resolve any V8 string node to its full text value. Handles all V8 string encodings:
${node.name} memlab_detached_dom Find detached DOM elements still retained in memory. These are common sources of memory leaks — DOM nodes removed from the document but kept alive by JavaScript references. Supports count-only and ids-only modes for large result sets. Use group_by to aggregate by dominator (accountable owner), element tag, retainer pattern, or data-testid.
memlab_dominator_chain Walk UPWARD through the immediate-dominator chain from a node to the GC root — the accountability chain of objects that each, if freed, would free the target. Every node on the chain exclusively dominates the target, so the nearest application-owned entry is the single owner to fix. This complements the DOWNWARD memlab_dominator_subtree / memlab_trace_dominators (what a node dominates) and the edge-based memlab_retainer_trace (a shortest reference path, which need not be a dominator). Mirrors the Chrome DevTools
memlab_referrer_summary Group all incoming references (referrers) of a node by edge name and source class.
memlab_retainer_diff A population grew between two snapshots — did it grow along the SAME retention path, or did a new one appear?\n\n
memlab_unit_cost How much memory does ONE of these actually cost? Reports dominator-deduped retained bytes per instance for a class or an object shape,
memlab_what_if If this set of objects were freed, how many bytes would actually come back? Reports the dominator-deduped retained size of a population — the bytes that go away when it does, with nothing double-counted and nothing counted that is also reachable another way.\n\n
Permissions 4
network medium filesystem low shell high env_vars low