Mastra (TypeScript) integration
Prismor adapter for Mastra. This is a genuinely separate npm package —
prismor-mastra — since a Python wheel can't bundle TypeScript. Source
lives at adapters/mastra/.
Registry entry: id: mastra in
prismor/runtime/integrations/registry.yaml.
Every tool call is routed through the Prismor eval-server (a local HTTP sidecar wrapping the same policy engine the Python adapters call in-process) before the tool body runs.
Why this hook point (and a correction from the original plan)
The original plan pointed at processOutputStep — Mastra's own type docs
describe it as running "after each LLM response, before tool execution,"
with an injected abort() to deny. This turned out not to be reliable
when tested against a real agent run (@mastra/core v0.x, 2026-07):
calling abort() from processOutputStep throws a workflow-level error,
but the tool's execute function runs anyway — confirmed with timestamped
logging showing execute firing after abort() was called.
Instead, prismorTool/prismorTools wrap a tool's execute function
directly — the same pattern the CrewAI/LangChain adapters use — which
is reliable: the wrapped function is what Mastra actually calls, so a
thrown error genuinely prevents the tool body from running.
Install
npm install prismor-mastra
Start the eval-server once, alongside your app:
prismor eval-server --port 7071
Connect to the console
To see this agent's tool calls in the Prismor console and control it from there:
- In the console, open Agents. Under SDK & deployed agents, enter a workload name and click Mint agent key. The key is shown once, so put it in your deployment's secret manager.
- Set it as
PRISMOR_AGENT_KEYin the environment of theprismor eval-serverprocess. The TypeScript adapter never sees the key; the eval-server evaluates, reports and pulls policy. - Run the agent. Its first guarded tool call pulls your org's signed policy and starts reporting, and the agent appears in the console under that workload name. Changes you make in the console (mode, blocked tools) reach it on its next tool call, at most about 30 seconds later.
Without a key the eval-server still enforces your local policy but reports nothing. To check the connection, run prismor doctor on the eval-server host with the same PRISMOR_AGENT_KEY set.
Use
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { prismorTool } from "prismor-mastra";
const guardedRunShell = prismorTool("run_shell", runShell, {
mode: "enforce",
subject: "user:alice",
});
const agent = new Agent({
name: "ops",
model: openai("gpt-4o-mini"),
tools: { run_shell: guardedRunShell },
});
A denied call throws PrismorBlocked; Mastra's tool-execution step
catches the thrown error and feeds it back to the model as the tool's
result, so the conversation continues with the denial visible. mode: "observe" is log-only. failMode controls what happens if the
eval-server is unreachable ("closed" in enforce mode by default — a
policy suspension must hold even when the sidecar is down).
Per-user control
subject follows the same convention as the Vercel AI SDK adapter's
useSubject() / the Python adapters' use_subject() — pass it per-call
or set it on prismorTool/prismorTools — and is forwarded to the
eval-server, resolved to per-user IAM profiles, and recorded in telemetry.
Verified
Live-tested against a real Mastra Agent running gpt-4o-mini (via
@ai-sdk/openai) with a genuine OpenAI API key and a local prismor eval-server: a destructive shell command was denied before the tool's
JavaScript implementation ever ran; a benign command executed normally.
See also
- Framework adapters overview
- Vercel AI SDK integration — the reference HTTP adapter pattern this one follows
- IAM — per-user permission profiles