Skip to main content
You can customize how an agent’s Foundry model processes requests at runtime using structured inputs. Structured inputs are placeholders defined in the agent using handlebar template syntax ({{variableName}}). At runtime, you provide actual values to dynamically customize agent instructions, tool resource configurations, and response parameters—without creating separate agent versions for each configuration. In this article, you learn how to:
  • Define structured inputs in an agent definition
  • Use handlebar templates in agent instructions
  • Dynamically configure tool resources such as Code Interpreter and File Search
  • Pass structured input values at runtime through the Responses API

Prerequisites

  • A basic or standard agent environment.
  • The latest SDK package for your language. See the quickstart for installation steps.
  • Azure credentials configured for authentication (such as DefaultAzureCredential).
  • Your Foundry project endpoint URL and model deployment name.

What are structured inputs?

Structured inputs use handlebar template syntax ({{variableName}}) to create parameterized agent definitions. You define input schemas in the agent definition under structured_inputs, where each input has a name, description, type, and optional default value. At runtime, supply actual values that replace the template placeholders before the agent processes the request. Structured inputs support two categories of overrides:
  • Instruction overrides: Parameterize agent instructions, response-level instructions, and system or developer messages.
  • Tool resource overrides: Dynamically configure tool properties at runtime, including:
    • File search vector store IDs
    • Code interpreter file IDs and containers
    • Model Context Protocol (MCP) server URLs and headers
For array fields like file_ids and vector_store_ids, the system automatically removes empty string values at runtime. This feature enables flexible input counts – define more template slots than needed and leave unused ones empty.

Supported structured input properties

The following table lists the agent definition properties that support handlebar templates:
CategoryPropertyDescription
InstructionsAgent instructionsAgent-level instruction text
InstructionsResponse instructionsInstructions passed in the Responses API request
InstructionsSystem/developer message contentMessage content in the input array
File Searchvector_store_idsArray of vector store IDs (empty values stripped)
Code Interpretercontainer (string)Container ID for a preconfigured container
Code Interpretercontainer.file_ids (array)File IDs in an auto container (empty values stripped)
MCPserver_labelLabel for the MCP server
MCPserver_urlURL for the MCP server endpoint
MCPheaders (values)HTTP header values as key-value pairs
Azure AI SearchfilterOData filter expression applied to a search index

Use structured inputs with agent instructions

The simplest use of structured inputs is to parameterize agent instructions. Define handlebar templates in the instructions field and supply values at runtime. This approach lets you personalize agent behavior for different users or contexts without creating multiple agent versions. The following examples create an agent whose instructions include user-specific details and then supply those values when creating a response.

Use structured inputs with Code Interpreter

By using structured inputs, you can dynamically configure which files and containers the Code Interpreter tool uses at runtime. Define handlebar templates in the tool’s file_ids or container properties, and then supply actual IDs when creating a response. By using structured inputs, you can dynamically configure which vector stores the File Search tool queries at runtime. Define template placeholders in the vector_store_ids array, and then supply actual vector store IDs when creating a response. By using structured inputs, you can dynamically configure the Azure AI Search tool’s index filter at runtime. Define a handlebar template inside the OData filter expression, and then supply the actual filter value when creating a response. This pattern lets a single agent definition serve users whose queries must be scoped to different subsets of an index without creating a separate agent version per filter value.

Use structured inputs with MCP servers

