Docs › Mastra
Integration Guide
Instrumenting Mastra Agents with Nexus
Mastra is a TypeScript-first AI agent framework with built-in memory, tools, and workflows. This guide shows you how to wrap your Mastra agents with Nexus traces so every run is visible in your dashboard — with full span waterfall, error alerts, and latency tracking.
What is Mastra?
Mastra is an open-source TypeScript AI agent framework built by the team behind Gatsby. It provides a structured way to define agents with tools, memory, and multi-step workflows — all in TypeScript with full type safety. Agents are defined as objects with a model, a set of tools, and optional instructions.
Nexus adds the production observability layer that Mastra doesn’t include out of the box: persistent trace storage, span waterfall visualization, error alerts, and dashboard metrics across all your deployed agents.
Why use Nexus with Mastra?
- ✓ Tool call tracing — each tool execute() becomes a span with input, output, and duration
- ✓ Agent run visibility — every agent.generate() call is wrapped in a trace you can inspect later
- ✓ Error alerts — get an email the moment a Mastra agent run fails in production
- ✓ Multi-agent tracking — register each Mastra agent with a separate agentId to track health independently
- ✓ Zero lock-in — Nexus SDK is framework-agnostic; instrument any TypeScript code
Step 1 — Install both SDKs
npm install @keylightdigital/nexus @mastra/core
Step 2 — Create an API key
Go to /dashboard/keys and create a new API key. Add it to your environment:
NEXUS_API_KEY=nxs_your_key_here
Step 3 — Wrap your agent run in a trace
The simplest integration wraps each agent.generate() call
in a Nexus trace. This gives you timing, status, and the agent’s input/output in one span.
import { Agent } from '@mastra/core/agent';
import { openai } from '@mastra/openai';
import { NexusClient } from '@keylightdigital/nexus';
const nexus = new NexusClient({
apiKey: process.env.NEXUS_API_KEY!,
agentId: 'research-assistant',
});
const agent = new Agent({
name: 'Research Assistant',
instructions: 'You are a helpful research assistant.',
model: openai('gpt-4o'),
});
async function runAgent(userMessage: string) {
const trace = await nexus.startTrace({
name: `Research: ${userMessage.slice(0, 60)}`,
metadata: { model: 'gpt-4o', user_message: userMessage },
});
try {
const result = await agent.generate(userMessage);
await trace.addSpan({
name: 'agent.generate',
status: 'ok',
input: { message: userMessage },
output: { text: result.text },
});
await trace.end({ status: 'success' });
return result.text;
} catch (err) {
await trace.end({ status: 'error', error: String(err) });
throw err;
}
}
Step 4 — Add spans for tool calls
For richer traces, instrument each Mastra tool’s execute()
function. Pass the trace reference through context so spans are nested under the right trace.
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
import { NexusClient } from '@keylightdigital/nexus';
// Pass trace in context so tools can add spans
export function createInstrumentedTools(nexus: NexusClient, traceId: string) {
const webSearch = createTool({
id: 'web_search',
description: 'Search the web for current information',
inputSchema: z.object({ query: z.string() }),
outputSchema: z.object({ results: z.array(z.string()) }),
execute: async ({ context }) => {
const started = new Date().toISOString();
// ... your actual search logic ...
const results = await performSearch(context.query);
await nexus.addSpanToTrace(traceId, {
name: 'tool:web_search',
status: 'ok',
started_at: started,
ended_at: new Date().toISOString(),
input: { query: context.query },
output: { result_count: results.length },
});
return { results };
},
});
return { webSearch };
}
Python alternative
Mastra is TypeScript-only, but if you’re calling a Mastra agent from a Python orchestrator via HTTP, you can still instrument the calling side with the Nexus Python SDK:
from nexus_agent import NexusClient
import httpx
nexus = NexusClient(api_key="nxs_your_key_here", agent_id="mastra-caller")
async def call_mastra_agent(message: str):
trace = nexus.start_trace(name=f"Mastra call: {message[:60]}")
try:
async with httpx.AsyncClient() as client:
resp = await client.post(
"http://localhost:4111/api/agents/research-assistant/generate",
json={"messages": [{"role": "user", "content": message}]},
)
resp.raise_for_status()
result = resp.json()
trace.add_span(name="mastra.generate", status="ok",
output={"text": result.get("text", "")})
trace.end(status="success")
return result
except Exception as e:
trace.end(status="error", error=str(e))
raise
See your Mastra agents in the dashboard
Sign up free — no credit card required. 1,000 traces/month on the free plan. Every Mastra agent run shows up in the waterfall view within seconds.