NitroStack x SRM Hackathon 2026

Your AI agent just got a permission system.

Connect an agent to an MCP server today and it is all or nothing. NitroWatch classifies every tool by risk, blocks what the agent should not do, and lets safe tools earn autonomy.

One billing server. Three tools.
get_invoicereads a record
send_invoicemoves money
delete_accountdestroys it permanently
MCP treats all three identically. There is no way to say read freely, ask before spending, never delete.

The middle option did not exist

Every team adopting MCP hits the same wall, and both available answers are bad. Approve every call by hand and the human becomes a bottleneck who starts rubber-stamping. Trust the agent completely and one hallucinated tool call destroys production data.

NitroWatch is the layer in between. It sits in front of any MCP server, and every tool it governs sits in exactly one of three tiers.

read
runs immediately

No side effects. Nothing to undo, so nothing to gate. Autonomous from the moment it is classified.

reversible
gated, can be promoted

Real effects that can be walked back. Requires approval by default, and this is the only tier that can ever earn the right to run unattended.

irreversible
gated permanently

Cannot be undone. Money moved, data destroyed, an instance terminated. Approval is required on every single call, forever.

The hard rule: an irreversible tool can never be promoted to run unattended, no matter how good its track record. Trust is earned per tool, but the ceiling is set by consequence, not history. A delete tool does not become safe because it deleted correctly twenty times.

Autonomy is earned, and offered rather than taken

A reversible tool that accumulates three clean approvals with zero denials becomes eligible for promotion. NitroWatch then makes an offer. It never promotes itself, a human confirms, and that autonomy can be withdrawn instantly.

A single denial disqualifies a tool from autonomy permanently. If a human ever said no, the pattern is not clean enough to stop asking.

classify

Every discovered tool is assigned a tier and a reason. An unclassified tool cannot run at all.

enforce

Reads pass through. Everything else is queued with a plain-language brief for the human.

earn

Three clean approvals make a reversible tool eligible. The human confirms, and can revoke.

audit

Every classification, block, denial, promotion and refusal is recorded, including refused escalations.

It speaks the protocol in both directions

To govern a server, NitroWatch has to talk to it. So NitroWatch is an MCP server that is simultaneously an MCP client. It connects outward over SSE, enumerates the target's real tools, resources and prompts, and every governed call is executed through a single audited function.

That is what makes it general. It is not wired to one server we also wrote. Point it at anything that speaks MCP and it will classify and gate what it finds.

Before approving

You see what it would actually touch

Blocking a call is the easy part. The hard part is giving a human enough context to decide well in five seconds, and a raw JSON payload is not a decision aid.

scoped to accountId="acc_991" UNBOUNDED - "force" is set, so this may affect every record this tool can reach

"Approve this?" and "approve this, knowing it hits every record" are very different questions.

The bug we found in our own classifier

We pointed the classifier at a domain it had never been tuned for, and it immediately made a dangerous mistake. This is the most useful thing we learned building NitroWatch, so it gets told rather than buried.

The classifier was written and tested against a billing vocabulary. To check whether it generalised, we ran it over an infrastructure server. One result stopped us.

read scale_deployment matched read-only verb "count"

scale_deployment was classified read. In NitroWatch, read means autonomous from birth. It runs immediately, forever, with no approval. A tool that resizes production deployments would have run completely unsupervised.

The classifier was reading the tool name and its description as one bag of words. The description said "change the replica count of a deployment", and count is in the read-verb list. One noun in a sentence of prose was enough to grant a mutating tool permanent unattended execution. The same flaw hit rotate_credentials, which matched set in "invalidate the previous set".

The name is authoritative

A name is written to state what a tool does. A description is prose. They are no longer read as one bag of words, so a noun buried in a sentence cannot decide a tier.

Descriptions may only escalate

Prose can reveal a tool is more dangerous than its name suggests. A cleanup tool that "permanently deletes" really is irreversible. It can never argue one down to read.

Rule two is a security property, not a bug fix

If a description could lower a tool's tier, the description becomes an attack surface. Anyone who controls the text of a tool, including the author of a third-party MCP server you connected, could write prose designed to talk NitroWatch into treating delete_everything as read-only.

Under the current rules that is impossible. The worst a hostile description can do is make a tool look more dangerous than it is, which fails safe. The same principle governs the optional LLM classifier: when the model and the heuristic disagree, the more dangerous verdict always wins.

It cost one test run against an unfamiliar vocabulary, and it is now locked in by a regression test asserting scale_deployment can never be classified read. We would rather ship a governance tool that has been caught failing and fixed than one that was never tested outside the domain it was written for.

Two of the bugs we found were not ours

We wrote tests because the rules encouraged it, and they immediately started earning their keep. Then, while debugging our own deployment, we found two issues in the NitroStack framework itself and reported them upstream.

Found in our code
classifier: scale_deployment
critical

A mutating tool classified read-only, so it would have run unattended forever. Fixed by making the tool name authoritative and letting descriptions escalate risk only.

classifier: conjugated verbs
high

A description reading "permanently deletes archived records" classified as reversible, because the verb list held delete and the prose said deletes. Fixed with suffix stripping, deliberately not prefix matching, which would have made "settings" match the verb "set".

blast radius: camelCase keys
high

An argument like accountId was invisible to scope detection, because the pattern anchored on an underscore or the start of the string. The approval card would have shown no scope at all for the most common argument shape there is.

widget: never rendered
high

The approval console existed but no tool carried the binding decorator, and no tool returned its data shape. It rendered perfectly in preview from static fixtures and would have shown nothing at all in a live demo.

Found in the NitroStack framework, reported upstream
core: OAuthModule
reported

@nitrostack/core registers OAuthModule unconditionally, but the OAUTH_CONFIG provider token only exists once forRoot() is called, and the starter template never calls it. Every project scaffolded from that template throws a dependency-injection failure on every cold start. It is non-fatal, the app serves fine, but it logs at error level and shows up as a failing health metric on a dashboard that is otherwise green.

cli: PORT is ignored
reported

The documented PORT environment variable is silently ignored by nitrostack-cli start. We set it in the environment and in .env, and the server bound to 3000 both times. Only the --port flag works. Two of our servers collided on the same port before we traced it.

Reading your own logs closely enough to find a bug in the platform you are building on is not a distraction from the project. It is the same skill the project is about.

What is actually built

Verified end to end against a live deployment, cloud governing cloud, with no localhost anywhere in the path.

14
governance tools
18
tests, 4 real bugs caught
2
framework bugs reported upstream
3
risk tiers, 1 hard ceiling

What it does not do yet

Stated plainly, because a governance tool that hides its gaps is worth less than one that names them.