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