Site
All posts

Published Sep 22, 202620 min read

AI Agents Are the New Consumers: Why Vinkius Is the Secure Runtime for Agent Workflows

How AI agents became the first stochastic consumers of a cloud platform, and why Vinkius built a V8 isolate runtime, a twelve-surface governance control plane, and the MCP Fusion MVA architecture as the secure operating system they cannot skip.

Renato Marinho

By Renato Marinho

Founder · Vinkius

The Vinkius runtime stack for AI agents: the agent fleet on the left consuming MCP tools through the gateway, backed by V8 isolate sandboxing, the twelve-surface governance control plane, and a SHA-256 hash-chained audit ledger

I have been living inside agent workflows for six months now. Not watching demos on slides. Living it. Watching agents book meetings, write code, query databases, move money, open tickets, and forget the ticket number by the next call. And what I learned is simple: agents are not more capable models. They are actors that execute writes to the world through tools, and the question is no longer whether an agent can plan a task. The question is whether the infrastructure that hosts those tools can survive the moment the agent decides to act.

This is the post where I explain how Vinkius became the operating system for AI agents, and why the gap between an agent on a demo and an agent you would hand production credentials is not a model problem. It is an infrastructure problem. And the answer lives in the architecture we built for MCP Fusion.

The agent is not a user. It is a new class of consumer.

Every SaaS platform in the last twenty years was built for one kind of caller: a human behind a browser, or a service account behind a known script. Both of those callers behave like the inside of a system. They do what they are told. They fail fast when the schema breaks. They do not retry a call that returned an error four times, because they do not forget that error from three turns ago. They do not lose track of which tools exist after a handoff to a specialist. They do not swallow a two hundred kilobyte response into context and then summarize a row that does not exist, because truncation is invisible to them.

An AI agent is none of those things. An agent is stochastic by construction. It will send "INV-999" as an invoice ID even when it just listed the invoices and saw three of them. It will retry a call that returned a 404 with the same input, because it does not remember that 404 from three turns ago. It will lose track of which tools exist after a handoff to a specialist. It will loop on a broken tool until the token budget collapses.

And then it will call your production database. Your payment API. Your CI pipeline.

The agents are already acting. They are acting on CRM records, on invoices, on infrastructure state. The question is not whether they will act. The question is whether the surface they act on is built for a non-deterministic principal that cannot read a schema and cannot remember a conversation.

Why MCP Fusion is not just another MCP server

MCP solved the discovery problem that kept every LLM integration stuck in brittle prompt chains. But vanilla MCP servers inherit every problem of the raw server model, and those problems become catastrophic when the consumer is an agent rather than a human. A raw server leaks whatever it returns, because its output is the row, serialized. A raw server enforces nothing, because its middleware is a convention, not a guarantee. A raw server cannot see its own drift, because it has no mechanism for detecting that the surface it exposes today differs from what it exposed yesterday. A raw server answers errors with strings, and the agent retries with the same string.

MCP Fusion fixes this with an architecture called MVA, and the name is the point. The split is not arbitrary. It is the split that application code already knows, but pointed at a new consumer.

The Model owns what the data is and what may leave the process. It declares fields, types, and descriptions. Those descriptions are not documentation for a human. They compile, just in time, into the interpretation rules the agent receives with each response. The model declares hidden fields, password hashes, internal flags, tenant markers, and they never cross the boundary. A new database column does not leak to an agent until someone puts it in the model. A raw server has no such property.

The Presenter owns what the agent perceives about the data. Before anything is serialized, the presenter runs its schema over the raw result in strip mode. Whatever the database returned, the agent sees only the declared surface. This is egress control at RAM level, not a view layer, not a template, not a convention. A field the schema does not know cannot cross. The presenter also attaches system rules, working limits, and affordances. suggestActions tells the agent what it can do next with what it just saw. This is HATEOAS for agents. The response is not a payload. It is a position in a workflow. Server-rendered chart blocks are deterministic: the framework renders them, the agent reads them, and no model in the loop generates the pixels.

The Tools own the verbs. f.query is read-only by default. f.mutation is destructive by default. f.action is neutral. Those are not metadata labels. They drive what the platform treats as safe to retry, what the observability pipeline marks, and what a governance tool flags when a read turns into a write.

One rule keeps the separation honest, and it is a security property, not a style rule. Direction. Tools import presenters, presenters import models, models import the core, and nothing imports backwards. The layer that touches your data must never be the layer an agent can steer.

This is the architecture that every connector deployed on Vinkius Cloud is built on, and it is why the runtime does not need to trust the code it runs.

The V8 isolate layer: where customer code meets platform control

