@memlab/mcp-server 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +23 -13
  2. package/bin/memlab-mcp.js +9 -0
  3. package/dist/heap-state.d.ts +12 -1
  4. package/dist/heap-state.d.ts.map +1 -1
  5. package/dist/heap-state.js +10 -4
  6. package/dist/heap-state.js.map +1 -1
  7. package/dist/index.js +29 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/tools/aggregate-nodes.d.ts.map +1 -1
  10. package/dist/tools/aggregate-nodes.js +2 -2
  11. package/dist/tools/aggregate-nodes.js.map +1 -1
  12. package/dist/tools/auto-investigate.d.ts +12 -0
  13. package/dist/tools/auto-investigate.d.ts.map +1 -0
  14. package/dist/tools/auto-investigate.js +683 -0
  15. package/dist/tools/auto-investigate.js.map +1 -0
  16. package/dist/tools/cache-analysis.d.ts +12 -0
  17. package/dist/tools/cache-analysis.d.ts.map +1 -0
  18. package/dist/tools/cache-analysis.js +341 -0
  19. package/dist/tools/cache-analysis.js.map +1 -0
  20. package/dist/tools/check-health.d.ts +12 -0
  21. package/dist/tools/check-health.d.ts.map +1 -0
  22. package/dist/tools/check-health.js +289 -0
  23. package/dist/tools/check-health.js.map +1 -0
  24. package/dist/tools/class-histogram.d.ts.map +1 -1
  25. package/dist/tools/class-histogram.js +70 -14
  26. package/dist/tools/class-histogram.js.map +1 -1
  27. package/dist/tools/closure-inspection.d.ts.map +1 -1
  28. package/dist/tools/closure-inspection.js +5 -5
  29. package/dist/tools/closure-inspection.js.map +1 -1
  30. package/dist/tools/detached-dom.d.ts.map +1 -1
  31. package/dist/tools/detached-dom.js +151 -5
  32. package/dist/tools/detached-dom.js.map +1 -1
  33. package/dist/tools/diff-snapshots.d.ts +12 -0
  34. package/dist/tools/diff-snapshots.d.ts.map +1 -0
  35. package/dist/tools/diff-snapshots.js +224 -0
  36. package/dist/tools/diff-snapshots.js.map +1 -0
  37. package/dist/tools/dominator-subtree.d.ts.map +1 -1
  38. package/dist/tools/dominator-subtree.js +29 -4
  39. package/dist/tools/dominator-subtree.js.map +1 -1
  40. package/dist/tools/duplicated-strings.d.ts.map +1 -1
  41. package/dist/tools/duplicated-strings.js +62 -9
  42. package/dist/tools/duplicated-strings.js.map +1 -1
  43. package/dist/tools/eval.d.ts.map +1 -1
  44. package/dist/tools/eval.js +111 -7
  45. package/dist/tools/eval.js.map +1 -1
  46. package/dist/tools/event-listener-leaks.d.ts +12 -0
  47. package/dist/tools/event-listener-leaks.d.ts.map +1 -0
  48. package/dist/tools/event-listener-leaks.js +266 -0
  49. package/dist/tools/event-listener-leaks.js.map +1 -0
  50. package/dist/tools/find-by-property.d.ts.map +1 -1
  51. package/dist/tools/find-by-property.js +38 -4
  52. package/dist/tools/find-by-property.js.map +1 -1
  53. package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
  54. package/dist/tools/find-nodes-by-class.js +4 -4
  55. package/dist/tools/find-nodes-by-class.js.map +1 -1
  56. package/dist/tools/for-each.d.ts.map +1 -1
  57. package/dist/tools/for-each.js +2 -2
  58. package/dist/tools/for-each.js.map +1 -1
  59. package/dist/tools/get-node.d.ts.map +1 -1
  60. package/dist/tools/get-node.js +2 -2
  61. package/dist/tools/get-node.js.map +1 -1
  62. package/dist/tools/get-property.d.ts.map +1 -1
  63. package/dist/tools/get-property.js +4 -4
  64. package/dist/tools/get-property.js.map +1 -1
  65. package/dist/tools/get-references.d.ts.map +1 -1
  66. package/dist/tools/get-references.js +11 -5
  67. package/dist/tools/get-references.js.map +1 -1
  68. package/dist/tools/get-referrers.d.ts.map +1 -1
  69. package/dist/tools/get-referrers.js +11 -5
  70. package/dist/tools/get-referrers.js.map +1 -1
  71. package/dist/tools/global-variables.d.ts.map +1 -1
  72. package/dist/tools/global-variables.js +10 -6
  73. package/dist/tools/global-variables.js.map +1 -1
  74. package/dist/tools/largest-objects.d.ts.map +1 -1
  75. package/dist/tools/largest-objects.js +78 -8
  76. package/dist/tools/largest-objects.js.map +1 -1
  77. package/dist/tools/load-snapshot.d.ts.map +1 -1
  78. package/dist/tools/load-snapshot.js +118 -4
  79. package/dist/tools/load-snapshot.js.map +1 -1
  80. package/dist/tools/object-shape.d.ts.map +1 -1
  81. package/dist/tools/object-shape.js +66 -47
  82. package/dist/tools/object-shape.js.map +1 -1
  83. package/dist/tools/pinch-points.d.ts +12 -0
  84. package/dist/tools/pinch-points.d.ts.map +1 -0
  85. package/dist/tools/pinch-points.js +124 -0
  86. package/dist/tools/pinch-points.js.map +1 -0
  87. package/dist/tools/quick-diagnosis.d.ts +12 -0
  88. package/dist/tools/quick-diagnosis.d.ts.map +1 -0
  89. package/dist/tools/quick-diagnosis.js +213 -0
  90. package/dist/tools/quick-diagnosis.js.map +1 -0
  91. package/dist/tools/referrer-summary.d.ts +12 -0
  92. package/dist/tools/referrer-summary.d.ts.map +1 -0
  93. package/dist/tools/referrer-summary.js +119 -0
  94. package/dist/tools/referrer-summary.js.map +1 -0
  95. package/dist/tools/reports.d.ts.map +1 -1
  96. package/dist/tools/reports.js +5 -5
  97. package/dist/tools/reports.js.map +1 -1
  98. package/dist/tools/retainer-summary.d.ts +12 -0
  99. package/dist/tools/retainer-summary.d.ts.map +1 -0
  100. package/dist/tools/retainer-summary.js +307 -0
  101. package/dist/tools/retainer-summary.js.map +1 -0
  102. package/dist/tools/retainer-trace.d.ts.map +1 -1
  103. package/dist/tools/retainer-trace.js +88 -14
  104. package/dist/tools/retainer-trace.js.map +1 -1
  105. package/dist/tools/search-nodes.d.ts.map +1 -1
  106. package/dist/tools/search-nodes.js +2 -2
  107. package/dist/tools/search-nodes.js.map +1 -1
  108. package/dist/tools/shape-histogram.d.ts +12 -0
  109. package/dist/tools/shape-histogram.d.ts.map +1 -0
  110. package/dist/tools/shape-histogram.js +119 -0
  111. package/dist/tools/shape-histogram.js.map +1 -0
  112. package/dist/tools/sliced-strings.d.ts +12 -0
  113. package/dist/tools/sliced-strings.d.ts.map +1 -0
  114. package/dist/tools/sliced-strings.js +126 -0
  115. package/dist/tools/sliced-strings.js.map +1 -0
  116. package/dist/tools/snapshot-summary.d.ts.map +1 -1
  117. package/dist/tools/snapshot-summary.js +42 -3
  118. package/dist/tools/snapshot-summary.js.map +1 -1
  119. package/dist/tools/stale-collections.d.ts.map +1 -1
  120. package/dist/tools/stale-collections.js +30 -6
  121. package/dist/tools/stale-collections.js.map +1 -1
  122. package/dist/tools/string-patterns.d.ts +12 -0
  123. package/dist/tools/string-patterns.d.ts.map +1 -0
  124. package/dist/tools/string-patterns.js +115 -0
  125. package/dist/tools/string-patterns.js.map +1 -0
  126. package/dist/tools/trace-dominators.d.ts +12 -0
  127. package/dist/tools/trace-dominators.d.ts.map +1 -0
  128. package/dist/tools/trace-dominators.js +237 -0
  129. package/dist/tools/trace-dominators.js.map +1 -0
  130. package/dist/utils.d.ts +9 -1
  131. package/dist/utils.d.ts.map +1 -1
  132. package/dist/utils.js +67 -5
  133. package/dist/utils.js.map +1 -1
  134. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import memlabCore from '@memlab/core';
