Skip to main content
Variables let an agent reference a value by name in a tool input, like {{city}} or {{env.API_KEY}}, and have Scout substitute the real value when the tool runs. The agent decides what to call and which values to pass. Scout decides how those names resolve. This keeps sensitive values like credentials, tokens, and tenant IDs out of the model’s context while still letting the agent use them in tool calls.

What Variables Are

A variable is a placeholder written in double curly braces that an agent can put anywhere in a tool’s input:
{
  "query": "latest weather in {{city}}"
}
When the agent calls the tool, Scout replaces {{city}} with the actual value before the tool receives it. The tool sees the resolved value, and the model never has to hold it. Values can come from two places:
  • Interaction variables are values you supply when you start an interaction, scoped to that interaction.
  • Environment variables are organization-wide values stored in Scout Settings, useful for shared credentials and configuration.

Why Use Variables

Without variables, an agent has two poor options when a tool call needs a runtime value. It can copy the value into the prompt, which puts secrets into model-visible context, or it can go without, which prevents valid tool calls. Variables separate the two responsibilities:
  • You provide values at interaction time or store them in your organization.
  • The agent references them symbolically by name.
  • Scout resolves the real value only when the tool executes.
An agent can then pass a per-request token to a tool, or route a call to the right tenant, without exposing those values to the model.

When Values Are Resolved

Variables are resolved at tool execution time, the moment before a tool runs, not when the prompt is rendered. A placeholder stays symbolic throughout the agent’s reasoning and is substituted only as the tool is invoked.
Variables apply to tool inputs only. They are not interpolated into prompts, messages, or model context.

Syntax

Scout supports three forms:
SyntaxResolves from
{{NAME}}Interaction variables first, then environment variables
{{local.path.to.value}}Interaction variables only
{{env.NAME}}Environment variables only
Use a bare name when you just want the value and don’t care where it comes from. Use local. or env. when you want to force a specific source.

Resolution Rules

Lookup behavior is deterministic, so the same placeholder always resolves the same way:
  • {{NAME}} resolves from interaction variables first, then falls back to environment variables.
  • {{local.*}} resolves only from interaction variables.
  • {{env.*}} resolves only from environment variables.
  • {{customer.email}}, a bare dotted path, resolves through interaction variables only.
  • Missing values resolve to an empty string.
Reach for {{env.NAME}} when the value is a shared organization secret, and a bare {{NAME}} when it’s supplied fresh with each interaction. Being explicit avoids surprises when the same name exists in more than one place.

Type Behavior

How a resolved value is typed depends on where the placeholder sits:
  • Whole-field placeholder: when a placeholder is the entire field value, the resolved value keeps its native type (object, array, number, boolean).
  • Embedded placeholder: when a placeholder sits inside a larger string, the resolved value is converted to a string.
For example, {{customer}} on its own can resolve to a full object, while "Bearer {{token}}" always resolves to a string.

Security Model

Variables are built so sensitive values stay out of the model’s context:
  • Values are resolved at tool execution time, not baked into the prompt.
  • Resolved values are not automatically exposed to the model. They only become visible if a downstream tool explicitly returns them in its output.
An agent can pass a secret to a tool without being able to read that secret itself.

Examples

Interaction-Scoped Variable

Supply a variable when you start the interaction, then reference it by name in the message. The agent uses {{city}} in the search tool’s input, and Scout resolves it at execution time. Here $AGENT is your agent ID and $SECRET is a Scout API key.
curl --request POST \
  --url "https://api.scoutos.com/world/$AGENT/_interact" \
  --header "Authorization: Bearer $SECRET" \
  --header 'content-type: application/json' \
  --data '{
    "variables": {
      "city": "Charleston, SC"
    },
    "messages": [
      {
        "content": [
          "Search the web for latest weather in {{city}}. Only search once. Compact the results"
        ]
      }
    ]
  }'

Nested Interaction Variables

Variables can be objects, and you can reference nested values with a dotted path.
curl --request POST \
  --url "https://api.scoutos.com/world/$AGENT/_interact" \
  --header "Authorization: Bearer $SECRET" \
  --header 'content-type: application/json' \
  --data '{
    "variables": {
      "location": {
        "city": "Charleston",
        "state": "SC"
      }
    },
    "messages": [
      {
        "content": [
          "Search the web for latest weather in {{location.city}}, {{location.state}}. Only search once. Compact the results"
        ]
      }
    ]
  }'

What the Agent Emits vs. What the Tool Receives

The agent emits tool input with placeholders still in place. Scout resolves them just before the tool runs, and the tool receives only the final values.
{
  "query": "latest weather in {{city}}",
  "headers": {
    "Authorization": "Bearer {{env.API_KEY}}",
    "X-Tenant": "{{tenant.id}}"
  }
}
{
  "query": "latest weather in Charleston, SC",
  "headers": {
    "Authorization": "Bearer sk-prod-123",
    "X-Tenant": "tenant_42"
  }
}

Native-Type Preservation

Because {{customer}} is the whole field, it resolves to the full object. Because {{customer.email}} is also a whole field, it resolves to the string at that path.
{
  "customer": "{{customer}}",
  "customer_email": "{{customer.email}}"
}
{
  "customer": {
    "email": "a@example.com",
    "name": "Scout Customer"
  },
  "customer_email": "a@example.com"
}

MCP Per-Call Headers

MCP-backed tools accept a reserved headers input that lets an agent supply request headers for a single tool call. These headers are merged over the MCP connection’s base auth headers and are not forwarded as normal tool arguments. They only shape the outbound request. Combined with variables, header values can carry per-request credentials or routing context to an MCP server without exposing those values to the model:
{
  "headers": {
    "Authorization": "Bearer {{env.API_KEY}}",
    "X-Tenant": "{{tenant.id}}"
  }
}
Here the bearer token comes from an organization environment variable, and the tenant ID comes from an interaction variable. Both are resolved at execution time, and sensitive header values are sanitized in tracing rather than logged raw.
Use per-call headers for values that vary by request, such as a request-scoped token or a tenant, workspace, or routing header. For a connection’s standing credentials, configure them on the MCP Server itself.

Next Steps

Agents Overview

See how agents pick tools and run the core agent loop.

MCP Server

Connect MCP-compatible tools and configure base transport headers.

Observability

Inspect tool inputs and outputs, with resolved values, in the Logs view.

Async Interactions

Start interactions programmatically and pass variables in the request.