MemlabBLOCK
A framework for finding JavaScript memory leaks and analyzing heap snapshots
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
MemLab
memlab is an end-to-end testing and analysis framework for identifying JavaScript memory leaks and optimization opportunities.
Online Resources: [Website] | [Doc] | [Meta Eng Blog Post] | [Tech Talk] | [AI Assistant Guide]
Features:
- Browser memory leak detection - Write test scenarios with the Puppeteer
API, and memlab will automatically compare JavaScript heap snapshots, filter out memory leaks, and aggregate the results
- Object-oriented heap traversal API - Supports the creation of
custom memory leak detectors, and enables programmatic analysis of JS heap snapshots taken from Chromium-based browsers, Node.js, Electron.js, and Hermes
- Memory CLI toolbox - Built-in toolbox and APIs for finding memory
optimization opportunities (not necessarily just memory leaks)
- MemLens: Browser Memory Debugging Tools - Enables visualization of memory
leaks and interactive memory debugging in the browser.
- Memory assertions in Node.js - Enables unit tests or running node.js
programs to take a heap snapshot of their own state, perform self memory checking, or write advanced memory assertions
- **MCP se
c52c9c0a8489OBSERVED · 2026-10-12Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control.
claude mcp add memlab-website -- npx -y [email protected]
{
"mcpServers": {
"memlab-website": {
"command": "npx",
"args": [
"-y",
"[email protected]"
]
}
}
}Exposed tools (140)
119 read · 21 write · 0 destructive.
| Tool | Risk | Description |
|---|---|---|
class_histogram | read | Show instance count and total self size per class/constructor name |
detached_dom | read | Find detached DOM elements still retained in memory — common source of leaks |
duplicated_strings | read | Find duplicated string instances ranked by total size — common source of waste |
global_variables | read | Find non-built-in global variables on Window, sorted by retained size |
largest_objects | read | Find the top objects by retained size in the heap |
memlab_aggregate | read | 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_analysis_battery | write | Run a round |
memlab_analyze_run | write | Point at a leak hunt |
memlab_anonymize_snapshot | read | |
memlab_app_config | read | Read the feature flags and config values the app was actually running with, out of the snapshot itself.\n\n |
memlab_app_heap | read | 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_array_group_by | write | Iterate through array (or Map/Set) elements, extract a named property from each, and |
memlab_artifact_budget | read | ONE number for |
memlab_async_census | read | 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_auto_investigate | read | |
memlab_batch | write | Run several memlab tools against ONE snapshot load, in order, and return all their outputs together. |
memlab_battery_status | read | Report on a battery started with |
memlab_build_provenance | read | Assert that the build a snapshot came from actually contains the change you are measuring, BEFORE reading any before/after number. Scans the heap for marker strings from the new revision ( |
memlab_cache_analysis | read | |
memlab_cache_inventory | write | Inventory of MODULE-SCOPE collections (Map / Set / WeakMap / Array held directly by a Haste module |
memlab_calibrate_judges | read | |
memlab_census | read | Count several named POPULATIONS across every rung of a ladder in ONE pass per snapshot, and report each one |
memlab_census_diff | read | Take the detached-DOM and listener-record census at TWO rungs and diff them per class / per callback in one call. |
memlab_chain_walk | read | Walk a repeated linked structure from a starting node and report how deep it goes and what it holds — for closure chains ( |
memlab_check_health | write | 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_class_histogram | read | Show per-constructor/class instance count and total self size. Useful for identifying which types of objects dominate memory. |
memlab_closure_inspection | read | Inspect a closure (function) OR a suspended generator/async frame to show its captured/live variables. |
memlab_collection_diff | read | 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 |
memlab_collection_trend | read | 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_compare_rounds | read | Compare N rounds of a sweep and surface the patterns no single round shows.\n\n |
memlab_console_retention | read | Report what an attached DevTools console is keeping alive, and answer whether a specific object depends on it. DevTools holds a global handle on every object passed to |
memlab_count_population | read | Count one population by SEVERAL independent methods and report when they disagree.\n\n |
memlab_detached_dom | read | |
memlab_dev_artifacts | read | |
memlab_dev_subtracted_delta | read | Per-class growth from |
memlab_diff_snapshots | read | Compare two heap snapshots by class histogram. Shows classes that grew, shrunk, appeared, or disappeared between |
memlab_dom_audit | read | Budget the ATTACHED DOM and rank the surfaces worth virtualizing. This is an OPTIMIZATION tool, not a leak tool — the elements it reports are all live and correctly retained; the point is that there are too many of them.\n\n |
memlab_dominator_attribution | read | 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_dominator_chain | read | |
memlab_dominator_subtree | read | 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_drill_to_heavy_leaf | read | Follow the retained size DOWN from one node to the object actually holding it, in a single call.\n\n |
memlab_duplicate_objects | read | |
memlab_duplicated_strings | read | 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_eval | write | Execute arbitrary JavaScript code against the loaded heap snapshot. |
memlab_eval_across | write | Run ONE |
memlab_event_listener_leaks | read | Detect EventEmitter-style listener accumulation — the #1 cause of memory leaks in |
memlab_event_registry | read | Detector for per-model event registries (Backbone/Marionette/observer style): objects mapping event names to arrays of {callback, context} listeners, e.g. |
memlab_explain_delta | read | 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_external_strings | read | Attribute |
memlab_field_release_impact | read | If a fix nulls this property, how many bytes actually come back — and is the property the ONLY reference?\n\n |
memlab_find_by_property | read | Find all objects that have a specific property name (outgoing edge). Useful for identifying |
memlab_find_by_shape | write | 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_find_nodes_by_class | read | |
memlab_finding_index | read | 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_for_each | read | Structured map/filter/reduce over all heap nodes. |
memlab_gate_fingerprint | read | Decide which EXPERIMENT ARM the loaded capture is in by comparing it against a capture of the other arm, for gates |
memlab_get_node | read | 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_get_property | read | 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_get_references | read | |
memlab_get_referrers | read | 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_get_string | read | Resolve any V8 string node to its full text value. Handles all V8 string encodings: |
memlab_get_value | read | Decode the actual numeric value of a V8 SMI (Small Integer) or heap number node. |
memlab_global_variables | read | 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_growth_cohort | read | Group the NEWEST instances of a population by who holds them — top referrer edges, top shapes, top root-path heads, and their dominator-deduped retained size.\n\n |
memlab_growth_signals | read | |
memlab_hunt_report | read | Render a leak hunt |
memlab_hypothesis | read | 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_id_space_audit | read | |
memlab_identify | read | Name a minified structure from its property shape. In a production bundle nearly every class is |
memlab_identity_diff | read | 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_intern_opportunities | read | |
memlab_island_doors | read | List EVERY production-reachable reference into an island, not just the shortest one. |
memlab_job_status | read | Report on a job started with |
memlab_judges | read | Judge a leak-hunt round against its stated INVARIANTS — plain-words claims about what must hold once the app is at rest — instead of reading |
memlab_ladder | read | Name a snapshot ladder once and reference it as |
memlab_ladder_probe | write | Run ONE numeric probe across an ORDERED ladder of snapshots and report the series, the per-cycle rate and a linear fit. |
memlab_largest_objects | read | 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_leak_report | read | |
memlab_load_snapshot | read | |
memlab_map_entries | write | 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_match_object | read | Find the object in ANOTHER loaded snapshot that corresponds to a given object in the current one. |
memlab_metric | read | 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_module_attribution | read | Attribute heap bytes to the MODULE that owns them, by walking the dominator tree up to the nearest module-registry export or module SCOPE (the top-level closure context a Haste |
memlab_module_present | read | Pre-flight: does a class/constructor appear in this heap AT ALL? Answers |
memlab_next_measurement | read | What can the snapshots currently loaded actually support — and which capture would change that?\n\n |
memlab_object_cost_breakdown | read | |
memlab_object_shape | read | 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_overlap_matrix | read | Do these classes retain the SAME bytes? Reports pairwise overlap in dominator-deduped retained size, plus the |
memlab_persistent_structures | read | Detect persistent / structurally-shared data structures (Immutable.js Maps, Lists and trie nodes; Immer drafts; RxJS-style Subscriptions) and report how many VERSIONS are retained, with dominator-deduped bytes. Use it whenever a leak report shows growth in short minified classes ( |
memlab_pinch_points | read | Find |
memlab_population_diff | read | 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_population_vs_owners | read | Decide whether a population is STRUCTURAL (about one record per live owner) or ACCUMULATING (owners are collecting records), by counting both and reporting the ratio. |
memlab_positive_controls | read | Measure the round\ |
memlab_property_distribution | read | |
memlab_property_names | read | Index the heap |
memlab_prune_run | write | Reclaim the disk a round |
memlab_quick_diagnosis | read | |
memlab_rate_model | write | Is this population UNBOUNDED, or is it a working set whose size is just a function of how fast the harness drove?\n\n |
memlab_rate_table | read | Build the per-surface, per-cycle rate table for ONE metric across several rounds — the artifact that says which surface to fix first.\n\n |
memlab_react_owners | read | Name the React COMPONENT behind a population of plain |
memlab_react_update_queues | write | The React eager-bailout leak family as one report. A |
memlab_referrer_summary | read | Group all incoming references (referrers) of a node by edge name and source class. |
memlab_replicate | read | Ask whether a measured effect REPRODUCES across two or more independently-driven runs, and refuse to call it real until it does. |
memlab_reports | write | Run curated memory analysis reports — like Chrome DevTools Memory panel views. Use |
memlab_retainer_diff | read | A population grew between two snapshots — did it grow along the SAME retention path, or did a new one appear?\n\n |
memlab_retainer_layers | read | Counterfactual retainer analysis: answer |
memlab_retainer_summary | read | |
memlab_retainer_trace | read | |
memlab_retention_windows | read | List the retention windows this app has — timeouts, TTLs, cleanup intervals, eviction ages — before calling any growth unbounded.\n\n |
memlab_round_audit | read | Read a leak hunt |
memlab_round_digest | read | The verdict table for a finished leak-hunt round, and nothing else. |
memlab_script_census | read | Census the retained JS SOURCE TEXT in the heap, and flag the same bundle being retained more than once. |
memlab_search_nodes | read | 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_search_strings | read | Search the content (stringValue) of all string nodes in the heap snapshot. |
memlab_sequence_analysis | read | Trend analysis across an ORDERED sequence of >=2 heap snapshots (the canonical |
memlab_server_status | read | Cheap liveness/health check: returns instantly with the server VERSION, process RSS, uptime, and the resident snapshots. The version answers |
memlab_settle_check | read | Separate RETENTION from in-flight BACKLOG by comparing a busy snapshot against one captured after the app settled (idle + forced GC). |
memlab_shape_census_diff | write | Per-SHAPE growth across a LADDER: group objects by their property set at every rung and report the series, the per-cycle rate and the fit — the shape-level equivalent of |
memlab_shape_histogram | read | 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_sliced_strings | read | |
memlab_snapshot_budget_planner | read | Which rungs of this ladder can you actually hold in memory at once, and which should be probed transiently?\n\n |
memlab_snapshot_header | read | Peek a .heapsnapshot |
memlab_snapshot_summary | read | Get an overview of the loaded heap snapshot: total nodes, edges, size, and per-node-type breakdown with count and self size. |
memlab_snapshots | read | |
memlab_source_for_node | read | Which MODULE\ |
memlab_sparse_elements | read | Find integer-keyed objects and arrays whose ELEMENTS BACKING STORE is mostly holes — memory V8 has allocated and the application never uses. This is the waste a class histogram cannot see: the store is a |
memlab_stale_collections | write | Find Map, Set, and Array collections holding stale references. Detects: (1) detached DOM / |
memlab_stale_refs | read | React refs ( |
memlab_start_job | write | Start ANY memlab tool as a background job and return a job id at once; collect the result with |
memlab_string_patterns | read | 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_switch_matrix | write | Prove the judges can go red: run every invariant judge (as |
memlab_tools | read | Index of every memlab tool, grouped by the QUESTION it answers ( |
memlab_trace_all | read | Retainer-trace an ENTIRE population and cluster the paths server-side, instead of sampling a handful and hoping they are representative.\n\n |
memlab_trace_dominators | read | |
memlab_unit_cost | read | How much memory does ONE of these actually cost? Reports dominator-deduped retained bytes per instance for a class or an object shape, |
memlab_verify_fix | read | 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_weakmap_entries | read | |
memlab_weakref_census | read | Census every WeakRef in the heap, split LIVE vs EMPTY (referent already collected), and group by the shape of the object holding them. |
memlab_what_if | write | 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 |
stale_collections | write | Find Map/Set/Array collections holding references to detached or unmounted nodes |
Trust audit
BLOCKgrade D · trust 60/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | WARN |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (5 observation(s))
- Network
- declared (5 observation(s))
- Shell
- declared (5 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (25)
(val.includes('function(') && val.includes('module'))'- ⚠ `node.retainedSize` / `node.retained_size` THROW inside eval (they read back ~0 on some loads). Use `helpers.retainedSize(id)` / `helpers.retainedSizes([ids])` / `helpers.aggregateRetained([ids])
'- `helpers.rootPath(nodeOrId, {maxHops?}) -> [{id, name, type, edge}]` — the GC-root path for one node, root first, exactly as `memlab_retainer_trace` walks it. Saves hand-writing the `while (cur.has.env
docs
apiKey: 'ad4054e5f8136d8d79b1124ba77ada30',
.watchmanconfig
.eslintrc.js
.env
.prettierignore
.nojekyll
eval(script);
const key = `para:${crypto.createHash('sha1').update(t).digest('hex')}`;return crypto.createHash('sha1').update(material).digest('hex').slice(0, 12);import {run} from '../../index';import {DetachedDOMElementAnalysis, warmupAndTakeSnapshots} from '../../index';import type {BrowserInteractionResultReader} from '../../index';import {ObjectShallowAnalysis, warmupAndTakeSnapshots} from '../../index';import {run} from '../../index';? atob(response.body)
ansi, babar, blessed, chalk, fs-extra, minimist, string-width, util.promisify
@memlab/core, @memlab/e2e, @memlab/heap-analysis, ansi, babar, chalk, fs-extra, minimist
@memlab/api, @memlab/core, @memlab/e2e, @memlab/heap-analysis, ansi, babar, blessed, chalk
ansi, babar, chalk, fs-extra, minimist, string-width, util.promisify, xvfb
@babel/generator, @babel/parser, @babel/template, @babel/traverse, @memlab/core, @memlab/lens, ansi, babar
Gates applied: no_behavioural_pass.
c52c9c0a8489full audit observations/trust-audit/mcp-server/facebook__memlab.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-12 | c52c9c0a8489 | BLOCK | D | 60 | first audit |
Questions
What is the @memlab/mcp-server MCP server?
A framework for finding JavaScript memory leaks and analyzing heap snapshots
What tools does @memlab/mcp-server expose?
140 in total: 119 read-only, 21 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.
Is @memlab/mcp-server safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (60/100) and found 3 critical or high issues in the source. Each one is listed on this page with the file and line it is on.
What credentials does @memlab/mcp-server need?
No credential environment variables were found in its source, so it appears to need none.
How does @memlab/mcp-server run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as memlab-website at 1.0.1.
How current is this page?
The grade is for one exact copy of the source (c52c9c0a8489), read on 2026-10-12. The repository is watched and re-audited when it changes.