Request context

Trust: ★★★☆☆ (0.90) · 0 validations · developer_reference

Published: 2026-05-10 · Source: crawler_authoritative

Tình huống

Mastra SDK documentation for using RequestContext to pass runtime values to agents, tools, and workflows for dynamic behavior based on user attributes, locale, or other request-specific data.

Insight

RequestContext enables passing request-specific values into agents, networks, workflows, and tools via a typed key-value store. The .set(key, value) method defines values before execution, while .get(key) retrieves them in primitives. Agents can access requestContext in configuration options like instructions, model, tools, and memory — all supporting both sync and async functions. Workflow steps access it via their execute function parameters, and tools receive it through the context.requestContext property. Reserved keys MASTRA_RESOURCE_ID_KEY and MASTRA_THREAD_ID_KEY enforce security and user isolation by controlling memory and thread operations with server-side ownership validation. TypeScript generics provide full type inference: RequestContext<MyContext> ensures .set() enforces correct value types, .get() returns properly typed values, .keys() returns typed key unions, and .entries() supports type narrowing. The requestContextSchema property accepts Standard JSON Schema validators (Zod, Valibot, ArkType) for runtime validation with platform-specific behavior: agents and workflows throw errors on validation failure, while tools return error objects. Studio supports named presets via JSON files and the --request-context-presets CLI flag for quick context switching during development.

Hành động

Import RequestContext from ‘@mastra/core/request-context’ and instantiate with optional type parameter. Use .set('key', value) to define context values before passing to agent/workflow/tool calls via the requestContext option. In agents, access values in configuration callbacks using the destructured requestContext parameter with .get('key'). In tools, access via context.requestContext.get('key'). For schema validation, add requestContextSchema: z.object({...}) to agent, tool, workflow, or step definitions. Reserved keys require manual setting in middleware using MASTRA_RESOURCE_ID_KEY and MASTRA_THREAD_ID_KEY constants from ‘@mastra/core/request-context’. For Studio presets, create a JSON file with named preset configurations and pass the file path via mastra dev --request-context-presets ./presets.json.

Kết quả

Request context values become available to all underlying primitives during execution, enabling dynamic instruction tailoring, locale-based behavior, A/B testing variants, and user isolation for multi-tenant applications. Schema validation catches missing or invalid context values early with component-specific error handling.

Điều kiện áp dụng

Requires @mastra/core package. TypeScript generics provide type safety when using the type parameter. Schema validation uses Standard JSON Schema-compatible libraries (Zod, Valibot, ArkType).


Nội dung gốc (Original)

Request context

Agents, tools, and workflows can all accept RequestContext as a parameter, making request-specific values available to the underlying primitives.

When to use RequestContext

Use RequestContext when a primitive’s behavior should change based on runtime conditions. For example, you might switch models or storage backends based on user attributes, or adjust instructions and tool selection based on language.

Note: RequestContext is primarily used for passing data into specific requests. It’s distinct from agent memory, which handles conversation history and state persistence across multiple calls.

Setting values

Pass requestContext into an agent, network, workflow, or tool call to make values available to all underlying primitives during execution. Use .set() to define values before making the call.

The .set() method takes two arguments:

  1. key: The name used to identify the value.
  2. value: The data to associate with that key.
import { RequestContext } from '@mastra/core/request-context'
 
export type UserTier = {
  'user-tier': 'enterprise' | 'pro'
}
 
const requestContext = new RequestContext<UserTier>()
requestContext.set('user-tier', 'enterprise')
 
const agent = mastra.getAgent('weatherAgent')
await agent.generate("What's the weather in London?", {
  requestContext,
})
 
const routingAgent = mastra.getAgent('routingAgent')
routingAgent.network("What's the weather in London?", {
  requestContext,
})
 
const run = await mastra.getWorkflow('weatherWorkflow').createRun()
await run.start({
  inputData: {
    location: 'London',
  },
  requestContext,
})
await run.resume({
  resumeData: {
    city: 'New York',
  },
  requestContext,
})
 
