Skip to main content
Applies to LLM. Some tools should be available on every model call an application makes, whether or not the developer remembered to send them — a lookup against your own knowledge base, an escalation tool, a tool that records a decision. Injecting them at the gateway makes them a platform guarantee instead of a per-client convention. The policy appends its tools to the request’s tool list before the request reaches the model. It only adds; a client’s own tools are never removed. The tool is written once and re-encoded for whichever provider the request is going to, so the same policy serves OpenAI-style and Anthropic requests.
The gateway adds the definition. It does not run the tool. This is what a first-time reader gets wrong, and it is worth getting right before you save anything. See What it does not do.

Configure the policy

Open Policies → Library → Tool Injection. It sits under Tool Governance. This policy has no form of its own: the console builds the panel from the policy’s own definition, so the field names below are the ones you will see, generic wording and all.

Inject Tools

Add Inject appends a card, titled Inject 1, Inject 2 and so on. At least one is required — a policy with an empty list is refused on save. The card does not lay these out as four fields in a row: Type sits on its own, and Name, Description and Parameters are grouped inside a bordered Function panel below it. If you are looking for Name at the top of the card, that is why it is not there.
Parameters cannot be filled in from the console. The generated panel has no editor for a value of that kind: you get the label and its help text, and no input underneath them. A tool created here therefore describes no arguments, and the model calls it with none.If your tool takes arguments, the form cannot give it them — today they can only be set outside the console, so ask whoever manages your gateway. Nothing in the panel says any of this; it simply renders an empty space where the field should be.

On Conflict

A client may already send a tool with the same name. On Conflict decides what happens, and it applies to the tool list as it stands when this policy runs — the client’s tools, whatever an earlier policy in the chain left behind, and the tools this policy has already injected on this request.
Reject abandons the whole injection, not just the colliding tool. The request is refused the moment the first collision is found: tools earlier in your list that had already been placed are discarded with it, and tools later in the list are never reached. There is no partial injection.It also means a duplicate inside your own list is a collision. Two entries named escalate collide with each other — the second one meets the first — and with Reject selected that configuration refuses every request in scope, with no client involvement at all. The policy saves without complaint.
The caller gets 400, and the response names the tool that collided.

Scope

The generated panel renders a Scope select offering Consumer and Global.
This field does nothing. The policy’s effective scope comes from the scope set on the policy itself — Requests from — and not from this select. It is informational, it is part of the schema, and a form generated from the schema has no way to know it should hide it. Leave it alone.

Mode

There is no mode control for this policy, and that is not a rendering fault. Tool Injection supports Enforce only, so the console draws no radio group at all: a one-option choice is not a choice. A policy set to Observe from anywhere else is refused as invalid. The consequence is the one that matters: you cannot dry-run this policy. There is no way to find out what it would do to your traffic without doing it. Attach it to one application first and widen the scope afterwards. Scope works as it does for every policy — Requests from, for applications and groups. See Policies overview.

How the decision is made

1

The request is read into the one shape the gateway works in

Requests arrive in whichever shape the client’s provider uses, and the gateway converts each of them into a single internal shape before any policy looks at it. If the body cannot be read, or it arrives in a shape the gateway does not know how to convert, the policy does nothing at all and the request is forwarded unchanged. See the warning below — this path is silent.
2

Each tool in the list is placed, in order

A name not already present is appended. A name already present is resolved by On Conflict — replaced, dropped, or the whole request rejected with 400.
3

If nothing was appended or replaced, the body is not touched

A list where every tool was dropped by Client Wins changes nothing, so the original body is forwarded byte for byte. The outcomes are still recorded.
4

Otherwise the tool list is written back

Only the fields the tool list actually changed are written back onto the body the client sent, rather than the body being rebuilt from scratch, so fields particular to your provider — the ones that internal shape does not cover — normally survive the round trip.Normally, not always. Two fallback paths rebuild the whole body instead: when the gateway cannot re-encode the request it read, and when it cannot work out which fields the injection changed. The request still goes upstream with your tools on it, but on either of those paths anything the internal shape does not model is gone from it.
The decision records what happened to each injected tool on each request: appended, replaced, dropped or skipped. That per-tool record is the only way to see a Client Wins drop, which is otherwise invisible — the request succeeds and your tool simply was not there.
Chat Completions requests to gpt-6.1-sol and gpt-6-astra are forwarded with nothing injected. Those models reject function tools on Chat Completions, so the request goes upstream unchanged, the decision is skipped, and each configured tool is recorded as skipped. Matching includes a vendor prefix (openai/gpt-6.1-sol), an ft: fine-tune (ft:gpt-6.1-sol:org::id), a dated snapshot (gpt-6.1-sol-2026-10-01, gpt-6-astra-2026-08-01), and a body that names no model when the binding default is one of those two. A model named on the body is the one that is checked. Other models are unchanged. Use the Responses API to have the tools injected on gpt-6.1-sol and gpt-6-astra: a Responses request to those models still receives them.Function tools the client sends itself on Chat Completions for these models are answered with 400: invalid_request_error, param tools, code unsupported_value. The message points at the Responses API.
A rejected request is the exception, and it follows from there being no partial injection: nothing was placed, so there is no per-tool outcome to record. What is kept is the rejection itself and the name of the tool that collided, and nothing else.

