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?

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.