await weatherTool.execute({ location: 'London' }, { requestContext })

Setting values based on request headers

You can populate requestContext dynamically in server middleware by extracting information from the request. In this example, the temperature-unit is set based on the Cloudflare CF-IPCountry header to ensure responses match the user’s locale.

import { Mastra } from '@mastra/core'
import { RequestContext } from '@mastra/core/request-context'
import { testWeatherAgent } from './agents/test-weather-agent'
 
export const mastra = new Mastra({
  agents: { testWeatherAgent },
  server: {
    middleware: [
      async (context, next) => {
        const country = context.req.header('CF-IPCountry')
        const requestContext = context.get('requestContext')
 
        requestContext.set('temperature-unit', country === 'US' ? 'fahrenheit' : 'celsius')
 
        await next()
      },
    ],
  },
})

Info: Visit Middleware for how to use server middleware.

Studio

When developing locally, you can define named presets in a JSON file and load them into Studio with the --request-context-presets CLI flag. This adds a dropdown to the request context editor in Studio so you can quickly switch between configurations without manually editing JSON each time.

mastra dev --request-context-presets ./presets.json
{
  "development": { "userId": "dev-user", "env": "development" },
  "production": { "userId": "prod-user", "env": "production" }
}

When you select a preset from the dropdown, the JSON editor populates with that preset’s values. Editing the JSON manually switches the dropdown back to “Custom”.

Accessing values with agents

You can access the requestContext argument from any supported configuration options in agents. These functions can be sync or async. Use the .get() method to read values from requestContext.

export type UserTier = {
  'user-tier': 'enterprise' | 'pro'
}
 
export const weatherAgent = new Agent({
  id: 'weather-agent',
  name: 'Weather Agent',
  instructions: async ({ requestContext }) => {
    const userTier = requestContext.get('user-tier') as UserTier['user-tier']
 
    if (userTier === 'enterprise') {
    }
  },
  model: ({ requestContext }) => {},
  tools: ({ requestContext }) => {},
  memory: ({ requestContext }) => {},
})

You can also use requestContext with other options like agents, workflows, scorers, inputProcessors, and outputProcessors.

Dynamic instructions

Agent instructions can be provided as an async function, enabling you to resolve prompts dynamically at runtime. Combined with requestContext, this enables patterns like:

  • Personalization: Tailor instructions based on user attributes, preferences, or tier
  • Localization: Adjust tone, language, or behavior based on locale
  • A/B testing: Serve different prompt variants for experimentation
  • External prompt management: Fetch prompts from registry services without redeploying
import { Agent } from '@mastra/core/agent'
 
export const dynamicAgent = new Agent({
  id: 'dynamic-agent',
  name: 'Dynamic Agent',
  instructions: async ({ requestContext }) => {
    const userTier = requestContext?.get('user-tier')
    const locale = requestContext?.get('locale')
 
    // Personalize based on user tier
    const basePrompt =
      userTier === 'enterprise'
        ? 'You are a premium support agent. Provide detailed, thorough responses with technical depth.'
        : 'You are a helpful assistant. Be concise and friendly.'
 
    // Localize behavior
    const localeInstructions = locale === 'ja' ? 'Respond in Japanese using formal keigo.' : ''
 
    return `${basePrompt} ${localeInstructions}`.trim()
  },
  model: 'openai/gpt-5.4',
})

Fetching from a prompt registry

If your organization uses a prompt registry service for central prompt management, you can fetch instructions at runtime. This allows you to update prompts without redeploying, run experiments with variants, and track prompt usage across your agents.

import { Agent } from '@mastra/core/agent'
 
// Your prompt registry client
import { promptRegistry } from '../lib/prompt-registry'
 
export const registryAgent = new Agent({
  id: 'registry-agent',
  name: 'Registry Agent',
  instructions: async ({ requestContext }) => {
    const prompt = await promptRegistry.getPrompt({
      promptId: 'customer-support-agent',
      // Pass context for variant selection or tracking
      variant: requestContext?.get('experiment-variant'),
      userId: requestContext?.get('user-id'),
    })
 
    return prompt.content
  },
  model: 'openai/gpt-5.4',
})