Every MCP server a customer ships on Vinkius Cloud is, sooner or later, third-party code executing on our infrastructure. Not ours. Not a library we control. Theirs. A cloud for AI agents is only useful if customers can bring their own logic, their own connectors, their own glue between an LLM and their systems. Once that capability exists, the question becomes: how do you run untrusted JavaScript for thousands of tenants on a small number of servers without giving any one of them a path to hurt the others, the machine, or their neighbors?

The answer is a V8 isolate per tenant, built on Node.js with isolated-vm, the C++ binding that lets a Node process own a raw V8 isolate. Not a container per tenant. Not a process per tenant. An isolate. A heap with its own garbage collector, its own global scope, and a hard memory cap of 128 MB that the engine enforces, not the application. When a tenant's heap hits it, that tenant's isolate stops being served. The other tenants keep running. No tenant's globalThis is reachable from another tenant's isolate, because there is no shared JavaScript boundary at all.

The boot is split into two phases, and only the first one is visible to cold-start metrics. Phase one: the V8 binary and the polyfill layer initialize, which takes 50 to 100 milliseconds on first contact with a deploy. Phase two: the tenant's bundle is loaded, wrapped, and executed inside the isolate, which happens on every request because the snapshot cannot capture async state. The platform snapshots the environment, not the program. The polyfill layer is static for a given deploy. What changes per request is the tenant code. The host runs the snapshot builder over the provisioned environment and caches the resulting heap blob on disk, keyed by deploy ID and stamped with the V8 version. On restore, a fresh isolate is created from that blob in 15 to 25 milliseconds total. The bundle re-executes, because isolate creation from a snapshot cannot handle async top-level await, but the polyfill work happens exactly once per deploy.

The V8 version matters. V8 isolates are not forward-compatible across major engine versions. A snapshot built on V8 version N cannot be loaded by V8 version N+1. The host stamps the snapshot blob with the engine version and refuses to load a blob whose stamp does not match the running version. A mismatch is a cache miss, not a crash.

The isolation is not just memory. The empty environment that the V8 isolate gives you has no fetch, no crypto, no timers, no process. Nothing that touches the outside world exists inside the isolate. Fetch in a tenant bundle is a polyfill on the guest side, but the actual request happens host-side, through the host bridge, as a binary-safe ArrayBuffer copy across the boundary. Crypto.subtle.digest and HMAC, the ones JWT verification needs, are host-side too, and the host verifies signatures with a constant-time comparison. Timers are host-side setTimeout calls that invoke back into the guest through a registered invoker, capped at five seconds at the framework level and thirty seconds at the dispatch level. The rule is simple. The polyfill makes the call look native. The host owns the effect. A tenant can express intent. It cannot reach the operating system.

This is the design I wrote about in detail in the V8 isolates post. The five-second budget is the per-isolate execution ceiling. The thirty-second budget is the dispatch ceiling. The ten-megabyte response cap is the egress ceiling. All three are named policies in the runtime config, not magic numbers, and all three are documented next to the constant that defines them.

The SSRF guard: outbound traffic as a policy, not a default

The most dangerous thing a tenant bundle can do is make an HTTP request. Fetch is a universal source of SSRF. A careless or malicious bundle pointing a tool at the AWS metadata service, at 169.254.169.254, hands a customer's AI agent a read path into the instance's credentials.

All outbound traffic goes through the SSRF guard. The guard works on one principle. An address is only valid for as long as the policy that approved it. The guard resolves DNS before the request and blocks private ranges outright: loopback, 10 slash 8, 172.16 slash 12, 192.168 slash 16, link-local 169.254 slash 16, zero slash 8, and their IPv6 twins. It then pins the approved IP into the connection, so a rebinding attack cannot swap the address after vetting. And it keeps SNI and TLS aligned with the pinned address, because pinning at the socket level without pinning the name would throw certificate errors on every request.

Responses stream into the isolate with a running byte counter, hard-capped at ten megabytes, with an AbortController wired through the whole dispose path. When an isolate is retired, its in-flight requests are aborted in the same call. When a dispatch times out at the thirty second budget, a classifier asks what the isolate was doing at the moment of breach. Upstream I/O in flight, the guest computing, or memory pressure. The tool error that goes back to the agent carries the answer, plus a recovery hint.

The DNS cache lifetime is coupled to the connection lifetime. A vetted address is cached exactly as long as the pool holds a keep-alive agent for it, up to 65 seconds by default. An address cannot outlive the connection policy that justified pinning it. There is no independent TTL by design, and that is the property that closes the rebinding window entirely.

The cryptographic audit path: a chain you cannot forge