11
+ const { utils, NumericSet } = memlabCore;
12
+ import { z } from 'zod';
13
+ import { getSnapshot } from '../heap-state.js';
14
+ import { formatBytes, formatNumber, errorResult, toolResult } from '../utils.js';
15
+ function getPropertyNames(node) {
16
+ const names = [];
17
+ for (const edge of node.references) {
18
+ if (edge.type === 'property') {
19
+ names.push(String(edge.name_or_index));
20
+ }
21
+ }
22
+ if (names.length === 0)
23
+ return null;
24
+ names.sort();
25
+ return names;
26
+ }
27
+ export function registerShapeHistogram(server) {
28
+ server.tool('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 "Object" — this tells you exactly what data structures exist and how much memory each shape consumes. Essential for data-heavy apps where millions of "Object" instances hide 3-5 distinct record shapes.', {
29
+ limit: z
30
+ .number()
31
+ .optional()
32
+ .default(20)
33
+ .describe('Maximum number of shapes to return (default 20)'),
34
+ min_count: z
35
+ .number()
36
+ .optional()
37
+ .default(2)
38
+ .describe('Minimum instance count to include (default 2)'),
39
+ min_retained_size: z
40
+ .number()
41
+ .optional()
42
+ .describe('Minimum aggregate retained size in bytes to include (e.g., 1048576 for 1 MB)'),
43
+ class_name: z
44
+ .string()
45
+ .optional()
46
+ .describe('Filter to objects with this constructor name (e.g., "Object"). If omitted, includes all object-type nodes.'),
47
+ }, async ({ limit, min_count, min_retained_size, class_name }) => {
48
+ try {
49
+ const snapshot = getSnapshot();
50
+ const shapeMap = new Map();
51
+ snapshot.nodes.forEach(node => {
52
+ if (node.type !== 'object')
53
+ return;
54
+ if (node.id <= 3)
55
+ return;
56
+ if (class_name && node.name !== class_name)
57
+ return;
58
+ const props = getPropertyNames(node);
59
+ if (!props)
60
+ return;
61
+ const key = props.join(',');
62
+ const existing = shapeMap.get(key);
63
+ if (existing) {
64
+ existing.count++;
65
+ existing.totalSelfSize += node.self_size;
66
+ existing.nodeIds.add(node.id);
67
+ }
68
+ else {
69
+ shapeMap.set(key, {
70
+ properties: props,
71
+ count: 1,
72
+ totalSelfSize: node.self_size,
73
+ nodeIds: new NumericSet([node.id]),
74
+ exampleNodeId: node.id,
75
+ });
76
+ }
77
+ });
78
+ const filtered = [...shapeMap.values()].filter(g => g.count >= min_count);
79
+ const withRetained = filtered.map(g => {
80
+ const retainedSize = utils.aggregateDominatorMetrics(g.nodeIds, snapshot, () => true, (node) => node.retainedSize);
81
+ return { ...g, retainedSize };
82
+ });
83
+ let finalList = withRetained;
84
+ if (min_retained_size != null) {
85
+ finalList = finalList.filter(g => g.retainedSize >= min_retained_size);
86
+ }
87
+ finalList.sort((a, b) => b.retainedSize - a.retainedSize);
88
+ finalList = finalList.slice(0, limit);
89
+ if (finalList.length === 0) {
90
+ return toolResult('No object shapes found matching the criteria. Try lowering min_count or removing class_name filter.');
91
+ }
92
+ const lines = [
93
+ `## Object Shape Histogram`,
94
+ `${formatNumber(shapeMap.size)} distinct shapes found, showing top ${finalList.length}`,
95
+ '',
96
+ ];
97
+ for (let i = 0; i < finalList.length; i++) {
98
+ const g = finalList[i];
99
+ const propsDisplay = g.properties.length <= 8
100
+ ? `{${g.properties.join(', ')}}`
101
+ : `{${g.properties.slice(0, 6).join(', ')}, … +${g.properties.length - 6} more}`;
102
+ lines.push(`${i + 1}. **${propsDisplay}** — ${formatNumber(g.count)} instances, ${formatBytes(g.retainedSize)} retained, ${formatBytes(g.totalSelfSize)} self`);
103
+ lines.push(` Example: @${g.exampleNodeId}`);
104
+ }
105
+ lines.push('', '**Suggested next steps:**');
106
+ const top = finalList[0];
107
+ lines.push(`- Inspect example: \`memlab_object_shape(${top.exampleNodeId})\``);
108
+ lines.push(`- Trace retention: \`memlab_retainer_trace(${top.exampleNodeId})\``);
109
+ if (finalList.length > 1) {
110
+ lines.push(`- Compare shapes: \`memlab_object_shape\` on examples from different shapes`);
111
+ }
112
+ return toolResult(lines.join('\n'));
113
+ }
114
+ catch (err) {
115
+ return errorResult(err);
116
+ }
117
+ });
118
+ }
119
+ //# sourceMappingURL=shape-histogram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape-histogram.js","sourceRoot":"","sources":["../../src/tools/shape-histogram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ export declare function registerSlicedStrings(server: McpServer): void;
12
+ //# sourceMappingURL=sliced-strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliced-strings.d.ts","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAsBvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6I7D"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import { z } from 'zod';
11
+ import { getSnapshot } from '../heap-state.js';
12
+ import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
13
+ export function registerSlicedStrings(server) {
14
+ server.tool('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.', {
15
+ limit: z
16
+ .number()
17
+ .optional()
18
+ .default(20)
19
+ .describe('Maximum number of parent strings to return (default 20)'),
20
+ min_parent_size: z
21
+ .number()
22
+ .optional()
23
+ .describe('Minimum parent string self size in bytes to include. Use to focus on large parents (e.g., 1048576 for 1 MB).'),
24
+ }, async ({ limit, min_parent_size }) => {
25
+ try {
26
+ const snapshot = getSnapshot();
27
+ let slicedCount = 0;
28
+ let concatCount = 0;
29
+ let slicedTotalSize = 0;
30
+ let concatTotalSize = 0;
31
+ // Map from parent node ID -> stats
32
+ const parentMap = new Map();
33
+ snapshot.nodes.forEach(node => {
34
+ const isSliced = node.type === 'string' && node.name === 'system / SlicedString';
35
+ const isConcat = node.type === 'concatenated string' ||
36
+ (node.type === 'string' && node.name === 'system / ConsString');
37
+ if (!isSliced && !isConcat)
38
+ return;
39
+ if (isSliced) {
40
+ slicedCount++;
41
+ slicedTotalSize += node.self_size;
42
+ }
43
+ else {
44
+ concatCount++;
45
+ concatTotalSize += node.self_size;
46
+ }
47
+ // For sliced strings, follow the 'parent' edge to find the
48
+ // backing string
49
+ for (const edge of node.references) {
50
+ const target = edge.toNode;
51
+ if (target.type !== 'string')
52
+ continue;
53
+ // Skip other sliced/concat strings — find the actual parent
54
+ if (target.name === 'system / SlicedString' ||
55
+ target.name === 'system / ConsString') {
56
+ continue;
57
+ }
58
+ const existing = parentMap.get(target.id);
59
+ if (existing) {
60
+ existing.sliced_ref_count++;
61
+ existing.sliced_total_size += node.self_size;
62
+ }
63
+ else {
64
+ parentMap.set(target.id, {
65
+ id: target.id,
66
+ name: target.name,
67
+ self_size: target.self_size,
68
+ retained_size: target.retainedSize,
69
+ sliced_ref_count: 1,
70
+ sliced_total_size: node.self_size,
71
+ });
72
+ }
73
+ }
74
+ });
75
+ if (slicedCount === 0 && concatCount === 0) {
76
+ return toolResult('No sliced or concatenated strings found in the snapshot.');
77
+ }
78
+ let parents = [...parentMap.values()];
79
+ if (min_parent_size != null) {
80
+ parents = parents.filter(p => p.self_size >= min_parent_size);
81
+ }
82
+ parents.sort((a, b) => b.self_size - a.self_size);
83
+ const topParents = parents.slice(0, limit);
84
+ const lines = [];
85
+ lines.push(`**Sliced strings:** ${formatNumber(slicedCount)} nodes (${formatBytes(slicedTotalSize)} self size)`);
86
+ if (concatCount > 0) {
87
+ lines.push(`**Concatenated strings:** ${formatNumber(concatCount)} nodes (${formatBytes(concatTotalSize)} self size)`);
88
+ }
89
+ lines.push(`**Unique parent strings referenced:** ${formatNumber(parentMap.size)}`);
90
+ lines.push('');
91
+ if (topParents.length > 0) {
92
+ const headers = [
93
+ 'Parent ID',
94
+ 'Content',
95
+ 'Parent Size',
96
+ 'Retained',
97
+ 'Sliced Refs',
98
+ 'Slices Size',
99
+ ];
100
+ const rightCols = new Set([2, 3, 4, 5]);
101
+ const rows = topParents.map(p => [
102
+ `@${p.id}`,
103
+ truncateNodeName(p.name, 'string', p.self_size, 80),
104
+ formatBytes(p.self_size),
105
+ formatBytes(p.retained_size),
106
+ formatNumber(p.sliced_ref_count),
107
+ formatBytes(p.sliced_total_size),
108
+ ]);
109
+ lines.push('### Top parent strings (keeping slices alive)');
110
+ lines.push('');
111
+ lines.push(markdownTable(headers, rows, rightCols));
112
+ const largeMB = topParents.filter(p => p.self_size >= 1024 * 1024);
113
+ if (largeMB.length > 0) {
114
+ const totalLarge = largeMB.reduce((s, p) => s + p.self_size, 0);
115
+ lines.push('');
116
+ lines.push(`**⚠ ${largeMB.length} parent string(s) > 1 MB (${formatBytes(totalLarge)} total).** Small substrings (slices) are keeping these large strings alive. Consider copying substring values instead of slicing, or nullifying references to the source data after extraction.`);
117
+ }
118
+ }
119
+ return toolResult(lines.join('\n'));
120
+ }
121
+ catch (err) {
122
+ return errorResult(err);
123
+ }
124
+ });
125
+ }
126
+ //# sourceMappingURL=sliced-strings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliced-strings.js","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot-summary.d.ts","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmF/D"}
1
+ {"version":3,"file":"snapshot-summary.d.ts","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAcvE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmI/D"}
@@ -10,9 +10,9 @@
10
10
  import memlabCore from '@memlab/core';
11
11
  const { utils, NumericSet } = memlabCore;
12
12
  import { getSnapshot, getFilePath } from '../heap-state.js';
13
- import { formatBytes, formatNumber, markdownTable, errorResult, textResult, } from '../utils.js';
13
+ import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
14
14
  export function registerSnapshotSummary(server) {
15
- server.tool('memlab_snapshot_summary', 'Get an overview of the loaded heap snapshot: total nodes, edges, size, and breakdown by node type with count, self size, and aggregate retained size (dominator-aware, no double-counting).', {}, async () => {
15
+ server.tool('memlab_snapshot_summary', 'Get an overview of the loaded heap snapshot: total nodes, edges, size, and breakdown by node type with count, self size, and aggregate retained size (dominator-aware, no double-counting). Includes anomaly detection for high-count classes that may indicate leaks. Follow up with memlab_class_histogram for per-class breakdown, or memlab_duplicated_strings to find string duplication.', {}, async () => {
16
16
  try {
17
17
  const snapshot = getSnapshot();
18
18
  let nodeCount = 0;
@@ -63,7 +63,46 @@ export function registerSnapshotSummary(server) {
63
63
  formatBytes(b.retained_size),
64
64
  ]);
65
65
  lines.push(markdownTable(headers, rows, rightCols));
66
- return textResult(lines.join('\n'));
66
+ // Anomaly detection: find classes with unusually high instance counts
67
+ const classMap = new Map();
68
+ snapshot.nodes.forEach(node => {
69
+ if (node.id <= 3)
70
+ return;
71
+ if (node.type === 'hidden' || node.type === 'array')
72
+ return;
73
+ const key = `${node.type}::${node.name}`;
74
+ const entry = classMap.get(key);
75
+ if (entry) {
76
+ entry.count++;
77
+ }
78
+ else {
79
+ classMap.set(key, { count: 1, type: node.type });
80
+ }
81
+ });
82
+ const anomalies = [...classMap.entries()]
83
+ .filter(([, v]) => v.count >= 5000)
84
+ .sort((a, b) => b[1].count - a[1].count)
85
+ .slice(0, 5);
86
+ if (anomalies.length > 0) {
87
+ lines.push('');
88
+ lines.push('**Potential anomalies** (classes with ≥5,000 instances):');
89
+ for (const [key, v] of anomalies) {
90
+ const name = key.split('::').slice(1).join('::');
91
+ lines.push(`- ${formatNumber(v.count)}× \`${name}\` (${v.type})`);
92
+ }
93
+ // Check for correlated high-count groups
94
+ const highCountNames = anomalies.map(([key]) => key.split('::').slice(1).join('::'));
95
+ if (highCountNames.length >= 2) {
96
+ const counts = anomalies.map(([, v]) => v.count);
97
+ const maxCount = Math.max(...counts);
98
+ const minCount = Math.min(...counts);
99
+ if (minCount >= maxCount * 0.8) {
100
+ lines.push(`- Similar counts suggest these may share a common root cause`);
101
+ }
102
+ }
103
+ lines.push('', 'Use `memlab_class_histogram` for the full breakdown, or `memlab_retainer_summary` on a class above to investigate retention patterns.');
104
+ }
105
+ return toolResult(lines.join('\n'));
67
106
  }
68
107
  catch (err) {
69
108
  return errorResult(err);
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot-summary.js","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"snapshot-summary.js","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stale-collections.d.ts","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AA6CvE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsEhE"}
1
+ {"version":3,"file":"stale-collections.d.ts","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AA8CvE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsGhE"}
@@ -8,8 +8,8 @@
8
8
  * @oncall memory_lab
9
9
  */
10
10
  import { z } from 'zod';
11
- import { getSnapshot } from '../heap-state.js';
12
- import { formatBytes, formatNumber, markdownTable, errorResult, textResult, } from '../utils.js';
11
+ import { getSnapshot, getSnapshotEnv } from '../heap-state.js';
12
+ import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
13
13
  const COLLECTION_NAMES = new Set(['Map', 'Set', 'WeakMap', 'WeakSet', 'Array']);
14
14
  function isCollectionNode(node) {
15
15
  return node.type === 'object' && COLLECTION_NAMES.has(node.name);
@@ -41,7 +41,17 @@ export function registerStaleCollections(server) {
41
41
  .optional()
42
42
  .default(15)
43
43
  .describe('Maximum number of results (default 15)'),
44
- }, async ({ limit }) => {
44
+ min_stale_count: z
45
+ .number()
46
+ .optional()
47
+ .default(1)
48
+ .describe('Minimum number of stale entries to include a collection (default 1). Increase to filter out trivially small stale collections.'),
49
+ min_stale_retained_size: z
50
+ .number()
51
+ .optional()
52
+ .default(0)
53
+ .describe('Minimum total stale retained size in bytes to include (default 0). Use e.g., 10240 for 10 KB to filter noise.'),
54
+ }, async ({ limit, min_stale_count, min_stale_retained_size }) => {
45
55
  try {
46
56
  const snapshot = getSnapshot();
47
57
  const results = [];
@@ -59,7 +69,8 @@ export function registerStaleCollections(server) {
59
69
  staleRetainedSize += edge.toNode.retainedSize;
60
70
  }
61
71
  }
62
- if (staleCount > 0) {
72
+ if (staleCount >= min_stale_count &&
73
+ staleRetainedSize >= min_stale_retained_size) {
63
74
  results.push({
64
75
  collection: node,
65
76
  stale_item_count: staleCount,
@@ -72,7 +83,15 @@ export function registerStaleCollections(server) {
72
83
  results.sort((a, b) => b.stale_retained_size - a.stale_retained_size);
73
84
  const topResults = results.slice(0, limit);
74
85
  if (topResults.length === 0) {
75
- return textResult('No stale collections found.');
86
+ const env = getSnapshotEnv();
87
+ if (env === 'node') {
88
+ return toolResult('No stale collections found. This is a Node.js snapshot — detached DOM detection is not applicable.\n\n' +
89
+ 'For Node.js memory investigation, try:\n' +
90
+ '- `memlab_largest_objects` — find objects consuming the most memory\n' +
91
+ '- `memlab_class_histogram` — per-class instance counts and sizes\n' +
92
+ '- `memlab_sliced_strings` — find sliced strings keeping large parents alive');
93
+ }
94
+ return toolResult('No stale collections found.');
76
95
  }
77
96
  const headers = [
78
97
  'Collection ID',
@@ -87,7 +106,12 @@ export function registerStaleCollections(server) {
87
106
  `${formatNumber(r.stale_item_count)} / ${formatNumber(r.total_children)}`,
88
107
  formatBytes(r.stale_retained_size),
89
108
  ]);
90
- return textResult(`Stale collections (${topResults.length} found)\n\n${markdownTable(headers, rows, rightCols)}`);
109
+ const output = `Stale collections (${topResults.length} found)\n\n${markdownTable(headers, rows, rightCols)}`;
110
+ return toolResult(output +
111
+ '\n\n---\n\n' +
112
+ '**Suggested action:** Collections holding detached/stale references prevent garbage collection. ' +
113
+ 'Consider using `WeakRef` or `WeakMap`/`WeakSet`, clearing entries on component unmount, ' +
114
+ 'or adding bounds to collection size.');
91
115
  }
92
116
  catch (err) {
93
117
  return errorResult(err);
@@ -1 +1 @@
1
- {"version":3,"file":"stale-collections.js","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stale-collections.js","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAE,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EAEX,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhF,SAAS,gBAAgB,CAAC,IAAe;IACvC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,WAAW,CAAC,IAAe;IAClC,qBAAqB;IACrB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,6BAA6B;IAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAe;IAC5C,2EAA2E;IAC3E,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,OAAO,CAAC,CAAC;QACzE,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC;QACrC,CAAC;IACH,CAAC;IACD,8CAA8C;IAC9C,OAAO,IAAI,CAAC,UAAU,CAAC;AACzB,CAAC;AASD,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,IAAI,CACT,0BAA0B,EAC1B,8KAA8K,EAC9K;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,wCAAwC,CAAC;QACrD,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,CAAC,CAAC;aACV,QAAQ,CACP,gIAAgI,CACjI;QACH,uBAAuB,EAAE,CAAC;aACvB,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,CAAC,CAAC;aACV,QAAQ,CACP,+GAA+G,CAChH;KACJ,EACD,KAAK,EAAE,EAAC,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAC,EAAE,EAAE;QAC1D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAqB,EAAE,CAAC;YAErC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;gBAC5B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAEpC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBAC7C,IAAI,UAAU,GAAG,CAAC,CAAC;gBACnB,IAAI,iBAAiB,GAAG,CAAC,CAAC;gBAC1B,IAAI,aAAa,GAAG,CAAC,CAAC;gBAEtB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,aAAa,EAAE,CAAC;oBAChB,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC7B,UAAU,EAAE,CAAC;wBACb,iBAAiB,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;oBAChD,CAAC;gBACH,CAAC;gBAED,IACE,UAAU,IAAI,eAAe;oBAC7B,iBAAiB,IAAI,uBAAuB,EAC5C,CAAC;oBACD,OAAO,CAAC,IAAI,CAAC;wBACX,UAAU,EAAE,IAAI;wBAChB,gBAAgB,EAAE,UAAU;wBAC5B,mBAAmB,EAAE,iBAAiB;wBACtC,cAAc,EAAE,aAAa;qBAC9B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,yCAAyC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAC;YACtE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE3C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;gBAC7B,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;oBACnB,OAAO,UAAU,CACf,wGAAwG;wBACtG,0CAA0C;wBAC1C,uEAAuE;wBACvE,oEAAoE;wBACpE,6EAA6E,CAChF,CAAC;gBACJ,CAAC;gBACD,OAAO,UAAU,CAAC,6BAA6B,CAAC,CAAC;YACnD,CAAC;YACD,MAAM,OAAO,GAAG;gBACd,eAAe;gBACf,MAAM;gBACN,eAAe;gBACf,gBAAgB;aACjB,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE;gBACrB,CAAC,CAAC,UAAU,CAAC,IAAI;gBACjB,GAAG,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE;gBACzE,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC;aACnC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,sBAAsB,UAAU,CAAC,MAAM,cAAc,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;YAC9G,OAAO,UAAU,CACf,MAAM;gBACJ,aAAa;gBACb,kGAAkG;gBAClG,0FAA0F;gBAC1F,sCAAsC,CACzC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ export declare function registerStringPatterns(server: McpServer): void;
12
+ //# sourceMappingURL=string-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string-patterns.d.ts","sourceRoot":"","sources":["../../src/tools/string-patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAiBvE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+H9D"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import { z } from 'zod';
11
+ import { getSnapshot } from '../heap-state.js';
12
+ import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
13
+ function extractPrefix(value, prefixLen) {
14
+ if (value.length <= prefixLen)
15
+ return value;
16
+ return value.slice(0, prefixLen);
17
+ }
18
+ export function registerStringPatterns(server) {
19
+ server.tool('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: "Strings matching prefix: 20 instances, 250 MB total." Useful for identifying families of related strings like API responses, repeated log messages, or duplicated data.', {
20
+ prefix_length: z
21
+ .number()
22
+ .optional()
23
+ .default(50)
24
+ .describe('Number of characters to use for prefix grouping (default 50). Shorter values create broader groups.'),
25
+ min_count: z
26
+ .number()
27
+ .optional()
28
+ .default(5)
29
+ .describe('Minimum number of strings in a group to show (default 5)'),
30
+ min_total_size: z
31
+ .number()
32
+ .optional()
33
+ .describe('Minimum total self size in bytes for a group to be shown. Use to filter to significant groups.'),
34
+ limit: z
35
+ .number()
36
+ .optional()
37
+ .default(20)
38
+ .describe('Maximum number of groups to return (default 20)'),
39
+ }, async ({ prefix_length, min_count, min_total_size, limit }) => {
40
+ try {
41
+ const snapshot = getSnapshot();
42
+ const groups = new Map();
43
+ snapshot.nodes.forEach(node => {
44
+ if (node.type !== 'string')
45
+ return;
46
+ if (node.name === 'system / SlicedString')
47
+ return;
48
+ if (node.name === 'system / ConsString')
49
+ return;
50
+ if (node.id <= 3)
51
+ return;
52
+ const prefix = extractPrefix(node.name, prefix_length);
53
+ const existing = groups.get(prefix);
54
+ if (existing) {
55
+ existing.count++;
56
+ existing.total_self_size += node.self_size;
57
+ existing.total_retained_size += node.retainedSize;
58
+ existing.min_len = Math.min(existing.min_len, node.name.length);
59
+ existing.max_len = Math.max(existing.max_len, node.name.length);
60
+ if (existing.example_ids.length < 3) {
61
+ existing.example_ids.push(node.id);
62
+ }
63
+ }
64
+ else {
65
+ groups.set(prefix, {
66
+ count: 1,
67
+ total_self_size: node.self_size,
68
+ total_retained_size: node.retainedSize,
69
+ min_len: node.name.length,
70
+ max_len: node.name.length,
71
+ example_ids: [node.id],
72
+ });
73
+ }
74
+ });
75
+ let filtered = [...groups.entries()].filter(([, g]) => g.count >= min_count);
76
+ if (min_total_size != null) {
77
+ filtered = filtered.filter(([, g]) => g.total_self_size >= min_total_size);
78
+ }
79
+ const sorted = filtered
80
+ .sort((a, b) => b[1].total_self_size - a[1].total_self_size)
81
+ .slice(0, limit);
82
+ if (sorted.length === 0) {
83
+ return toolResult('No string groups found matching the criteria. Try lowering min_count or prefix_length.');
84
+ }
85
+ const headers = [
86
+ 'Prefix',
87
+ 'Count',
88
+ 'Total Size',
89
+ 'Retained',
90
+ 'Len Range',
91
+ 'Examples',
92
+ ];
93
+ const rightCols = new Set([1, 2, 3]);
94
+ const rows = sorted.map(([prefix, g]) => {
95
+ const displayPrefix = prefix.length > 60 ? prefix.slice(0, 60) + '…' : prefix;
96
+ const lenRange = g.min_len === g.max_len
97
+ ? formatNumber(g.min_len)
98
+ : `${formatNumber(g.min_len)}-${formatNumber(g.max_len)}`;
99
+ return [
100
+ displayPrefix,
101
+ formatNumber(g.count),
102
+ formatBytes(g.total_self_size),
103
+ formatBytes(g.total_retained_size),
104
+ lenRange,
105
+ g.example_ids.map(id => `@${id}`).join(', '),
106
+ ];
107
+ });
108
+ return toolResult(`String patterns (prefix_length=${prefix_length}, ${formatNumber(filtered.length)} groups matching filters, showing ${rows.length})\n\n${markdownTable(headers, rows, rightCols)}`);
109
+ }
110
+ catch (err) {
111
+ return errorResult(err);
112
+ }
113
+ });
114
+ }
115
+ //# sourceMappingURL=string-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string-patterns.js","sourceRoot":"","sources":["../../src/tools/string-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ export declare function registerTraceDominators(server: McpServer): void;
12
+ //# sourceMappingURL=trace-dominators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-dominators.d.ts","sourceRoot":"","sources":["../../src/tools/trace-dominators.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAqGvE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8M/D"}