December 3, 2025
Add framework-agnostic stream handlers for use outside of Hono/Mastra server (#10628)
handleChatStream: Standalone handler for streaming agent chat in AI SDK formathandleWorkflowStream: Standalone handler for streaming workflow execution in AI SDK formathandleNetworkStream: Standalone handler for streaming agent network execution in AI SDK format
These functions accept all arguments explicitly and return a ReadableStream, making them usable in any framework (Next.js App Router, Express, etc.) without depending on Hono context.Example usage:
import { handleChatStream } from '@mastra/ai-sdk';
import { createUIMessageStreamResponse } from 'ai';
export async function POST(req: Request) {
const params = await req.json();
const stream = await handleChatStream({
mastra,
agentId: 'weatherAgent',
params,
});
return createUIMessageStreamResponse({ stream });
}
New exports:
Support streaming agent text chunks from workflow-step-output (#10540)
Adds support for streaming text and tool call chunks from agents running inside workflows via the workflow-step-output event. When you pipe an agent's stream into a workflow step's writer, the text chunks, tool calls, and other streaming events are automatically included in the workflow stream and converted to UI messages.
Features:
includeTextStreamParts option to WorkflowStreamToAISDKTransformer (defaults to true)isMastraTextStreamChunk type guard to identify Mastra chunks with text streaming datatext-start, text-delta, text-endtool-call, tool-resulttransformers.test.tsworkflowRoute()Example:
const planActivities = createStep({
execute: async ({ mastra, writer }) => {
const agent = mastra?.getAgent('weatherAgent');
const response = await agent.stream('Plan activities');
await response.fullStream.pipeTo(writer);
return { activities: await response.text };
},
});
When served via workflowRoute(), the UI receives incremental text updates as the agent generates its response, providing a smooth streaming experience.
Added support for resuming agent streams in the chat route. You can now pass resumeData in the request body to continue a previous agent stream, enabling long-running conversations and multi-step agent workflows. (#10448)
Add Better Auth authentication provider (#10658)
Adds a new authentication provider for Better Auth, a self-hosted, open-source authentication framework.
import { betterAuth } from 'better-auth';
import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';
import { Mastra } from '@mastra/core';
// Create your Better Auth instance
const auth = betterAuth({
database: {
provider: 'postgresql',
url: process.env.DATABASE_URL!,
},
emailAndPassword: {
enabled: true,
},
});
// Create the Mastra auth provider
const mastraAuth = new MastraAuthBetterAuth({
auth,
});
// Use with Mastra
const mastra = new Mastra({
server: {
auth: mastraAuth,
},
});
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Add support for custom fetch function in MastraClient to enable environments like Tauri that require custom fetch implementations to avoid timeout errors. (#10677)
You can now pass a custom fetch function when creating a MastraClient:
import { MastraClient } from '@mastra/client-js';
// Before: Only global fetch was available
const client = new MastraClient({
baseUrl: 'http://your-api-url',
});
// After: Custom fetch can be passed
const client = new MastraClient({
baseUrl: 'http://your-api-url',
fetch: customFetch, // Your custom fetch implementation
});
If no custom fetch is provided, it falls back to the global fetch function, maintaining backward compatibility.
Fixes #10673
The client-js package had its own simpler zodToJsonSchema implementation that was missing critical features from schema-compat. This could cause issues when users pass Zod schemas with z.record() or z.date() through the MastraClient. (#10730)
Now the client uses the same implementation as the rest of the codebase, which includes the Zod v4 z.record() bug fix, date-time format conversion for z.date(), and proper handling of unrepresentable types.
Also removes the now-unused zod-to-json-schema dependency from client-js.
Fix wrong arguments type in list workflow runs (#10755)
Adjust the generate / stream types to accept tracingOptions (#10742)
fix(a2a): fix streaming and memory support for A2A protocol (#10653)
Client (@mastra/client-js):
sendStreamingMessage to properly return a streaming response instead of attempting to parse it as JSONServer (@mastra/server):
contextId as threadId for memory persistence across conversationsresourceId via params.metadata.resourceId or message.metadata.resourceId, falling back to agentIdfeat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)Convex storage and vector adapter improvements: (#10421)
id field for Mastra record ID and by_record_id index for efficient lookupssaveMessages and updateMessages to automatically update thread updatedAt timestampslistMessages to properly fetch messages from different threads when using includesaveResource to preserve undefined metadata instead of converting to empty objectConvexAdminClient to use Convex HTTP API directly with proper admin authentication@mastra/convex/server for easy schema setupChanged .branch() result schema to make all branch output fields optional. (#10693)
Breaking change: Branch outputs are now optional since only one branch executes at runtime. Update your workflow schemas to handle optional branch results.
Before:
const workflow = createWorkflow({...})
.branch([
[condition1, stepA], // outputSchema: { result: z.string() }
[condition2, stepB], // outputSchema: { data: z.number() }
])
.map({
finalResult: { step: stepA, path: 'result' } // Expected non-optional
});
After:
const workflow = createWorkflow({...})
.branch([
[condition1, stepA],
[condition2, stepB],
])
.map({
finalResult: {
step: stepA,
path: 'result' // Now optional - provide fallback
}
});
Why: Branch conditionals execute only one path, so non-executed branches don't produce outputs. The type system now correctly reflects this runtime behavior.
Related issue: https://github.com/mastra-ai/mastra/issues/10642
Memory system now uses processors. Memory processors (MessageHistory, SemanticRecall, WorkingMemory) are now exported from @mastra/memory/processors and automatically added to the agent pipeline based on your memory config. Core processors (ToolCallFilter, TokenLimiter) remain in @mastra/core/processors. (#9254)
Add reserved keys in RequestContext for secure resourceId/threadId setting from middleware (#10657)
This allows middleware to securely set resourceId and threadId via reserved keys in RequestContext (MASTRA_RESOURCE_ID_KEY and MASTRA_THREAD_ID_KEY), which take precedence over client-provided values for security.
feat(workflows): add suspendData parameter to step execute function (#10734)
Adds a new suspendData parameter to workflow step execute functions that provides access to the data originally passed to suspend() when the step was suspended. This enables steps to access context about why they were suspended when they are later resumed.
New Features:
suspendData parameter automatically populated in step execute function when resumingsuspendSchemaExample:
const step = createStep({
suspendSchema: z.object({ reason: z.string() }),
resumeSchema: z.object({ approved: z.boolean() }),
execute: async ({ suspend, suspendData, resumeData }) => {
if (!resumeData?.approved) {
return await suspend({ reason: 'Approval required' });
}
// Access original suspend data when resuming
console.log(`Resuming after: ${suspendData?.reason}`);
return { result: 'Approved' };
},
});
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)Adds trace tagging support to the BrainTrust and Langfuse tracing exporters. (#10765)
Add messageList parameter to processOutputStream for accessing remembered messages during streaming (#10608)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
unexpected json parse issue, log error but dont fail (#10241)
Fixed a bug in agent networks where sometimes the task name was empty (#10629)
Adds tool-result and tool-error chunks to the processor.processOutputStream path. Processors now have access to these two chunks. (#10645)
Include .input in workflow results for both engines and remove the option to omit them from Inngest workflows. (#10688)
getSpeakers endpoint returns an empty array if voice is not configured on the agent and getListeners endpoint returns { enabled: false } if voice is not figured on the agent. (#10560)
When no voice is set on agent don't throw error, by default set voice to undefined rather than DefaultVoice which throws errors when it is accessed.
SimpleAuth and improved CloudAuth (#10490)
When LLMs like Claude Sonnet 4.5 and Gemini 2.4 call tools with all-optional parameters, they send args: undefined instead of args: {}. This caused validation to fail with "root: Required". (#10728)
The fix normalizes undefined/null to {} for object schemas and [] for array schemas before validation.
Fixed tool validation error messages so logs show Zod validation errors directly instead of hiding them inside structured JSON. (#10579)
Fix error when spreading config objects in Mastra constructor (#10718)
Adds validation guards to handle undefined/null values that can occur when config objects are spread ({ ...config }). Previously, if getters or non-enumerable properties resulted in undefined values during spread, the constructor would throw cryptic errors when accessing .id or .name on undefined objects.
Fix GPT-5/o3 reasoning models failing with "required reasoning item" errors when using memory with tools. Empty reasoning is now stored with providerMetadata to preserve OpenAI's item_reference. (#10585)
Fix generateTitle model type to accept AI SDK LanguageModelV2 (#10541)
Updated the generateTitle.model config option to accept MastraModelConfig instead of MastraLanguageModel. This allows users to pass raw AI SDK LanguageModelV2 models (e.g., anthropic.languageModel('claude-3-5-haiku-20241022')) directly without type errors.
Previously, passing a standard LanguageModelV2 would fail because MastraLanguageModelV2 has different doGenerate/doStream return types. Now MastraModelConfig is used consistently across:
memory/types.ts - generateTitle.model configagent.ts - genTitle, generateTitleFromUserMessage, resolveTitleGenerationConfigagent-legacy.ts - AgentLegacyCapabilities interfaceFix message ordering when using toAISdkV5Messages or prepareStep (#10686)
Messages without createdAt timestamps were getting shuffled because they all received identical timestamps during conversion. Now messages are assigned monotonically increasing timestamps via generateCreatedAt(), preserving input order.
Before:
Input: [user: "hello", assistant: "Hi!", user: "bye"]
Output: [user: "bye", assistant: "Hi!", user: "hello"] // shuffled!
After:
Input: [user: "hello", assistant: "Hi!", user: "bye"]
Output: [user: "hello", assistant: "Hi!", user: "bye"] // correct order
Fix Scorer not using custom gateways registered with Mastra (#10778)
Scorers now have access to custom gateways when resolving models. Previously, calling resolveModelConfig in the scorer didn't pass the Mastra instance, so custom gateways were never available.
Fix workflow run status not being updated from storage snapshot in createRun (#10664)
When createRun is called with an existing runId, it now correctly updates the run's status from the storage snapshot. This fixes the issue where different workflow instances (e.g., different API requests) would get a run with 'pending' status instead of the correct status from storage (e.g., 'suspended').
Pass resourceId and threadId to network agent's subAgent when it has its own memory (#10592)
use agent.getMemory to fetch the memory instance on the Agent class to make sure that storage gets set if memory doesn't set it itself. (#10556)
Built-in processors that use internal agents (PromptInjectionDetector, ModerationProcessor, PIIDetector, LanguageDetector, StructuredOutputProcessor) now accept providerOptions to control model behavior. (#10651)
This lets you pass provider-specific settings like reasoningEffort for OpenAI thinking models:
const processor = new PromptInjectionDetector({
model: 'openai/o1-mini',
threshold: 0.7,
strategy: 'block',
providerOptions: {
openai: {
reasoningEffort: 'low',
},
},
});
Improved typing for workflow.then to allow the provided steps inputSchema to be a subset of the previous steps outputSchema. Also errors if the provided steps inputSchema is a superset of the previous steps outputSchema. (#10763)
Fix type issue with workflow .parallel() when passing multiple steps, one or more of which has a resumeSchema provided. (#10708)
Adds bidirectional integration with otel tracing via a new @mastra/otel-bridge package. (#10482)
Adds processInputStep method to the Processor interface. Unlike processInput which runs once at the start, this runs at each step of the agentic loop (including tool call continuations). (#10650)
const processor: Processor = {
id: 'my-processor',
processInputStep: async ({ messages, messageList, stepNumber, systemMessages }) => {
// Transform messages at each step before LLM call
return messageList;
},
};
When using output processors with agent.generate(), result.text was returning the unprocessed LLM response instead of the processed text. (#10735)
Before:
const result = await agent.generate('hello');
result.text; // "hello world" (unprocessed)
result.response.messages[0].content[0].text; // "HELLO WORLD" (processed)
After:
const result = await agent.generate('hello');
result.text; // "HELLO WORLD" (processed)
The bug was caused by the text delayed promise being resolved twice - first correctly with the processed text, then overwritten with the unprocessed buffered text.
Refactored default engine to fit durable execution better, and the inngest engine to match. (#10627) Also fixes requestContext persistence by relying on inngest step memoization.
Unifies some of the stepResults and error formats in both engines.
Allow direct access to server app handle directly from Mastra instance. (#10598)
// Before: HTTP request to localhost
const response = await fetch(`http://localhost:5000/api/tools`);
// After: Direct call via app.fetch()
const app = mastra.getServerApp<Hono>();
const response = await app.fetch(new Request('http://internal/api/tools'));
mastra.getServerApp<T>() to access the underlying Hono/Express appmastra.getMastraServer() and mastra.setMastraServer() for adapter accessMastraServerBase class in @mastra/core/server for adapter implementationsFix network agent not getting text-delta from subAgent when .stream is used (#10533)
Fix discriminatedUnion schema information lost when json schema is converted to zod (#10500)
Fix writer.custom not working during workflow resume operations (#10720)
When a workflow step is resumed, the writer parameter was not being properly passed through, causing writer.custom() calls to fail. This fix ensures the writableStream parameter is correctly passed to both run.resume() and run.start() calls in the workflow execution engine, allowing custom events to be emitted properly during resume operations.
Fix corrupted provider-registry.json file in global cache and regenerate corrupted files (#10606)
Fix TypeScript error when using Zod schemas in defaultOptions.structuredOutput (#10710)
Previously, defining structuredOutput.schema in defaultOptions would cause a TypeScript error because the type only accepted undefined. Now any valid OutputSchema is correctly accepted.
Add support for providerOptions when defining tools. This allows developers to specify provider-specific configurations (like Anthropic's cacheControl) per tool. (#10649)
createTool({
id: 'my-tool',
providerOptions: {
anthropic: { cacheControl: { type: 'ephemeral' } },
},
// ...
});
Fixed OpenAI reasoning message merging so distinct reasoning items are no longer dropped when they share a message ID. Prevents downstream errors where a function call is missing its required "reasoning" item. See #9005. (#10614)
Improve nested ts-config paths resolution for NX users (#6243)
Fix dev playground auth to allow non-protected paths to bypass authentication when MASTRA_DEV=true, while still requiring the x-mastra-dev-playground header for protected endpoints (#10722)
Unified MastraServer API with MCP transport routes (#10644)
Breaking Changes:
HonoServerAdapter to MastraServer in @mastra/honoExpressServerAdapter to MastraServer in @mastra/expressServerAdapter to MastraServerBase in @mastra/serverNew Features:
/api/mcp/:serverId/mcp (HTTP) and /api/mcp/:serverId/sse (SSE)express.json() middleware compatibility for MCP routes@mastra/server/authTesting:
@internal/server-adapter-test-utilsFixed module not found errors during production builds by skipping transitive dependency validation. Production builds now only bundle direct dependencies, which also results in faster deployment times. (#10587)
Fixes #10116 Fixes #10055 Fixes #9951
Allow direct access to server app handle directly from Mastra instance. (#10598)
// Before: HTTP request to localhost
const response = await fetch(`http://localhost:5000/api/tools`);
// After: Direct call via app.fetch()
const app = mastra.getServerApp<Hono>();
const response = await app.fetch(new Request('http://internal/api/tools'));
mastra.getServerApp<T>() to access the underlying Hono/Express appmastra.getMastraServer() and mastra.setMastraServer() for adapter accessMastraServerBase class in @mastra/core/server for adapter implementationsFixed bundling to correctly exclude subpath imports of external packages. Previously, when a package like lodash was marked as external, subpath imports such as lodash/merge were still being bundled incorrectly. Now all subpaths are properly excluded. (#10588)
Fixes #10055
Improved error messages when bundling fails during deployment. (#10756)
What changed:
SimpleAuth and improved CloudAuth (#10490)
Fix installing external peer deps for cloud deployer (#10783)
Adds --force and --legacy-peer-deps=false flags to npm install command to ensure peer dependencies for external packages are properly installed in the mastra output directory. The --legacy-peer-deps=false flag overrides package manager settings (like pnpm's default of true) to ensure consistent behavior.
.netlify/v1/config.json file to not let Netlify bundle the functions (since Mastra already bundles its output). Also, re-enable ESM shimming. (#10405)Add DuckDB vector store implementation (#10760)
Adds DuckDB as a vector store provider for Mastra, enabling embedded high-performance vector storage without requiring an external server.
import { DuckDBVector } from '@mastra/duckdb';
const vectorStore = new DuckDBVector({
id: 'my-store',
path: ':memory:', // or './vectors.duckdb' for persistence
});
await vectorStore.createIndex({
indexName: 'docs',
dimension: 1536,
metric: 'cosine',
});
await vectorStore.upsert({
indexName: 'docs',
vectors: [[0.1, 0.2, ...]],
metadata: [{ text: 'hello world' }],
});
const results = await vectorStore.query({
indexName: 'docs',
queryVector: [0.1, 0.2, ...],
topK: 10,
filter: { text: 'hello world' },
});
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Add ElasticSearch vector store support (#10741)
New @mastra/elasticsearch package providing vector similarity search using ElasticSearch 8.x+ with dense_vector fields.
import { ElasticSearchVector } from '@mastra/elasticsearch';
const vectorDB = new ElasticSearchVector({
url: 'http://localhost:9200',
id: 'my-vectors',
});
await vectorDB.createIndex({
indexName: 'embeddings',
dimension: 1536,
metric: 'cosine',
});
await vectorDB.upsert({
indexName: 'embeddings',
vectors: [embedding],
metadata: [{ source: 'doc.pdf' }],
});
const results = await vectorDB.query({
indexName: 'embeddings',
queryVector: queryEmbedding,
topK: 10,
filter: { source: 'doc.pdf' },
});
getReasoningFromRunOutput utility function for extracting reasoning text from scorer run outputs. This enables scorers to access chain-of-thought reasoning from models like deepseek-reasoner in preprocess functions. (#10684)Include .input in workflow results for both engines and remove the option to omit them from Inngest workflows. (#10688)
Using createStep with a nested Inngest workflow now returns the workflow itself, maintaining the correct .invoke() execution flow Inngest workflows need to operate. (#10689)
Refactored default engine to fit durable execution better, and the inngest engine to match. (#10627) Also fixes requestContext persistence by relying on inngest step memoization.
Unifies some of the stepResults and error formats in both engines.
Miscellanous bug fixes and test fixes: (#10515)
Emit workflow-step-result and workflow-step-finish when step fails in inngest workflow (#10555)
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Add projectName config option for LangSmith exporter (#10762)
You can now specify which LangSmith project to send traces to via the projectName config option. This overrides the LANGCHAIN_PROJECT environment variable.
new LangSmithExporter({
apiKey: process.env.LANGSMITH_API_KEY,
projectName: 'my-custom-project',
});
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Fix MCPClient automatic reconnection when session becomes invalid (#10660)
When an MCP server restarts, the session ID becomes invalid causing "Bad Request: No valid session ID provided" errors. The MCPClient now automatically detects session-related errors, reconnects to the server, and retries the tool call.
This fix addresses issue #7675 where MCPClient would fail to reconnect after an MCP server went offline and came back online.
Populate RequestContext from options.extra for workflows and agents (#10655)
Workflows and agents exposed as MCP tools now receive all keys from options.extra directly on the RequestContext. This allows workflows and agents to access authentication information (authInfo, sessionId, requestId, etc.) via requestContext.get('key') when exposed via MCPServer.
Fix timeout parameter position in listTools call (#10609)
The MCP SDK's listTools signature is listTools(params?, options?). Timeout was incorrectly passed as params (1st arg) instead of options (2nd arg), causing timeouts to not be applied to requests.
Unified MastraServer API with MCP transport routes (#10644)
Breaking Changes:
HonoServerAdapter to MastraServer in @mastra/honoExpressServerAdapter to MastraServer in @mastra/expressServerAdapter to MastraServerBase in @mastra/serverNew Features:
/api/mcp/:serverId/mcp (HTTP) and /api/mcp/:serverId/sse (SSE)express.json() middleware compatibility for MCP routes@mastra/server/authTesting:
@internal/server-adapter-test-utilsAdd MCP Roots capability support (fixes #8660) (#10646)
This adds support for the MCP Roots capability, allowing clients to expose filesystem roots to MCP servers like @modelcontextprotocol/server-filesystem.
New Features:
roots option to server configuration for specifying allowed directoriesroots capability when roots are configuredroots/list requests from servers per MCP specclient.roots getter to access configured rootsclient.setRoots() to dynamically update rootsclient.sendRootsListChanged() to notify servers of root changesUsage:
const client = new MCPClient({
servers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
roots: [
{ uri: 'file:///tmp', name: 'Temp Directory' },
{ uri: 'file:///home/user/projects', name: 'Projects' },
],
},
},
});
Before this fix, the filesystem server would log:
"Client does not support MCP Roots, using allowed directories set from server args"
After this fix, the server properly receives roots from the client:
"Updated allowed directories from MCP roots: 2 valid directories"
Add MCP progress notification support and refactor client structure (#10637)
enableProgressTracking: true in server config and use client.progress.onUpdate(handler) to receive progress updates during long-running tool operations.ProgressClientActions class for handling progress notificationsactions/ directory (elicitation, prompt, resource, progress)types.ts file for better code organizationMemory system now uses processors. Memory processors (MessageHistory, SemanticRecall, WorkingMemory) are now exported from @mastra/memory/processors and automatically added to the agent pipeline based on your memory config. Core processors (ToolCallFilter, TokenLimiter) remain in @mastra/core/processors. (#9254)
Schema-based working memory now uses merge semantics instead of replace semantics. (#10659)
Before: Each working memory update replaced the entire memory, causing data loss across conversation turns.
After: For schema-based working memory:
null to delete itTemplate-based (Markdown) working memory retains the existing replace semantics.
This fixes issue #7775 where users building profile-like schemas would lose information from previous turns.
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)Fix recall() to return newest messages when using lastMessages config (#10543)
When using lastMessages: N config without an explicit orderBy, the recall() function was returning the OLDEST N messages instead of the NEWEST N messages. This completely breaks conversation history for any thread that grows beyond the lastMessages limit.
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Adds trace tagging support to the BrainTrust and Langfuse tracing exporters. (#10765)
Adds bidirectional integration with otel tracing via a new @mastra/otel-bridge package. (#10482)
Unified MastraServer API with MCP transport routes (#10644)
Breaking Changes:
HonoServerAdapter to MastraServer in @mastra/honoExpressServerAdapter to MastraServer in @mastra/expressServerAdapter to MastraServerBase in @mastra/serverNew Features:
/api/mcp/:serverId/mcp (HTTP) and /api/mcp/:serverId/sse (SSE)express.json() middleware compatibility for MCP routes@mastra/server/authTesting:
@internal/server-adapter-test-utilsAllow direct access to server app handle directly from Mastra instance. (#10598)
// Before: HTTP request to localhost
const response = await fetch(`http://localhost:5000/api/tools`);
// After: Direct call via app.fetch()
const app = mastra.getServerApp<Hono>();
const response = await app.fetch(new Request('http://internal/api/tools'));
mastra.getServerApp<T>() to access the underlying Hono/Express appmastra.getMastraServer() and mastra.setMastraServer() for adapter accessMastraServerBase class in @mastra/core/server for adapter implementationsAdd stream data redaction to prevent sensitive information leaks in agent stream API responses. (#10705)
The stream API endpoint now automatically redacts request data from stream chunks (step-start, step-finish, finish) which could contain system prompts, tool definitions, and API keys. Redaction is enabled by default and can be disabled for debugging/internal services via streamOptions.redact.
Unified MastraServer API with MCP transport routes (#10644)
Breaking Changes:
HonoServerAdapter to MastraServer in @mastra/honoExpressServerAdapter to MastraServer in @mastra/expressServerAdapter to MastraServerBase in @mastra/serverNew Features:
/api/mcp/:serverId/mcp (HTTP) and /api/mcp/:serverId/sse (SSE)express.json() middleware compatibility for MCP routes@mastra/server/authTesting:
@internal/server-adapter-test-utilsAllow direct access to server app handle directly from Mastra instance. (#10598)
// Before: HTTP request to localhost
const response = await fetch(`http://localhost:5000/api/tools`);
// After: Direct call via app.fetch()
const app = mastra.getServerApp<Hono>();
const response = await app.fetch(new Request('http://internal/api/tools'));
mastra.getServerApp<T>() to access the underlying Hono/Express appmastra.getMastraServer() and mastra.setMastraServer() for adapter accessMastraServerBase class in @mastra/core/server for adapter implementationsAdd stream data redaction to prevent sensitive information leaks in agent stream API responses. (#10705)
The stream API endpoint now automatically redacts request data from stream chunks (step-start, step-finish, finish) which could contain system prompts, tool definitions, and API keys. Redaction is enabled by default and can be disabled for debugging/internal services via streamOptions.redact.
fix(pg): qualify vector type to fix schema lookup (#10786)
feat(storage): support querying messages from multiple threads (#10663)
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)fix: ensure score responses match saved payloads for Mastra Stores. (#10557)
Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Fix wrong hook arg type when retrieving workflow runs (#10755)
Fix discriminatedUnion schema information lost when json schema is converted to zod (#10500)
Hide time travel on map steps in Studio (#10631)
Added tracing options to workflow runs and agent generate / stream / network. You can now configure tracing options, custom request context keys, and parent trace/span IDs through a new "Tracing options" tab in the workflow/agent ui UI. (#10742)
Usage:
The workflow settings are now accessible via the new useTracingSettings hook and TracingSettingsProvider:
import { TracingSettingsProvider, useWorkflowSettings } from '@mastra/playground-ui';
// Wrap your workflow components with the provider
<TracingSettingsProvider entityId="my-workflow" entityType="workflow">
<YourWorkflowUI />
</TracingSettingsProvider>;
// Access settings in child components
const { settings, setSettings } = useTracingSettings();
// Configure tracing options
setSettings({
tracingOptions: {
metadata: { userId: '123' },
requestContextKeys: ['user.email'],
traceId: 'abc123',
},
});
Tracing options are persisted per workflow/agent in localStorage and automatically applied to all workflow/agent executions.
Add maxSize support for HTML chunking strategies (#10654)
Added support for the maxSize option in HTML chunking strategies (headers and sections), allowing users to control the maximum chunk size when chunking HTML documents. Previously, HTML chunks could be excessively large when sections contained substantial content.
Changes:
maxSize support to headers strategy - applies RecursiveCharacterTransformer after header-based splittingmaxSize support to sections strategy - applies RecursiveCharacterTransformer after section-based splittingsplitHtmlByHeaders content extraction bug - changed from broken nextElementSibling to working parentNode.childNodes approachUsage:
import { MDocument } from '@mastra/rag';
const doc = MDocument.fromHTML(htmlContent);
const chunks = await doc.chunk({
strategy: 'html',
headers: [
['h1', 'Header 1'],
['h2', 'Header 2'],
['h3', 'Header 3'],
],
maxSize: 512, // Control chunk size
overlap: 50, // Optional overlap for context
});
Results from real arXiv paper test:
Fixes #7942
Unified MastraServer API with MCP transport routes (#10644)
Breaking Changes:
HonoServerAdapter to MastraServer in @mastra/honoExpressServerAdapter to MastraServer in @mastra/expressServerAdapter to MastraServerBase in @mastra/serverNew Features:
/api/mcp/:serverId/mcp (HTTP) and /api/mcp/:serverId/sse (SSE)express.json() middleware compatibility for MCP routes@mastra/server/authTesting:
@internal/server-adapter-test-utilsAllow direct access to server app handle directly from Mastra instance. (#10598)
// Before: HTTP request to localhost
const response = await fetch(`http://localhost:5000/api/tools`);
// After: Direct call via app.fetch()
const app = mastra.getServerApp<Hono>();
const response = await app.fetch(new Request('http://internal/api/tools'));
mastra.getServerApp<T>() to access the underlying Hono/Express appmastra.getMastraServer() and mastra.setMastraServer() for adapter accessMastraServerBase class in @mastra/core/server for adapter implementationsfix(a2a): fix streaming and memory support for A2A protocol (#10653)
Client (@mastra/client-js):
sendStreamingMessage to properly return a streaming response instead of attempting to parse it as JSONServer (@mastra/server):
contextId as threadId for memory persistence across conversationsresourceId via params.metadata.resourceId or message.metadata.resourceId, falling back to agentIdAdd stream data redaction to prevent sensitive information leaks in agent stream API responses. (#10705)
The stream API endpoint now automatically redacts request data from stream chunks (step-start, step-finish, finish) which could contain system prompts, tool definitions, and API keys. Redaction is enabled by default and can be disabled for debugging/internal services via streamOptions.redact.
threadId: string | string[] was being passed to places expecting Scalar typelistMessages across all adapters when threadId is an array_getIncludedMessages to look up message threadId by ID (since message IDs are globally unique)msg-idx:{messageId} index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)Unify transformScoreRow functions across storage adapters (#10648)
Added a unified transformScoreRow function in @mastra/core/storage that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
preferredTimestampFields: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)convertTimestamps: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)nullValuePattern: Skip values matching pattern (ClickHouse's '_null_')fieldMappings: Map source column names to schema fields (LibSQL's additionalLLMContext)Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
Add Vertex AI support to GoogleVoice provider (#10661)
vertexAI, project, and location configuration optionsisUsingVertexAI(), getProject(), getLocation()GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variablesThis makes @mastra/voice-google consistent with @mastra/voice-google-gemini-live and enables enterprise deployments using Google Cloud project-based authentication instead of API keys.
Fix discriminatedUnion schema information lost when json schema is converted to zod (#10500)
Hide time travel on map steps in Studio (#10631)
During npm create-mastra you can now optionally initialize a git repository in the newly created project. The setup wizard will prompt for this option. (#9792)
Fix discriminatedUnion schema information lost when json schema is converted to zod (#10500)
Hide time travel on map steps in Studio (#10631)
Fixed tool list empty state when there are no agents so the page renders correctly. (#10711)
Fetched April 7, 2026