Info: Visit Agent for a full list of configuration options.

Accessing values from workflow steps

You can access the requestContext argument from a workflow step’s execute function. This function can be sync or async. Use the .get() method to read values from requestContext.

export type UserTier = {
  'user-tier': 'enterprise' | 'pro'
}
 
const stepOne = createStep({
  id: 'step-one',
  execute: async ({ requestContext }) => {
    const userTier = requestContext.get('user-tier') as UserTier['user-tier']
 
    if (userTier === 'enterprise') {
    }
  },
})

Info: Visit createStep() for a full list of configuration options.

Accessing values with tools

You can access the requestContext argument from a tool’s execute function. This function is async. Use the .get() method to read values from requestContext.

export type UserTier = {
  'user-tier': 'enterprise' | 'pro'
}
 
export const weatherTool = createTool({
  id: 'weather-tool',
  execute: async (inputData, context) => {
    const userTier = context?.requestContext?.get('user-tier') as UserTier['user-tier'] | undefined
 
    if (userTier === 'enterprise') {
    }
  },
})

Info: Visit createTool() for a full list of configuration options.

Reserved keys

Mastra reserves special context keys for security purposes. When set, these keys take precedence over client-provided values. The server automatically validates ownership and returns 403 errors when users attempt to access resources they don’t own.

The easiest way to set MASTRA_RESOURCE_ID_KEY is via the mapUserToResourceId callback in auth config:

auth: {
  authenticateToken: async token => verifyToken(token),
  mapUserToResourceId: user => user.id,
}

You can also set these keys manually in middleware:

import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from '@mastra/core/request-context'
 
// In middleware: force memory operations to use authenticated user's ID
requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id)
 
// In middleware: set validated thread ID
requestContext.set(MASTRA_THREAD_ID_KEY, threadId)
KeyPurpose
MASTRA_RESOURCE_ID_KEYForces all memory operations to use this resource ID. The server validates that accessed threads belong to this resource and returns 403 if not.
MASTRA_THREAD_ID_KEYForces thread operations to use this thread ID, overriding client-provided values

These keys are used to implement user isolation in multi-tenant applications. See Authorization middleware for usage examples.

TypeScript support

When you provide a type parameter to RequestContext, all methods are fully typed:

import { RequestContext } from '@mastra/core/request-context'
 
type MyContext = {
  userId: string
  maxTokens: number
  isPremium: boolean
}
 
const ctx = new RequestContext<MyContext>()
 
// set() enforces correct value types
ctx.set('userId', 'user-123') // ✓ valid
ctx.set('maxTokens', 4096) // ✓ valid
ctx.set('maxTokens', 'wrong') // ✗ TypeScript error: expected number
 
// get() returns the correct type automatically
const tokens = ctx.get('maxTokens') // inferred as number
const id = ctx.get('userId') // inferred as string
 
// keys() returns typed keys
for (const key of ctx.keys()) {
  // key is "userId" | "maxTokens" | "isPremium"
}
 
// entries() supports type narrowing
for (const [key, value] of ctx.entries()) {
  if (key === 'maxTokens') {
    // TypeScript knows value is number here
    console.log(value.toFixed(2))
  }
  if (key === 'userId') {
    // TypeScript knows value is string here
    console.log(value.toUpperCase())
  }
}

Schema validation

Use requestContextSchema to define a Standard JSON Schema (Zod, Valibot, ArkType, etc.) that validates request context values at runtime. This catches missing or invalid context values early, provides clear error messages, and gives you type inference within your component.

Agent schema validation

When you define requestContextSchema on an agent, the context is validated at the start of generate() or stream(). If validation fails, the agent throws a MastraError before any LLM calls are made.

import { Agent } from '@mastra/core/agent'
import { z } from 'zod'
 