By using structured inputs, you can dynamically configure MCP server connections at runtime. You can set the server URL, authentication headers, and server label. By using this approach, a single agent definition can connect to different MCP servers depending on the context. The following JSON shows the request body for the Create Agent Version operation (POST /agents?api-version=v1). The agent definition includes MCP tool properties with handlebar template placeholders:
{
  "name": "mcp-dynamic-agent",
  "definition": {
    "kind": "prompt",
    "model": "gpt-4o",
    "instructions": "You are a development assistant for {{project_name}}.",
    "tools": [
      {
        "type": "mcp",
        "server_label": "{{server_label}}",
        "server_url": "{{server_url}}",
        "require_approval": "never",
        "headers": {
          "Authorization": "{{auth_token}}",
          "X-Project-ID": "{{project_id}}"
        }
      }
    ],
    "structured_inputs": {
      "project_name": {
        "description": "Project name",
        "required": true
      },
      "server_label": {
        "description": "MCP server label",
        "required": true,
        "schema": {"type": "string"}
      },
      "server_url": {
        "description": "MCP server URL",
        "required": true,
        "schema": {"type": "string"}
      },
      "auth_token": {
        "description": "Authentication token",
        "required": true,
        "schema": {"type": "string"}
      },
      "project_id": {
        "description": "Project identifier",
        "required": true,
        "schema": {"type": "string"}
      }
    }
  }
}
At runtime, supply the actual server configuration values in the request body for the Create Response operation (POST /openai/v1/responses):
{
  "agent_reference": {
    "type": "agent_reference",
    "name": "mcp-dynamic-agent"
  },
  "input": [{"type": "message", "role": "user", "content": "List recent commits"}],
  "structured_inputs": {
    "project_name": "CloudSync API",
    "server_label": "cloudsync-repo",
    "server_url": "https://gitmcp.io/myorg/cloudsync-api",
    "auth_token": "Bearer ghp_xxxxxxxxxxxx",
    "project_id": "proj_12345"
  }
}
The SDK patterns for MCP structured inputs follow the same approach shown in the previous examples. Define the template placeholders in the MCP tool properties, declare the structured input schemas in the agent definition, and supply the values at runtime. The following Python example shows the complete pattern:
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    MCPTool,
    PromptAgentDefinition,
    StructuredInputDefinition,
)
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Create MCP tool with template placeholders
tool = MCPTool(
    server_label="{{server_label}}",
    server_url="{{server_url}}",
    require_approval="never",
    headers={"Authorization": "{{auth_token}}", "X-Project-ID": "{{project_id}}"},
)

# Create agent with structured inputs for MCP configuration
agent = project.agents.create_version(
    agent_name="mcp-dynamic-agent",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions="You are a helpful development assistant for {{project_name}}.",
        tools=[tool],
        structured_inputs={
            "project_name": StructuredInputDefinition(
                description="Project name", required=True, schema={"type": "string"},
            ),
            "server_label": StructuredInputDefinition(
                description="MCP server label", required=True, schema={"type": "string"},
            ),
            "server_url": StructuredInputDefinition(
                description="MCP server URL", required=True, schema={"type": "string"},
            ),
            "auth_token": StructuredInputDefinition(
                description="Authentication token", required=True, schema={"type": "string"},
            ),
            "project_id": StructuredInputDefinition(
                description="Project identifier", required=True, schema={"type": "string"},
            ),
        },
    ),
)

# Supply MCP server configuration at runtime
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="List recent commits",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {
            "project_name": "CloudSync API",
            "server_label": "cloudsync-repo",
            "server_url": "https://gitmcp.io/myorg/cloudsync-api",
            "auth_token": "Bearer ghp_xxxxxxxxxxxx",
            "project_id": "proj_12345",
        },
    },
)
print(response.output_text)
For more information about connecting to MCP servers, see Connect agents to MCP servers.

Use structured inputs in the Responses API

You can use handlebar templates directly in Responses API calls without defining them in the agent definition. This approach works for response-level instructions and for system or developer messages in the input array.

Response-level instructions with structured inputs

Pass structured inputs alongside instructions in a response request to parameterize the system prompt:
{
  "instructions": "You are assisting {{customerName}} from {{companyName}} located in {{location}}.",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": "Hello, who am I?"
    }
  ],
  "structured_inputs": {
    "customerName": "Bob Johnson",
    "companyName": "Tech Corp",
    "location": "San Francisco"
  },
  "model": "gpt-4o"
}

System and developer messages with structured inputs

