A Company Card for Your Agents: Cost, Access and Observability with an AI Gateway
A coding agent estimated that a run cost $0.044. The model was free.
That contradiction points at a bigger problem. A software factory runs many AI agents on tickets, and each brings its own credentials, its own way of calling models and tools, and its own report of what happened. You lose control over what they may do and visibility into what they did.
A gateway is meant to fix that. It sits between the agents and everything they call, and routes each request while it applies access rules, limits and logging. Think of it as a company card for each agent: a spending limit, a list of what it may use, and a statement of every charge. How much does it actually give you? We ran three coding agents through four gateways to find out.
Why agents need a control and observability layer
A coding agent works in a loop: it asks a model what to do, runs a command or calls a tool, and feeds the result back. Each step can cost money or have side effects. Agents need the same foundations as any application, such as access control, logging and cost attribution, but they decide for themselves which models and tools to use.
An LLM gateway sits between agents and model providers, and an MCP gateway does the same for tools. MCP, the Model Context Protocol, is a standard way for agents to reach tools such as Jira. OpenTelemetry (OTel) is a standard way to collect telemetry, and its protocol, OTLP, carries that data between systems.
Think of this layer as a front door. Agents hold a limited key, the gateway holds the real credentials, and every request passes through one place that can apply rules and record what happened. That door has three jobs, and this post follows them:
Control what agents can access
Understand what agents are doing
Decide where agent data goes
Conceptual architecture, not the exact setup of every test.
Inside the experiment
We recorded 61 runs, nine of them ending in an error, some on purpose in budget and model-block tests. Nearly all used one small task: read a file and explain a behaviour, which kept the workload comparable.
Agents: Claude Code 2.1.318, Codex 0.164.0, OpenCode 2.2.1
Gateways: Bifrost 2.4.0 and agentgateway 1.7.0 in Docker, Cloudflare AI Gateway, Vercel AI Gateway
Models: Claude Haiku 5.5, GPT-6 Luna, free Nemotron through Vercel, Mistral Small and Qwen on Scaleway
Tools: MCP tests used a fake Jira server, with a scripted client and one Claude Code run
Telemetry: OTel Collector into Langfuse Cloud
Scope: a small sample, and not every agent ran on every gateway. We tested the control layer, not model output, and four of many gateways. Others, such as LiteLLM, Portkey and Kong, may behave differently.
Four gateways, seven real-world requirements
A gateway earns its place when something changes, so we compared the changes a platform team actually makes.
Change you need to make
Bifrost
agentgateway
Cloudflare
Vercel
Add Claude Code or Codex
Works
Works
Works
Paid credits only
Trust the cost
Exact on Claude
Exact on Claude
Verify first
Verify first
Cap a team's spend
Stops with 402, can overshoot
Stops with 429, can overshoot
Docs: best-effort limits by model, provider or metadata
Docs: budgets per team, project, key or member
Restrict a key's models
Blocked with 400, unclear error
Blocked with 403, clear error
Not found
Docs: team-level allowlist only
Swap to an open-weight model
Works
Works
Partly, agent failed on call 2
Works
Control one MCP tool
Hidden and refused
Hidden and refused
Docs: MCP portals can turn off single tools
Docs: not in AI Gateway
Self-host it
Yes
Yes
No
No
Cells starting with "Docs:" come from vendor documentation, which we did not run. "Not found" means we found nothing there. Every other cell is a result from our runs or a product fact.
Putting limits on what agents can do
A budget is a stop, not a ceiling
The gateways we tested checked recorded spend before a call and charged it afterwards, so the call that crossed the limit still ran. Cloudflare's and Vercel's docs describe the same pattern, which we did not test. A gateway could instead reserve the worst case up front, since input tokens are known and max_tokens caps the output, then release the rest, like a card hold. The price is caution: a key near its limit may refuse calls it could have afforded.
Final spend against a deliberately tiny test limit. The overshoot was one call.
A software factory makes this worse, because it runs many agents at once and all of them pass the check before any finishes. We did not run that case, but Cloudflare's docs describe it, and a reservation would close it too.
A factory also needs budgets in layers:
Cap per
What it limits
Why
Agent run
One ticket's work
One stuck ticket cannot drain the rest
Project
All runs for one project
Keeps each project inside its share
Organization
All agent spend
A hard ceiling on the total
A gateway can enforce these only if every request says which run and project it belongs to, for example through a separate key or metadata per run.
Test your own clients before you rely on a budget. They react differently to a refusal:
Claude Code stopped at once on both gateways.
Codex retried Bifrost's 402 five times in about seven seconds, then gave up.
Codex stalled on agentgateway's 429 until our five-minute timeout, in both of two runs.
From model access to tool access: MCP gateways
Agents also act on external systems through tools, and that is a separate security concern: a bad model call wastes money, a bad tool call can delete a project. An MCP gateway extends the front door to tools. The agent holds a limited key, the gateway decides which tools that key can see and call, and the real tool credential stays at the gateway.
To test it, we gave two keys different rights on a fake Jira server behind each gateway. The server rejects any call without its own token, and the client never holds it.
One tool, two keys. The dev key never sees the delete tool, and a direct call to it is refused.
Below is the real output through Bifrost, trimmed. The same test through agentgateway ended the same way.
$ npm run mcp -- bifrost
no key: 401
dev
tools visible: fake_jira-jira_create_issue, fake_jira-jira_search_issues
search: ALLOWED: jira_search_issues ran on fake Jira
direct delete: REFUSED (200): Tool execution failed: MCP tool
'fake_jira-jira_delete_project' is not allowed for virtual key
admin
tools visible: fake_jira-jira_create_issue, fake_jira-jira_delete_project,
fake_jira-jira_search_issues
direct delete: ALLOWED: jira_delete_project ran on fake Jira
What the run shows:
The tool is hidden. The dev key never sees the delete tool.
A direct call is refused. In REFUSED (200), the HTTP request succeeded, and the gateway rejected the tool call inside the MCP response.
Credentials stay at the gateway. The client never holds the Jira token.
A real agent sees the same. Claude Code on the dev key, through agentgateway, could not see the delete tool and said so.
If you self-host, keep the admin port private. In our setup one gateway's admin interface answered without authentication, and its configuration listed the keys the agents use.
Can you trust the numbers?
Budgets only help if you know what agents did and the numbers are right. Gateways show the same traffic differently: some lead with tokens and cost, and one stored the request content.
agentgateway: tokens, cache share and cost per call. Cache share appears when the provider reports cached tokens, and cost only where the gateway knows the model's price. Prompts stayed empty in our setup.Bifrost: calling app and stored message text, which needs a retention decision.Vercel: the free model at $0, as expected. The top row is GPT, refused on the free tier.Cloudflare: failed calls sit next to successful ones, with no tokens and no cost.
Check who is reporting the cost
Source
What it reported
Verdict
Claude Code on Claude
Matched both self-hosted gateways to the last digit
Accurate
Claude Code on free Nemotron
Estimated $0.044 to $0.084 per run, against a $0 price on Vercel
Wrong price
Codex
Token counts, but no dollar figure in any signal we captured
Calculate it yourself
A hosted gateway on Claude
About 4.7× the price the other sources applied, on mostly cached runs. Fits cache reads billed near the full input price
Differed
Bifrost, agentgateway
Per-call cost including cache. Exact on Claude, and close to each other on GPT
Accurate
Three numbers are easy to confuse, and they need not match:
Agent-reported. Claude Code estimates at list price. Codex reports only tokens.
Gateway-calculated. Tokens times the gateway's own price table.
The invoice. What you actually pay. Check the others against it before you build dashboards. We did not.
What we saw:
Claude Code priced a free model. All three runs we checked match $5 input, $25 output and $0.50 cache read per million, likely a default rate for unknown models. Administrators can set rates with modelPricing, which we did not test.
The hosted gateway likely missed the cache discount. Pricing cached tokens as full input explains about 3.9× of its 4.7× gap.
Codex gives no dollars. A gateway can price every call, which makes it a natural cost source for a mixed fleet.
Field names mislead. Anthropic's input_tokens leaves out cache reads: one call showed 2 in Claude Code and 17,268 at the gateway. Normalize fields before you mix sources.
Cache belongs to the provider, and clients decide whether you hit it
Agents resend long prompts on every call, and providers charge much less for input they have seen recently. That cache lives at Anthropic or OpenAI, not in the gateway: Bifrost and Cloudflare, using one key, shared it seconds apart. Both misses we saw came from the client.
Claude Code changes its request with the base URL. Moving from direct to a gateway gave a cold first call. A proxy that forwards requests untouched went cold too, on the same key, so the request changed on the client side, not in the gateway.
In our tests, Codex started every session cold. It sends a new prompt_cache_key per session, a request field that OpenAI's prompt caching docs use to group requests for caching. When our proxy pinned that key to one value, the next two runs read 10,594 tokens on their first call.
In our tests, only the first call of a session missed. A cold first call cost about $0.002 more on Claude Haiku 5.5 and $0.0012 more on GPT-6 Luna, likely a small share of a long ticket.
Following one ticket, not one call
Gateway telemetry is per call, but a factory needs answers per ticket: what a run cost and which project it was for. Give every call a correlation ID, such as run, ticket and project, and pass the trace context from agent to gateway. In our lab a run ID and traceparent were enough to show one run as a single trace.
Your gateway doesn't determine where your data lives
EU data residency is set hop by hop
The third job is knowing where data goes. Prompts can contain source code and customer data, so many teams must keep them inside a region, which is called data residency. A request can pass through several services, and each may process or store part of it. A gateway in Frankfurt does not keep prompts in Europe: the gateway, the model host, the telemetry collector and any observability backend that receives prompt text all count.
Keep prompts out of telemetry. Make sure spans do not carry full prompts and responses. In our setup one gateway exported them by default, and tool arguments still slipped past our filter, so filter on an allowlist.
A hosted gateway adds a hop. Filtering prompts before export takes the backend off the path, but a collector that does the filtering still sees them.
The model host is usually the deciding hop, and options differ by vendor. This table reflects vendor documentation as we checked it on 5 November 2026. Regional options change, so check them again before you rely on one.
A gateway makes switching easy. We added two Scaleway models to agentgateway as aliases, and OpenCode finished the task on both with no change. That shows the route works, not where the model ran.
The agent names an alias, and the gateway decides where it goes.
Which gateway fits your architecture?
Start from your requirements. These apply even if you pick none of the products we tested:
Requirement
What to prioritize
Centralized credentials
Virtual keys, with provider credentials held at the gateway
Fine-grained model access
Per-key model lists, or rules on role
MCP security
Per-tool authorization enforced by the gateway
Cost management
Per-call cost that counts cache, and budgets you understand
Observability
OTLP support, trace propagation and configurable filtering
Data residency
Control over every service that processes or stores prompts
Infrastructure independence
Self-hosting and configurable routing
Treat the gateway as infrastructure
A software factory runs many agents on tickets nobody watches live. A gateway gives you one place to control what they access, see what each run cost and decide where their data goes. In our tests it did not guarantee accurate cost, firm budgets, clean telemetry or data residency on its own, so verify those. The agent ecosystem will keep changing. Your front door shouldn't have to change with it.
A coding agent can turn a ticket into a green pull request in minutes. We split the merge decision into narrow checks, let fixed rules decide, set the strictness by the blast radius of a change, and bring in a person only where the agent gets stuck.
We compared a stronger model, a different agent, answers from the author and a read-only investigation before any code. On 19 fresh tickets, the investigation went ahead on 9 of 10 wanted changes and held back 7 of 9 requests an author had already declined.
We ran OpenSpec, Spec Kit, Superpowers and Claude Code plan mode on a real ticket, then planted drift and contradictions. For one feature we couldn't separate the code, and plan mode cost about half. What differs most is the record each leaves for the next agent.
We use cookies to run the site and understand how it’s used. You can accept all cookies or reject non-essential ones. See our Cookie Policy.
Cookie settings
By clicking 'Accept all cookies', you agree to storing cookies on your device to enhance site navigation, analyze site usage and assist in our marketing efforts as outlined in our cookie policy.