Count how many times a function is called (MUTATES STATE via hookfunction)
count-function-callsHook any game function to count its calls, read the live count, then restore the original. Confirms anticheat ticks, hot paths, or remote handlers actually run.
Instructions
WRITES LIVE GAME STATE — INSTALLS A PERSISTENT GLOBAL HOOK. Lightweight call-frequency counter for any function: hook a target so that every invocation bumps an integer counter, then read the counter, then restore the original. Unlike hook-and-log-function (which records full args/returns), this captures ONLY a count, so it is the cheapest way to answer 'is this function actually being called, and how often?' — ideal for confirming an anticheat tick fires, measuring how hot a code path is, or verifying a remote handler runs. WORKFLOW (stateful — survives across tool calls via getgenv().__mcp_callCounts, keyed by functionPath): 1. action='start' with functionPath — resolves the target, captures the original, installs a counting hook that transparently calls the original and increments a counter. Returns { started, key }. 2. action='fetch' with the same functionPath — returns { calls } captured so far WITHOUT stopping. Poll to watch live. 3. action='stop' with the same functionPath — restores the original and clears the entry. Returns { stopped, calls }. CAVEATS: the hook is GLOBAL and PERSISTS until you stop it (or the client restarts), adds (small) overhead on every call, and a live function hook CAN TRIP ANTICHEAT — always stop when done. The counting work is pcall-isolated and the hook always calls through to the original, so behavior is unchanged. Requires hookfunction, newcclosure, and getgenv; restoration uses hookfunction(target, original) with a restorefunction fallback. Returns { error } if a capability is missing, the target cannot be resolved, or there is no active counter for fetch/stop. Signature: { action: "start" | "fetch" | "stop", functionPath: string?, threadContext: number? }. Phase: act; cost=medium; idempotency=contextual-write. Requires: active-client, resolved-target, explicit-mutation-approval. Produces: operation-receipt. Verify with: assert-state. Safety: MUTATING; writes live game/client state. On failure: inspect tool-schema for exact fields, defaults, constraints, and an invocation example.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | 'start' installs the counting hook on functionPath; 'fetch' returns the call count so far (hook stays live); 'stop' restores the original function and clears the counter. Use the SAME functionPath for all three so they address the same registry entry. | |
| functionPath | No | Luau expression resolving to the function to count, e.g. 'getsenv(game.Players.LocalPlayer.PlayerScripts.Main).heartbeat', '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 counter to act on, so it must match the string used at start. | |
| threadContext | No | Optional Roblox thread identity for this call; omit it to use the server default. |