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
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