All of the agent traffic, all of the tool calls, all of the data flowing in and out of every connector, flows to a single-threaded streaming daemon. This daemon forges a SHA-256 hash chain and signs it with an Ed25519 session key. The session key is held in RAM for twenty four hours and certified by the master key on boot. Every request hash is sealed at ingestion. Each record carries the previous hash and its position in the sequence. The chain is signed. A tamper is not a privacy issue. It is a detectable event.

The chain input is the raw base64 payload concatenated with the previous hash and the sequence number. The current hash is SHA-256 of that input. The signature is Ed25519 over the same input, using the session private key. The session key rotates every twenty four hours, and the chain continues without a gap. The chain state is checkpointed to Redis Streams so that a crash resumes from the last acknowledged event instead of re-deriving the chain. SIEM adapters drain that same stream behind their own circuit breakers. A failing sink gets fenced off rather than allowed to back up the audit path.

The audit is structured around GDPR Article 73, the data subject's right of access. When a regulator or a customer asks for the full history of a connector, the answer is a single exportable, verifiable chain, not a project.

And here is the boundary that I am proudest of. V8 never touches crypto. Tenant code can compute a hash through the host bridges, but it cannot sign, certify, or forge anything. The audit trail is something the platform does to the runtime, not something the runtime's tenants can reach into.

The full twelve-surface model, the audit layer, the decoy layer, and the vault are described in the AI governance post.

The twelve surfaces: governance as an operating system

If you have read the AI governance post, you know the control plane. Twelve surfaces, eight that report and four that decide, sitting on scoped connection tokens, a sealed vault for credentials, a hash-chained audit ledger, and a decoy layer that contains damage before you notice it. What I have not yet said is how those twelve surfaces map onto the new consumer, the AI agent itself.

The agent does not see the twelve surfaces directly. It sees them as constraints on the environment it operates in. And those constraints are what let you hand the agent the night shift, the production query, the payment reconciliation.

Attribution. Every tool call carries the identity of the token that made it, the client behind it, the human or service account behind that. There is no such thing as an anonymous action in production. An agent that should be running hourly and is calling every ninety seconds shows up on Mission Control, and that is where a runaway loop is first noticed, before it becomes an invoice.

Data shielding. Sensitive fields are masked in memory, on the outbound path between the upstream and the model. The shielding happens before the response reaches the agent. The difference between data that was masked and data that was never in the model's context.

Cost control. The circuit breaker enforces a sliding-window request budget per connector, with a default of five thousand requests every five minutes and a fifteen-minute cooldown. When the budget is exceeded, the breaker trips and tells the agent, in a machine-readable refusal written for a model, that the resource is open and that it should back off. A good agent respects that. A loop that cannot read the refusal gets stopped by the same trip, which is the point. The breaker state is shared across the gateway fleet, so a budget is a budget, not a per-process limit that resets when traffic moves between instances.

Error recovery. A raw server answers a bad call with a flat string. The agent retries with the same string. MCP Fusion answers with a self-healing envelope. A specific code, a message, a suggestion, and a list of actions the agent can take instead. InvoiceNotFound tells the agent something that BAD_REQUEST cannot, and the recovery line removes the guesswork that makes retry loops expensive. This is the subject of the connector architecture post, where the full MVA pattern is explained.

The capability lockfile: drift detection as a compile step

One of the silent failures in agentic systems is drift. The server you deployed last month exposed twelve tools. Today it exposes seventeen, because someone added five more. The agent calls the new ones. Nobody reviewed them. The output is the same row, and it goes to a different place, and the audit trail records the call, but the surface area that was reviewed in CI is not the surface area that the agent can reach.

The MCP Fusion CLI runs a second, introspective compile of every bundle. It extracts the tool contracts, the prompts, and the credential schema, and writes them into a capability lockfile. This is a deterministic snapshot of the connector's behavioral surface. The lockfile is diffable in git. A fusion lock check in CI is the gate. The surface that your code actually exposes is compared to the surface you committed, and the diff is classified as breaking, risky, safe, or cosmetic.

The runtime that finally executes that program, sealed and snapshot-restored, is the same program that produced that lockfile. The source code, the compiled bundle, and the committed lockfile are one artifact. Drift is not possible because drift would mean the lockfile and the running code disagree, and that disagreement fails the CI gate.

The connector ships as a single artifact. The mcpfusion deploy command bundles the server into one self-contained file: all dependencies inlined, Node builtins replaced by stubs that exist only to satisfy the bundler and are never called, and the transport itself stubbed, because the platform supplies it. The bundle passes a size gate of 1.5 megabytes raw, which is a budget, not a spec, then gets compressed and hashed, and goes to the edge. If the hash matches the deployed one, the platform reports an instant restore: the same bytes, no reload.

Multi-agent orchestration: the SwarmGateway

