Skip to main content
Glama
carloshpdoc

memorydetective

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
analyzeMemgraphA

[mg.memory] Run leaks(1) against a .memgraph file (exported from Xcode Memory Graph Debugger) and return a structured summary: header info, totals, top-level ROOT CYCLE blocks with chain length, plain-English diagnosis. Set fullChains: true to also include the full nested retain forest.

Pipeline: → classifyCycle (named-antipattern + fix hint) → reachableFromCycle (scope blame to a single root). The response includes suggestedNextCalls so the agent can chain without re-reasoning.

findCyclesA

[mg.memory] Extract just the ROOT CYCLE blocks from a .memgraph as flattened chains (depth + edge + retainKind + className + address). Optionally filter to cycles touching a specific class name (substring match). Use this when you want to inspect chains without the noise of standalone leaks.

findRetainersA

[mg.memory] Walk the cycle forest from a .memgraph and return every retain chain that ends in a node whose className contains the given substring. Useful for answering "who is keeping alive?". Returns paths from a top-level node down to the matching node.

countAliveA

[mg.memory] Count how many times each class appears in a .memgraph's leaked nodes. Provide className (substring) for a single number, or omit it to get the top N most-leaked classes. Use this to confirm whether a fix actually reduced instance counts.

diffMemgraphsA

[mg.memory] Compare a baseline .memgraph (before) against a comparison .memgraph (after). Returns total leak/byte deltas, classes whose counts increased or decreased, and ROOT CYCLE signatures bucketed into newInAfter / goneFromBefore / persisted. The killer feature for verifying that a fix actually worked.

classifyCycleA

[mg.memory] Match each ROOT CYCLE against a built-in catalog of 8 known antipatterns (TagIndexProjection cycle, ForEachState retention, Combine sink-store-self, Task-without-weak-self, NotificationCenter observer, viewmodel-wrapped-strong closure, UINavigationController host, _DictionaryStorage internal). Returns patternId, confidence, and a fixHint per cycle.

Pipeline: this is the killer tool — after the result, follow suggestedNextCalls which pre-translates each match to a Swift regex (swiftSearchPattern) + the captured class name (swiftGetSymbolDefinition). Discovery is data, not inference.

analyzeHangsA

[mg.trace] Run xcrun xctrace export against a .trace bundle for the potential-hangs schema and return aggregated stats (Hang vs Microhang counts, longest, average, total duration) plus the top N longest hangs sorted by duration. Use minDurationMs: 250 to filter to user-visible hangs only.

analyzeTimeProfileA

[mg.trace] Export the time-profile schema from a .trace bundle and return top symbols by sample count. Note: heavy/unsymbolicated traces may crash xctrace export — when that happens, the tool returns a notice field with workarounds (open in Instruments first to symbolicate, or re-record shorter).

listTraceDevicesA

[mg.discover] Run xcrun xctrace list devices and return parsed devices/simulators with their UDIDs. The LLM should call this before recordTimeProfile to discover the right UDID without asking the user. Set includeOffline: true to include disconnected devices.

listTraceTemplatesA

[mg.discover] Run xcrun xctrace list templates and return parsed standard + custom templates. Useful when picking a template name for recordTimeProfile (e.g. "Time Profiler", "Animation Hitches", "Allocations").

recordTimeProfileA

[mg.trace] Wrapper around xcrun xctrace record. Capture a .trace bundle from a running app on a device or simulator. Required: exactly 1 of deviceId/simulatorId, exactly 1 of attachAppName/attachPid/launchBundleId, an output path ending in .trace. Defaults: template = "Time Profiler", durationSec = 90.

captureMemgraphA

[mg.memory] Wrapper around leaks --outputGraph. Resolves appName to a PID via pgrep -x (or accepts pid directly), then writes a .memgraph snapshot. Limitation: only works for processes running on the local Mac (Mac apps + iOS simulator). Does NOT work for physical iOS devices — use Xcode's Memory Graph button there.

analyzeAnimationHitchesA

[mg.trace] Parse the animation-hitches schema from a .trace recorded with the Animation Hitches Instruments template. Returns hitch totals, by-type counts, longest hitches, and how many crossed the user-perceptible 100ms threshold.

analyzeAllocationsA

[mg.trace] Parse the allocations schema from a .trace recorded with the Allocations Instruments template. Returns per-category aggregates (cumulative bytes, allocation count, lifecycle = transient/persistent/mixed), top allocators by size and by count, and a one-liner diagnosis identifying the dominant allocator.

analyzeAppLaunchA

[mg.trace] Parse the app-launch schema from a .trace recorded with the App Launch Instruments template. Returns total launch time, launch type (cold/warm), per-phase breakdown (process-creation, dyld-init, ObjC-init, AppDelegate, first-frame), and the slowest phase.