Use handlebar templates in system and developer message content to inject runtime values into the conversation context:
{
  "instructions": "You are a helpful assistant.",
  "input": [
    {
      "type": "message",
      "role": "system",
      "content": "The user's name is {{userName}} and they work in {{department}}."
    },
    {
      "type": "message",
      "role": "developer",
      "content": [
        {
          "type": "input_text",
          "text": "User role: {{userRole}}. Always be professional."
        }
      ]
    },
    {
      "type": "message",
      "role": "user",
      "content": "Hello, can you confirm my details?"
    }
  ],
  "structured_inputs": {
    "userName": "Sarah Connor",
    "department": "Engineering",
    "userRole": "Tech Lead"
  },
  "model": "gpt-4o"
}
In SDK code, pass these values by using the same extra_body (Python), body (TypeScript), or AzureCreateResponseOptions (Java/C#) patterns shown in the previous examples. The following Python example shows how to use response-level instructions with structured inputs:
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Pass structured inputs with response-level instructions
response = openai.responses.create(
    model="gpt-5-mini",
    instructions="You are assisting {{customerName}} from {{companyName}} located in {{location}}.",
    input=[
        {
            "type": "message",
            "role": "user",
            "content": "Hello, who am I?",
        }
    ],
    extra_body={
        "structured_inputs": {
            "customerName": "Bob Johnson",
            "companyName": "Tech Corp",
            "location": "San Francisco",
        },
    },
)
print(response.output_text)

Advanced template syntax

Structured inputs support full Handlebars template syntax beyond simple variable substitution. You can use conditionals, loops, and other built-in helpers to create dynamic instruction logic within a single agent definition. The following example creates a weather assistant whose behavior adapts based on runtime inputs. The instructions template uses {{#if}} for conditional sections and {{#each}} to iterate over a list of user preferences:
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, StructuredInputDefinition
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Define instructions with conditionals and loops
instructions = """You are a weather assistant. Provide a helpful weather summary for the user.

The user asked about: {{location}}
Use the following units: {{units}}

{{#if includeForecast}}
Include a brief multi-day forecast in your response.
{{else}}
Focus only on the current conditions.
{{/if}}

{{#if preferences}}
The user has these additional preferences:
{{#each preferences}}
- {{this}}
{{/each}}
{{/if}}

Keep the final answer clear and easy to read."""

agent = project.agents.create_version(
    agent_name="weather-assistant",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions=instructions,
        structured_inputs={
            "location": StructuredInputDefinition(
                description="City or region to check weather for",
                required=True,
                schema={"type": "string"},
            ),
            "units": StructuredInputDefinition(
                description="Temperature units (Celsius or Fahrenheit)",
                default_value="Celsius",
                schema={"type": "string"},
            ),
            "includeForecast": StructuredInputDefinition(
                description="Whether to include a multi-day forecast",
                default_value="false",
                schema={"type": "boolean"},
            ),
            "preferences": StructuredInputDefinition(
                description="Additional user preferences",
                schema={"type": "array"},
            ),
        },
    ),
)

# Supply values at runtime — conditionals and loops resolve automatically
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="What's the weather like?",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {
            "location": "Seattle, WA",
            "units": "Fahrenheit",
            "includeForecast": True,
            "preferences": ["Highlight UV index", "Include wind speed"],
        },
    },
)
print(response.output_text)
With these values, the resolved instructions become:
You are a weather assistant. Provide a helpful weather summary for the user. The user asked about: Seattle, WA Use the following units: Fahrenheit Include a brief multi-day forecast in your response. The user has these additional preferences:
  • Highlight UV index
  • Include wind speed
Keep the final answer clear and easy to read.
The following table summarizes the supported Handlebars helpers:
HelperSyntaxDescription
Conditional{{#if value}}...{{else}}...{{/if}}Render content based on a truthy or falsy value
Negation{{#unless value}}...{{/unless}}Render content when a value is falsy
Loop{{#each array}}{{this}}{{/each}}Iterate over array items
Last item check{{#unless @last}}, {{/unless}}Conditionally render separators between loop items