> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Tool template variables

> Which values resolve in runtime tool URL, header, and body templates, and which do not

Runtime tool configurations accept `{{...}}` templates in their URL, headers, and body. This page lists the values a tool template can read, the fields that support them, and what happens when a template does not resolve.

## Values a tool template can read

A tool template resolves against the tool call's arguments and the managed secret store. It does not read execution variables directly.

| Template              | Resolves from                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| `{{paramName}}`       | The argument the model sent for `paramName`                                                     |
| `{{paramName.field}}` | A field inside an object-valued argument                                                        |
| `{{secret:NAME}}`     | The managed secret named `NAME`                                                                 |
| `{{hiddenName}}`      | A parameter listed in `hiddenParameterNames`, filled from the execution variable with that name |
| `{{_tenant.id}}`      | The execution's tenant, filled by Runtype. The model cannot set it                              |
| `{{_endUser.id}}`     | The execution's end user, filled by Runtype. The model cannot set it                            |
| `{{_identity.token}}` | A Runtype-signed identity assertion, minted for each tool call                                  |

A hidden name without a leading `_` falls back to the model when no execution variable matches it, so use it only for values the model may also set. A hidden name with a leading `_` never falls back. For the lookup order, see [Hide parameters from the model](/developer-guides/guides/runtime-tools#hide-parameters-from-the-model).

Runtype resolves `{{secret:NAME}}` references first, then fills the remaining templates from the arguments. Hidden parameters are merged into the arguments before that second pass, so a hidden parameter resolves exactly like an argument the model sent.

## Values a tool template cannot read

Execution variables such as `{{_record.field}}`, `{{_flow.id}}`, `{{_user.id}}`, `{{_execution.id}}`, and flow step outputs do not resolve inside a tool's `url`, `headers`, `body`, or `authHeader`. Runtype sends an unresolved template as literal text, so a header written as `X-User-Id: {{_user.id}}` reaches your API as the string `{{_user.id}}`.

To pass an execution variable to a tool, use one of these options:

* **Hidden parameter.** Add the variable's name to `hiddenParameterNames`. Runtype fills it from the execution variable and removes it from the schema the model sees. See [Hide parameters from the model](/developer-guides/guides/runtime-tools#hide-parameters-from-the-model).
* **Flow tool call step.** In a flow, the parameters of a tool call step are flow templates, so `{{_record.metadata.orderId}}` or a previous step's output resolves there before the tool runs.
* **Model argument.** Put the value in the prompt and let the model pass it as an argument. Use this only for values the model is allowed to change.

> **Warning**
>
> Do not use a model argument for identity or authorization. The model can send any value it
> chooses. Use `_tenant`, `_endUser`, or `_identity.token` for identity, and authenticate Runtype to
> your backend with a managed secret in a header.

## Fields that support templates

The following table lists the template-capable fields for each runtime tool type:

| Tool type                | Field                   | Arguments and hidden parameters | `{{secret:NAME}}` |
| ------------------------ | ----------------------- | ------------------------------- | ----------------- |
| HTTP (`external`)        | `url`                   | Yes                             | Yes               |
| HTTP (`external`)        | `headers`               | Yes                             | Yes               |
| HTTP (`external`)        | `body`                  | Yes                             | Yes               |
| Inline MCP (`mcp`)       | `authHeader`, `headers` | Yes                             | Yes               |
| Inline MCP (`mcp`)       | `url`                   | No                              | Yes               |
| A2A (`a2a`)              | `authHeader`            | Yes                             | Yes               |
| A2A (`a2a`)              | `endpoint`              | No                              | Yes               |
| Agent `tools.mcpServers` | `auth.headers`          | Yes                             | Yes               |
| Saved MCP server         | `auth`                  | No                              | Yes               |

A saved HTTP tool, attached by tool ID, templates its `url`, `headers`, and `body` the same way, including `{{_tenant.id}}` and `{{_endUser.id}}`. It does not support `{{_identity.token}}` yet.

A saved MCP server is one you register with `POST /v1/mcp/servers` and attach by tool ID. It sends the authentication you configured on the server, with no per-execution templating, so it cannot carry the caller's identity. To send identity to an MCP server, define the server in the agent's `tools.mcpServers` or as an inline `mcp` runtime tool.

## How templates resolve

* **Missing values.** A template whose value is `undefined` stays in the output as literal text. A `null` value also stays literal in the URL and headers.
* **Body values.** In `body`, Runtype inserts each value as JSON, including the quotes around strings. Write `{"status": {{status}}}`, not `{"status": "{{status}}"}`. A `null` value becomes `null`.
* **Objects.** In the URL and headers, an object or array value is inserted as a JSON string.
* **Fallbacks.** `{{a || b}}` uses the first truthy operand, `{{a ?? b}}` uses the first operand that is not `null` or `undefined`, and `{{a|default}}` uses `default` when `a` is missing. Operands can be argument paths or literals such as `"none"`, `0`, `true`, and `null`.
* **Unused arguments.** For a `GET` request, arguments the URL does not reference are added to the query string. For other methods without a `body`, those arguments are sent as the JSON body. Hidden parameters are excluded from both, so a hidden value reaches the request only where you template it.

## Identity in templates

`_tenant` and `_endUser` are set by Runtype from the execution's end-user identity. They follow stricter rules than other names:

* **HTTP tools.** A `{{_tenant...}}` or `{{_endUser...}}` template, or a `parametersSchema` property with either name, makes that name hidden even if you don't list it in `hiddenParameterNames`. This applies to runtime tools, saved tools, and saved tools that a flow `tool-call` step calls. Runtype removes the name from the schema the model sees, fills it only from the execution, and ignores any value the model sends.
* **MCP servers.** In an agent's `tools.mcpServers` entry or an inline `mcp` runtime tool, a `_tenant` or `_endUser` reference in a header gets the same treatment. Runtype also leaves identity headers out of tool discovery requests.
* **Missing identity.** If the execution has no value for a referenced name, Runtype doesn't call the tool and returns an error to the model. The exception is a name used only before a fallback, such as `{{_endUser.id ?? 'guest'}}`. Runtype then calls the tool and the fallback renders.
* **Nested flows.** A flow that runs as a tool gets `_tenant` and `_endUser` from the execution that called it, never from the tool arguments.

A plain `_tenant` or `_endUser` value tells your API who the caller is, but your API must trust the request that carries it. To let your API verify the identity itself, reference `{{_identity.token}}` in an HTTP tool's URL, headers, or body, or in an MCP server header. Runtype signs a short-lived JWT for the tool's host on each call. The tool's URL must use `https` and a fixed host, and the saved agent must have a tenancy strategy. For the claims and how to verify them, see [Send a verifiable identity assertion to your API](/developer-guides/guides/end-user-identity#send-a-verifiable-identity-assertion-to-your-api).

The following agent `tools.mcpServers` entry forwards the verified tenant to a remote MCP server:

**`Identity header on an MCP server`**

```json title="Identity header on an MCP server"
{
  "id": "catalog",
  "name": "Buyer catalog",
  "url": "https://mcp.example.com/mcp",
  "auth": {
    "type": "headers",
    "headers": {
      "Authorization": "Bearer {{secret:CATALOG_MCP_TOKEN}}",
      "X-Buyer-Org": "{{_tenant.id}}"
    }
  }
}
```

Replace `CATALOG_MCP_TOKEN` with the name of the managed secret that authenticates Runtype to the MCP server. Your MCP server must still check that the organization in `X-Buyer-Org` may read the data it returns.

## Next steps

* [Runtime tools](/developer-guides/guides/runtime-tools): define HTTP, MCP, and A2A tools per request
* [End-user identity and credentials](/developer-guides/guides/end-user-identity): how Runtype sets `_tenant` and `_endUser`
* [Identity Exchange with Clerk Organizations](/developer-guides/guides/identity-exchange-clerk): admit a verified Clerk user and organization
* [Tenancy strategies](/developer-guides/guides/tenancy-strategies): choose what Runtype isolates per tenant or end user