renderCycleGraphA

[mg.render] Read a .memgraph, pick a ROOT CYCLE by index, and emit the chain as a Mermaid graph definition (default — embeddable in markdown / GitHub) or a Graphviz DOT file. App-level classes are highlighted; CYCLE BACK terminators are styled distinctly. Use cycleIndex to render cycles other than the first.

logShowA

[mg.log] Wrap log show --style compact --last <window> with optional NSPredicate filter, process and subsystem sugar. Returns parsed entries (timestamp, type, process, pid, subsystem, category, message) bounded by maxEntries. Use this to look back at app logs without leaving chat.

logStreamB

[mg.log] Wrap log stream --style compact for a bounded duration (≤60 s — MCP requests should not block longer). Returns parsed entries collected during the window. Useful for capturing a specific user flow without setting up a full Console.app session.

detectLeaksInXCUITestA

[mg.ci] Build the workspace for testing, launch the test cycle, capture a baseline .memgraph once the app appears, run the test to completion, capture an after .memgraph, and diff. Returns passed: false when new ROOT CYCLE blocks appear that aren't in the allowlistPatterns list. Designed for CI gating — non-zero exit code on failure.

reachableFromCycleA

[mg.memory] Cycle-scoped reachability + class counting. Answers questions like "how many NSURLSessionConfiguration instances are reachable from the cycle rooted at DetailViewModel?" — distinguishing the actual culprit (the cycle root) from its retained dependencies. Pick a cycle by zero-based cycleIndex or by rootClassName substring. Returns per-class counts ranked by occurrence, plus the total reachable node count.

swiftGetSymbolDefinitionA

[mg.code] Find the file:line where a Swift symbol (class, struct, enum, protocol, func, var, etc.) is declared. Pre-scans candidatePaths (or hint.filePath) with a fast regex first, then asks SourceKit-LSP for jump-to-definition. Returns the position even when LSP can't follow through. Use after findRetainers / classifyCycle surface a class name from a memgraph cycle to land in the actual source file.

swiftFindSymbolReferencesA

[mg.code] Locates the symbol's declaration in filePath, then asks SourceKit-LSP for textDocument/references. Returns every callsite + capture across the project, with a snippet of each line. Requires an IndexStoreDB at <projectRoot>/.build/index/store for cross-file references — build it with swift build -Xswiftc -index-store-path -Xswiftc <projectRoot>/.build/index/store. The result includes a needsIndex: true hint when the index is missing.

swiftGetSymbolsOverviewA

[mg.code] Cheap orientation: returns the top-level symbols (classes, structs, enums, protocols, free functions) declared in a Swift file via SourceKit-LSP's documentSymbol. Set topLevelOnly: false for nested children too. Useful right after swiftGetSymbolDefinition lands you in a new file.

swiftGetHoverInfoA

[mg.code] SourceKit-LSP textDocument/hover at a (line, character) position. Returns the markdown / plaintext hover content plus a best-effort extracted declaration fragment. Use to disambiguate self captures: a class self in a closure can leak; a struct self can't.

swiftSearchPatternA

[mg.code] Pure regex search over a file's contents — no SourceKit-LSP, no IndexStoreDB. Catches what LSP misses: closure capture lists ([weak self], [unowned self]), Task { ... self ... } blocks, and any other pattern the agent constructs from a leak chain. Returns matches with line/character positions and a trimmed snippet.

getInvestigationPlaybookA

[meta] Returns a versioned, declarative pipeline for a known investigation flow (memgraph-leak, perf-hangs, ui-jank, app-launch-slow, verify-fix). Each step has a tool name, purpose, and argsTemplate. Use this once at the start of an investigation so any LLM agent can follow the right sequence without rediscovering it from individual tool descriptions.

verifyFixA

[mg.memory] Cycle-semantic diff. Classifies both before and after .memgraph snapshots and emits a per-pattern PASS/PARTIAL/FAIL verdict plus bytes freed and instances released. Use as a CI gate: if expectedPatternId is provided, expectedPatternVerdict tells you in one field whether the fix landed.

Pipeline: this is the natural followup to classifyCycle after you've shipped a fix. Capture a fresh .memgraph, point this at the before/after pair.

compareTracesByPatternA