export const validatedAgent = new Agent({
  id: 'validated-agent',
  name: 'Validated Agent',
  requestContextSchema: z.object({
    userId: z.string(),
    apiKey: z.string(),
  }),
  instructions: ({ requestContext }) => {
    // Access all values as a typed object
    const { userId, apiKey } = requestContext.all
    // { userId: string; apiKey: string }
 
    // Or retrieve individual values with .get()
    const id = requestContext.get('userId')
    // string
 
    return `You are helping user ${userId}`
  },
  model: 'openai/gpt-5.4',
})

When validation fails, the error includes the agent ID and details about which fields failed:

Request context validation failed for agent 'validated-agent':
- apiKey: Required

Tool schema validation

When you define requestContextSchema on a tool, the context is validated before execute() runs. Unlike agents, tools return a validation error object instead of throwing:

import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
 
export const validatedTool = createTool({
  id: 'validated-tool',
  description: 'A tool that requires authenticated context',
  inputSchema: z.object({
    query: z.string(),
  }),
  requestContextSchema: z.object({
    userId: z.string(),
  }),
  execute: async (inputData, context) => {
    // Access all values as a typed object
    const { userId } = context.requestContext?.all ?? {}
    // { userId: string }
 
    // Or retrieve individual values with .get()
    const id = context.requestContext?.get('userId')
    // string | undefined
 
    return { result: `Processed for ${userId}` }
  },
})

When validation fails, the tool returns an error object instead of throwing:

{
  "error": true,
  "message": "Request context validation failed for validated-tool. Please fix the following errors and try again:\n- userId: Required\n\nProvided context: {}"
}

Workflow schema validation

When you define requestContextSchema on a workflow, the context is validated at the start of run.start(). If validation fails, the workflow throws an error before any steps execute.

import { createWorkflow, createStep } from '@mastra/core/workflows'
import { z } from 'zod'
 
// Define schema once and share between workflow and steps
const workflowContextSchema = z.object({
  tenantId: z.string(),
})
 
const step1 = createStep({
  id: 'step-1',
  inputSchema: z.object({ message: z.string() }),
  outputSchema: z.object({ result: z.string() }),
  // Add schema to step for type inference
  requestContextSchema: workflowContextSchema,
  execute: async ({ inputData, requestContext }) => {
    // Access all values as a typed object
    const { tenantId } = requestContext.all
    // { tenantId: string }
 
    // Or retrieve individual values with .get()
    const id = requestContext.get('tenantId')
    // string
 
    return { result: `Processed for tenant ${tenantId}` }
  },
})
 
export const validatedWorkflow = createWorkflow({
  id: 'validated-workflow',
  inputSchema: z.object({ message: z.string() }),
  outputSchema: z.object({ result: z.string() }),
  requestContextSchema: workflowContextSchema,
})
  .then(step1)
  .commit()

When validation fails, the workflow throws an error:

Request context validation failed for workflow 'validated-workflow':
- tenantId: Required

Steps can also define their own requestContextSchema for step-level validation. Step validation runs before the step’s execute() function.

Validation behavior

ComponentPropertyValidation timingOn failure
AgentrequestContextSchemaStart of generate() / stream()Throws MastraError
ToolrequestContextSchemaBefore execute()Returns error object
WorkflowrequestContextSchemaStart of run.start()Throws Error
SteprequestContextSchemaBefore step execute()Step fails with error

Best practices

Match your middleware: Define the same required fields in your schema that your middleware sets. This ensures the contract between middleware and components is explicit and validated.

// Middleware sets these fields
requestContext.set('userId', user.id)
requestContext.set('tenantId', tenant.id)
 
// Schema validates they exist
requestContextSchema: z.object({
  userId: z.string(),
  tenantId: z.string(),
})

Use optional fields for conditional context: Use .optional() for values that may not always be present.

requestContextSchema: z.object({
  userId: z.string(), // Always required
  experimentVariant: z.string().optional(), // May not be set
})

Handle tool validation errors: Since tools return error objects instead of throwing, check for errors in your agent or workflow logic when tool execution is critical.

Liên kết

Xem thêm: