Hook a function and log every call (turnkey instrumentation, MUTATES STATE)
hook-and-log-functionHook a target function to log every call's arguments, returns, and timestamp. Fetch the captured log and restore the original to stop tracing.
Instructions
DANGER — INSTALLS A PERSISTENT GLOBAL HOOK. Turnkey call-tracing for any function: hook a target, automatically record every invocation (stringified arguments + return values + a timestamp), then fetch the captured call log and restore the original — all from three actions of this one tool. This is the fastest way to answer 'what is this function actually called with, how often, and what does it return?' without hand-writing a hook. WORKFLOW (stateful — survives across tool calls via getgenv().__mcp_fnlogs, keyed by functionPath): 1. action='start' with functionPath — resolves the target, captures the original, installs a logging hook that transparently calls the original and records up to maxCalls invocations. Returns { started, key }. 2. action='fetch' with the same functionPath — reads the accumulated call log so far WITHOUT stopping it. Returns { count, max, calls } where each call is { args[], returns[], t }. Call repeatedly to watch live. 3. action='stop' with the same functionPath — restores the original function and removes the registry entry. Returns { stopped }. ALWAYS stop when done. CAVEATS: The hook is GLOBAL and PERSISTS until you stop it (or the client restarts). It adds overhead on every call to the target and CAN TRIP ANTICHEAT or destabilize the game, especially on hot paths — prefer specific, low-frequency targets and keep maxCalls modest. Arguments/returns are captured by tostring (Instances become GetFullName()) and both arrays are capped at 8 entries each. Logging stops accumulating once maxCalls is reached, but the hook stays installed (and keeps calling the original) until you stop it. Requires hookfunction, newcclosure, and getgenv; restoration uses hookfunction(target, original) with a restorefunction fallback. Returns { error } with a clear message if a capability is missing, the target cannot be resolved, or there is no active log for fetch/stop. Signature: { action: "start" | "fetch" | "stop", functionPath: string?, maxCalls: any?, threadContext: number? }. Phase: act; cost=medium; idempotency=contextual-write. Requires: active-client, resolved-target, explicit-mutation-approval. Produces: structured-result. Verify with: is-function-hooked. Safety: MUTATING; changes persistent executor-side observer or hook state. On failure: inspect tool-schema for exact fields, defaults, constraints, and an invocation example.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | What to do: 'start' installs the logging hook on functionPath; 'fetch' returns the call log captured so far (hook stays live); 'stop' restores the original function and clears the log. Use the SAME functionPath for all three so they address the same registry entry. | |
| maxCalls | No | Maximum number of calls to record before logging stops accumulating (default 100). On 'start' this sizes the ring of captured calls; on 'fetch' it caps how many entries are returned in this response. Keep modest on hot paths to limit overhead and output size. | |
| functionPath | No | Luau expression resolving to the function to instrument, e.g. 'getsenv(game.Players.LocalPlayer.PlayerScripts.Main).validate', 'getrawmetatable(game).__namecall', or 'getconnections(game.Workspace.Part.Touched)[1].Function'. Evaluated as `return <functionPath>` and must resolve to a function. REQUIRED for 'start'. For 'fetch'/'stop' it is the registry key identifying which running log to act on, so it must match the string used at start (defaults to the start expression). | |
| threadContext | No | Optional Roblox thread identity for this call; omit it to use the server default. |