Modes and failures

Enforce is the only mode, so there is one column.
When the policy cannot read the request, it fails open and silently. A body it cannot read, or one that arrives in a shape it cannot convert, produces no injection, no rejection and no event of any kind. The request reaches the model exactly as the client sent it, carrying only the client’s own tools, and there is nothing in Activity to count.For a governance control that is the wrong direction, and no setting changes it. If a tool must be present on every call, assert its presence somewhere you can alarm on rather than reading a quiet request as an injected one.

Limits

  • It cannot be dry-run. Enforce is the only supported mode, so there is no way to watch what the policy would do before it does it.
  • It adds; it never removes or narrows. There is no way to take a tool away with this policy. See Applications for that.
  • It does not run anything. See below.
  • Parameters cannot be set from the console. A tool created here describes no arguments, so the model calls it with none.
  • Function tools only. Any other tool type is refused on save.
  • Request only. There is no response leg and no leg to choose: the tools are added on the way to the model, and nothing is inspected on the way back.
  • It fails open and silently on a request it cannot read. See the warning above.
  • Provider-specific fields usually survive, but not always. Two fallback paths rebuild the body from scratch and drop whatever the gateway’s internal shape does not model. See the last step above.
  • LLM traffic only. The policy does not apply to MCP (Model Context Protocol) tool calls. A tool served by an MCP server is governed on the MCP side, not here.

What it does not do

The gateway adds the definition; it does not run the tool. When the model decides to call an injected tool, the call comes back to the application like any other tool call, and the application has to execute it — itself, or through an MCP server that serves it. Inject only tools your applications know how to handle. A client that receives a tool call it has never heard of does one of two things, neither of them good: it fails, or it returns nothing and lets the model improvise. Injecting a tool into an application that does not implement it does not extend the application; it breaks it. It is not an access control. Which tools an application may call is set on the application; this policy adds to that set for the model’s benefit, it does not narrow it. Reaching for Tool Injection to stop a tool being used is reaching for the wrong policy: it has no mechanism that can refuse anything except a name collision.

Verify the policy

Open the Playground, pick an application the policy applies to, and send these in this order. Starting with the control means a failure tells you something specific.
1

Control — the path works at all

Expect a normal reply. If this fails, the problem is the application, the model or the provider — not the policy. Fix it before going on.
2

The tool was injected — the model knows about it

Your injected tool must be in the answer, with the Description you wrote. The model’s own account is not proof on its own — models invent tool lists — so confirm it against the event, which records the tool by name with the outcome appended.
3

The model will actually call it

Ask for something only the injected tool can do, phrased the way a real user would.Expect a tool call to come back to the client. This is where most first attempts fail, and the cause is almost always the description: a tool the model does not understand is a tool the model does not call. Rewrite the Description for the model rather than for a reviewer.
4

A collision behaves the way you chose

This is the one check the Playground cannot make. A collision only happens when the caller declares a tool of its own, and the Playground sends none — it sends your prompt and nothing else. So this last check has to come from whatever already calls this gateway: an application that declares a tool with the same Name as one of yours. Arranging that request is a job for whoever builds the application, and this page does not cover it.What to read on the event when such a request does arrive: with Gateway Wins, replaced, and your Description surviving; with Client Wins, dropped, and the client’s surviving; with Reject, a 400 and the model never reached.Worth arranging even if you expect no collisions. A duplicate name inside your own list collides the same way, and that one you can catch without any traffic at all — read your list before you save it.
Every decision lands on the request itself. Open Activity, open the request, and read its Policies tab — the Tool Injection row is there with the decision it reached. The event schema lists the full set of fields a decision records, the per-tool outcomes included.

Troubleshooting