Gate your Mastra agent's MCP tool calls
Your Mastra agent asks mcpindex whether an MCP tool is vetted before it invokes it, warning you (or blocking the call) on your terms, fail-closed.
By default a Mastra agent calls whatever tools an MCP server hands it, trusting each tool's own description. The @mcp-index/mastra package adds a second opinion at the moment of the call: a beforeToolCall hook that checks mcpindex's advisory screen first. It is a client of the advisory screen (has this tool been vetted?), not the in-path drift gate (did this contract change since I pinned it?).
- 01
Install the package#
Zero runtime dependencies; @mastra/core is an optional peer you already have.
npm i @mcp-index/mastra - 02
Add the hook to your agent#
Pass the mcpindex server id whose tools your agent calls. That is the whole integration.
import { Agent } from "@mastra/core/agent"; import { mcpindexGate } from "@mcp-index/mastra"; const agent = new Agent({ id: "gated-agent", name: "gated-agent", instructions: "You are a helpful assistant.", model: "openai/gpt-4o-mini", hooks: { beforeToolCall: mcpindexGate({ serverId: "your-mcp-server-id" }), }, });In the default
warnmode you now get a log line before every tool call with the tool's trust directive, and nothing about your agent's behavior changes. - 03
Choose warn or enforce#
Two policies, and the default is deliberately the non-breaking one.
mcpindexGate({ serverId: "your-mcp-server-id", policy: "warn" }) // default mcpindexGate({ serverId: "your-mcp-server-id", policy: "enforce" }) // fail-closed- warn never blocks a call. It logs and annotates. Pure visibility.
- enforce is fail-closed: only an explicit ALLOW directive proceeds; DENY, REVIEW, and UNVERIFIED are blocked, and the model receives a short 'not cleared' message in place of the tool's output.
- 04
Read the honest limit (important)#
The mcpindex public advisory API is at verdict contract 1.1.0, and it does not yet emit ALLOW or DENY - every verdict today is REVIEW or UNVERIFIED. So today this is a visibility and early-warning tool, and
warnis the sane default.enforceblocks every tool call right now, because nothing is ALLOW yet; that is correct fail-closed behavior, and it becomes a real allow-list the moment mcpindex ships ALLOW/DENY verdicts, with no code change on your side. If mcpindex is slow or unreachable, the check fails closed to UNVERIFIED rather than silently trusting.Two more tokens worth knowing when you read
honest_limits. Verdicts today are description-level, so the server's screen comes back for whatever tool name you pass, and every per-tool response says so withtool_name_not_independently_verified. And each verdict is bound to the exact registry description it judged: if that text has since been replaced, the response carriescontent_drift, and a clean verdict renders STALE until re-screened rather than posing as a live assessment of text the registry no longer publishes.One thing changed in contract 1.1.0, and it affects you if you gate on
expires_at. What the field means is unchanged: do not act on a verdict once it has passed. What changed is how the date is set. It used to be stamped once at screen time and left to run down, so a verdict aged out even when the server it describes had not changed at all. It is now rolled forward on read whenever the description the registry publishes today still matches the exact text the screen judged. The practical effect is that yourexpires_atgate fires far less often than it used to. When a window was extended by re-confirming rather than by a fresh screen,freshness_confirmedappears inhonest_limitsso you can tell the two cases apart in code. Confirmation only ever moves the date: it never appears on a server whose description has changed, and it cannot turn a flagged verdict clean. - 05
Direct lookups (optional)#
Need the verdict without the hook? The client is exported.
import { TrustClient } from "@mcp-index/mastra"; const client = new TrustClient(); const v = await client.checkTool("your-server-id", "send_email"); console.log(v.directive, v.honest_limits);Full SDK and API reference — the 'Ways to use the directory' HTTP endpoints and the SDK section.
- Does @mcp-index/mastra block untrusted MCP tools?
- In enforce mode it blocks any tool whose directive is not an explicit ALLOW. But note the mcpindex v1 public API only emits REVIEW or UNVERIFIED today (ALLOW/DENY are reserved), so today enforce blocks everything and warn (the default) is the useful mode: it flags unvetted tools without changing behavior. It becomes a real allow-list when ALLOW/DENY ship, with no code change.
- What happens if mcpindex is unreachable?
- It fails closed. A timeout, network error, non-2xx, or unparseable response resolves to an UNVERIFIED verdict, never a silent ALLOW. Under warn it proceeds and logs; under enforce it blocks.