> ## Documentation Index
> Fetch the complete documentation index at: https://fentaris.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Intercept tool calls with fine-grained filters.

Unified events provide targeted observation without wrapping every request. They are best for focused events like auditing a single server, capturing diagnostics for specific tools, and observing session lifecycle.

If you need to enforce policy for *all* tool calls, use [Middleware](/guides/middleware).

## When to use hooks

* You only care about a single server or a small subset of tools.
* You want audit logs without changing the control flow.
* You want lightweight metrics without blocking requests.

## Tool success event

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.on("tool:success", async ({ ctx, result, durationMs }) => {
  ctx.log.info("tool.success", { durationMs, isError: result?.isError });
});
```

## Filtered event

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.on("tool:success", { server: "diagnostics" }, async ({ ctx }) => {
  ctx.log.info("diagnostics");
});
```

## Server-scoped event

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const github = proxy.mcp("github");

github.on("tool:error", async ({ ctx, error }) => {
  ctx.log.warn("github.tool.error", { message: error?.message });
});
```

## Available filters

* `server`: match the upstream server name.
* `tool`: match the original tool name.
* `proxyTool`: match the prefixed tool name.

Hooks run before middleware and can return a tool result to short-circuit the call.

Legacy `proxy.on("call", ...)` hooks are still supported for compatibility. Use middleware or tool routes for runtime control, and use `tool:start`, `tool:success`, `tool:error`, `tool:after`, `tools:list:after`, `session:start`, and `session:end` for observation.

## Use hooks for audits

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.on("tool:after", { proxyTool: "filesystem__delete" }, async ({ ctx, success }) => {
  ctx.log.warn("audit.delete", {
    userId: ctx.user.id,
    tool: ctx.tool?.proxyName,
    success,
  });
});
```

## Use hooks for metrics

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.on("tool:success", async ({ ctx, durationMs }) => {
  ctx.log.info("metric.tool", {
    tool: ctx.tool?.proxyName,
    server: ctx.server?.name,
    durationMs,
  });
});
```

## Combine hooks with middleware

Hooks can collect data while middleware enforces policy. This lets you capture metrics without blocking the request.

```ts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
proxy.on("tool:success", async ({ ctx }) => {
  ctx.log.info("hook.metric", { tool: ctx.tool?.proxyName });
});

proxy.tool("filesystem.delete", async (ctx) => {
  if (ctx.user.role !== "admin") {
    return ctx.deny("Delete is disabled.");
  }
});
```

## Debugging hooks

If a hook is not firing, verify the filter values and check the `proxyToolName` from logs. Most issues are due to mismatched prefixes.

## Best practices

* Use hooks for observation, middleware for control.
* Keep hook handlers fast and non-blocking.
* Prefer `proxyTool` filtering for clarity.
* Avoid mutations in hooks; keep them side-effect free when possible.

## Reference links

* MCP SDK: [https://github.com/modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk)