Not every task can be solved by a single agent. Some problems need specialists. A finance specialist, a devops specialist, a customer operations specialist. Each of them is its own MCP server, its own model, its own tools.

The SwarmGateway implements the B2BUA pattern. It presents itself to the calling agent as a single MCP server with a prefixed tool list. When the agent calls a prefixed tool, the gateway strips the prefix and forwards the call to the upstream specialist server. When the agent is done with the specialist, a single return tool closes the tunnel and restores the gateway's tool list. Each handoff mints a short-lived delegation token, scoped to that domain only, valid for sixty seconds. The tunnel idle times out after five minutes.

Two security properties matter here. First, the delegation token cannot escape its sandbox, because the gateway validates the domain against its registry on every call. Second, the return-trip tool is injected by the gateway, not by the upstream, which means a compromised or buggy specialist cannot trick the agent into calling a different gateway. The namespace rewriter enforces this at the tool name level.

And because the gateway speaks the same trace context as the incoming agent, every tool span across the specialist handoff parents to the same trace. You can follow the agent from the triage layer to the finance specialist to the devops specialist and back, all in one distributed trace. That work, the W3C Trace Context propagation across the gateway, shipped in MCP Fusion 5.1.0, and the details are in the trace correlation post. When the swarm hits the gateway at scale, the session layer has to coalesce every agent without deadlock. The mechanics behind session pooling, causal invalidation, and the circuit breaker that keeps a runaway swarm in check are in the SwarmGateway sessions post.

The agent as a governed principal

Most conversations about agent governance treat the agent as a risk to contain, and I am not going to pretend otherwise. The agent is a risk. A non-deterministic principal calling tools against third-party systems under a budget. That is the risk.

But the other half of the argument is what I would put on the sales deck: governance is what turns an agent from a demo into a worker.

Trust is granted in proportion to evidence. An operator will hand an agent the night shift, the production query, the payment reconciliation, in direct proportion to how well every action it took can be attributed, budgeted, shielded, and verified after the fact. The receipt is not a burden on the agent. It is the credential that gets it the bigger room.

The envelope of a governed agent is knowable. A deterministic policy around a non-deterministic model is the only sane shape for production: the model plans inside a box, and the box is stable. The circuit breaker's refusal is written in the model's language, so the agent learns the budget and respects it, instead of discovering it in the form of a bill. The truncation in the FinOps guard means the model gets a sized answer instead of a two hundred kilobyte blob, which is an intelligence problem, not only a cost one.

And the agent itself gains the capability that no autonomous system has ever had in practice. It can show its work. For an agent that operates in regulated workflows, the audit trail is not overhead. It is the product. The governed agent is the only kind of agent you can give real authority, and the ungoverned agent is, forever, a demo.

Direction

What I have described above is the stack that runs today. Not the plan. Not the roadmap. The stack that a customer's MCP server, built with MCP Fusion, ships to the edge and executes inside.

The open direction is the stateful one. Longer-lived tenant state riding the hibernation hooks of the isolate. Denser packing of live isolates per host. Teams bringing their own connector catalogs into the marketplace without waiting on our CI. The snapshot layer already carries the hibernation interface. The state sync layer already understands causal invalidation. What remains is the density and the developer experience.

The deeper direction is the A2A protocol bridge. MCP Fusion already exposes any server as an A2A compliant agent, with the standard discovery endpoint at the well-known agent-card.json path. The SwarmGateway already speaks the B2BUA pattern. When A2A matures and agents start discovering each other autonomously, the gateway does not change. It already handles a fleet of specialists behind a single surface, with scoped delegation tokens and trace continuity through every handoff.

The boundary

I do not think V8 isolates are the final answer to multi-tenant edge code. They are the answer for the shape this platform has, and the shape is where I want it to stay. Cheap tenants. Hard caps. Millisecond-scale boot. Because an agent's patience is measured in seconds, and so is its trust.

The agents are already acting on your systems. The question is no longer whether you can afford governance. It is whether you can afford the day you find out you do not have it. Vinkius Cloud is the runtime that ships that governance, and MCP Fusion is the framework that makes it composable. Both are the result of building against one invariant: the consumer is not a human reading a screen. The consumer is a model that cannot read a schema and cannot remember a conversation. Everything else follows from that.

If you are building agents that act on production systems, the operating system they run on should be built for that consumer, not retrofitted for it. That is what we built. That is what the code enforces. And that is why the audit trail is something the platform does to the runtime, not something the runtime's tenants can reach into.

The runtime behind the MCP servers on cloud.vinkius.com is what I described here. The framework is open source at github.com/vinkius-labs/mcpfusion. Both are written in the same invariant.

Topicsagentsgovernancemcpfusionsecurityruntimeisolation