The deploy step was where the human stood
What reviews a tool that did not exist ten seconds ago?
An agent working through a task decides it needs a capability nobody built. On most platforms the next few hours look like this: someone writes a handler, opens a pull request, a second person reads it, it merges, CI builds, the MCP server redeploys, and the tool exists. The agent waits. More often the run simply ends and a person picks the thread back up tomorrow.
On OBTO an MCP tool is a database record. Creating one is a single call, and there is no build, no redeploy and no server restart between that call and the tool appearing in the tenant's catalog.
That is a real speed difference, and it is the least interesting thing about it. The deploy step was carrying a passenger.
What the deploy step was actually for
Look at a normal tool-shipping pipeline and the deploy is the last mechanical stage in a chain that began with a human reading code. The review is not really attached to the deploy. It is attached to the fact that shipping was slow enough, and public enough, that somebody had to look.
Take the chain out and you get the speed. You also quietly delete the one guaranteed moment when a person read what the new tool was allowed to do. Nobody decides to remove that review. It leaves with the pipeline it was riding on.
So the question a platform like ours has to answer is narrow and slightly uncomfortable. If a tool can exist one second after an agent decides it wants one, what does that tool have to say for itself first?
The declaration moved into the call
Our creation call refuses a tool that has not described its own blast radius. Two arguments are required, and neither one is optional documentation.
annotations is the machine-readable part. readOnlyHint, destructiveHint and openWorldHint are all required booleans. Does this tool change state? Can it destroy something? Does its effect leave the platform?
annotationJustifications is the part that is harder to fake. For each of those three claims the caller has to write a reviewer-facing sentence explaining why the value is accurate. That sentence is stored on the record.
Here is a real one, from a tool live in our own catalog. bridge_post appends a message to a thread so that people can see what an agent is doing. It declares itself non-destructive, and it has to say why:
"It is append-only. It adds a new message and never edits,
overwrites, deletes, or deactivates existing threads or
messages, so no prior data can be lost."
A person reads that in about four seconds and can tell whether the handler underneath is behaving. That is the job the pull request used to do, relocated into the API that creates the thing.
What creating one looks like
The whole surface is one call: a Zod schema for the arguments, a handler written as a JavaScript function expression, and the declarations.
name: "flag_overdue_invoice",
zodSchemaString: 'z.object({ invoiceId: z.string() })',
handlerFunction: 'async (args) => { ... }',
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
annotationJustifications: { /* one sentence per claim, required */ }
})
There is no repository for this tool, no image to rebuild and no process to restart. It is a row in the tenant's catalog, scoped to that tenant, and the next session that connects will see it.
The boundary we did not remove
One constraint survives, and it comes from MCP rather than from us. A client caches the tool catalog when it connects, so an agent that creates a tool cannot then call it. Its own catalog was fixed at connect time. The new tool becomes callable from the next session.
We did not design that as a safety feature and it would be dishonest to sell it as one. It is a protocol detail. Its effect, though, is a quarantine: every tool an agent mints sits in the catalog, readable, across at least one session boundary before anything can invoke it. Whatever inspection you want to run in that window, automated or human, has somewhere to stand.
What this does not solve
A justification is a claim, and an agent can write a confident, well-formed sentence that is wrong. Nothing about a required string field makes the handler beneath it honest. A tool can declare destructiveHint: false and then drop a collection, and the record will hold a fluent explanation of why that could never happen.
A pull request, where a person reads the actual code before it can run, is stronger than this for anything high-stakes. That is worth saying plainly. Managed MCP platforms that keep a build step keep that review along with it, and for a small set of carefully written tools they are right to.
What the structured declaration buys is narrower. The claim is stored as data on every tool in the tenant, so "show me every tool here that says it can destroy something" is a query rather than an afternoon of reading source. So is "show me every tool whose effect leaves the platform." You are trading a guaranteed read of a few tools for a queryable index over all of them.
Which one you want depends on how many tools you have and how fast they arrive. If the answer is a handful, written by people, keep the pull request. Catalogs stop being readable at a size that shows up sooner than most teams expect.
What we would tell you to steal
The generalizable rule has nothing to do with MCP. When you remove a human step because it is slow, name the second job it was doing before you take it out. Shipping was the visible job; the review was riding along with it.
Then put that second job somewhere structural. Make it an argument the creation API refuses to run without, so a caller in a hurry cannot skip it. A doc comment, a wiki page, or a line in a prompt asking the agent to be careful are all things a system will happily proceed without. A required field is not.
We use the same move elsewhere. A patch carries an anchor and is refused when that anchor no longer matches what is live. An upload is refused when its bytes do not hash to what was promised. Guardrails that live in the prompt are the version of this that does not hold.
If you want to try it, building a tool is the shortest way in, and the Builder tier is free.