[mg.trace][mg.ci] Trace-side counterpart to verifyFix. Compares two .trace bundles for a specific perf category (hangs, animation-hitches, or app-launch) and emits a PASS/PARTIAL/FAIL verdict plus before/after stats and deltas. Apply thresholds: hangs PASS when longest is below hangsMaxLongestMs (default 0); hitches PASS when longest is below hitchesMaxLongestMs (default 100ms — Apple's user-perceptible threshold); app-launch PASS when total is below appLaunchMaxTotalMs (default 1000ms).

Pipeline: capture before/after .trace (via recordTimeProfile or Xcode), then point this at the pair. The natural followup to a hangs/jank/launch fix PR.

Prompts

Interactive templates invoked by user choice

NameDescription
investigate-leakRun the canonical 6-step memgraph-leak investigation: analyzeMemgraph → classifyCycle → reachableFromCycle → swiftSearchPattern → swiftGetSymbolDefinition → swiftFindSymbolReferences.
investigate-hangsDiagnose main-thread hangs from a `.trace` recorded with the Time Profiler or Hangs template.
investigate-jankDiagnose dropped frames from a `.trace` recorded with the Animation Hitches template.
investigate-launchDiagnose cold/warm launch slowness from a `.trace` recorded with the App Launch template.
verify-cycle-fixDiff a before/after pair of `.memgraph` snapshots to confirm a fix actually closed the originally-classified cycle.

Resources

Contextual data attached and managed by the client

NameDescription
SwiftUI .tag(...) closure-over-self cycleSwiftUI .tag(...) closure-over-self cycle
SwiftUI _DictionaryStorage<…WeakBox<AnyLocationBase>> internal cycleSwiftUI _DictionaryStorage<…WeakBox<AnyLocationBase>> internal cycle
SwiftUI ForEachState retained by tap-gesture closureSwiftUI ForEachState retained by tap-gesture closure
Closure capturing `_viewModel.wrappedValue` stronglyClosure capturing `_viewModel.wrappedValue` strongly
UIViewControllerRepresentable + UINavigationController host cycleUIViewControllerRepresentable + UINavigationController host cycle
Combine .sink/.assign closure capturing self via AnyCancellableCombine .sink/.assign closure capturing self via AnyCancellable
Swift `Task { }` body strongly capturing selfSwift `Task { }` body strongly capturing self
NotificationCenter observer block capturing selfNotificationCenter observer block capturing self
Combine `.assign(to: \.x, on: self)` capturing selfCombine `.assign(to: \.x, on: self)` capturing self
Swift `Task { }` inside a SwiftUI View capturing selfSwift `Task { }` inside a SwiftUI View capturing self
NotificationCenter observer never deregisteredNotificationCenter observer never deregistered
`delegate` property declared without `weak``delegate` property declared without `weak`
Timer.scheduledTimer(target:selector:) retains its targetTimer.scheduledTimer(target:selector:) retains its target
CADisplayLink retains its targetCADisplayLink retains its target
UIGestureRecognizer / UIControl `addTarget` retains targetUIGestureRecognizer / UIControl `addTarget` retains target
`NSKeyValueObservation` token retains its change handler`NSKeyValueObservation` token retains its change handler
URLSession retains its delegate stronglyURLSession retains its delegate strongly
SwiftUI `@EnvironmentObject` with back-reference to UIView/UIViewControllerSwiftUI `@EnvironmentObject` with back-reference to UIView/UIViewController
`AsyncStream` continuation retains self via producer / onTermination`AsyncStream` continuation retains self via producer / onTermination
`WKUserContentController.add(_:name:)` retains the handler`WKUserContentController.add(_:name:)` retains the handler
DispatchSource event handler closure retains selfDispatchSource event handler closure retains self
RxSwift `DisposeBag` retains subscription closures capturing selfRxSwift `DisposeBag` retains subscription closures capturing self
Realm `NotificationToken` retains its change closureRealm `NotificationToken` retains its change closure
Coordinator pattern: child holds parent stronglyCoordinator pattern: child holds parent strongly
CAAnimation retains its delegate (Apple's documented quirk)CAAnimation retains its delegate (Apple's documented quirk)
Custom CALayer delegate pointing at non-UIView ownerCustom CALayer delegate pointing at non-UIView owner
NSFetchedResultsController retains its delegateNSFetchedResultsController retains its delegate
@Observable class held as @State across modal presentation@Observable class held as @State across modal presentation
NavigationPath retains every element ever pushed into itNavigationPath retains every element ever pushed into it
`for await` over an infinite AsyncSequence pins self via the consuming Task`for await` over an infinite AsyncSequence pins self via the consuming Task
`for await ... in NotificationCenter.notifications(named:)` retains self forever`for await ... in NotificationCenter.notifications(named:)` retains self forever
Swift 6.2 `Observations { }` closure retains selfSwift 6.2 `Observations { }` closure retains self
WKScriptMessageHandler bridge: handler ↔ webview ↔ contentController cycleWKScriptMessageHandler bridge: handler ↔ webview ↔ contentController cycle
SwiftData ModelContext retained by actor through DefaultSerialModelExecutorSwiftData ModelContext retained by actor through DefaultSerialModelExecutor

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/carloshpdoc/memorydetective'

If you have feedback or need assistance with the MCP directory API, please join our Discord server