You write the handler. Kitted is the MCP server, the auth, the sandbox, and the audit log. Your tools reach the systems that run your company, and IT can see every call, scope who may make it, and switch it off.
MCP server, with OAuth for the clients that call it
The same tool on a plain HTTP endpoint
A fresh sandbox per invocation, with time and output caps
Secrets held by the workspace, injected at run time
Preview, release, and a rollback that is not a redeploy
A run record with the person behind the call, not just the agent
One tool, three screens
Your code. A platform around it.
The implementation you wrote, the reasoning you wrote beside it, and every call it has served. Previews, releases, permissions, and a run record around code that stays ordinary.
Scroll to explore02 / 03
Packing operationsIntentEdited 13d ago
Packing operations
Purpose
Tools for the packing queue in the fulfillment system.
Expected behavior
update_packing_status moves one transfer to a new status and records the reason on the order.
Boundaries
Refuse any status the fulfillment system does not define. Refuse to move a transfer that is already Done.
Press ‘/’ for commands…
Type / for commands•Select text for formatting•Drag ⋮⋮ to reorder
Packing operationsCodeEdited 13d ago
src/update_packing_status.ts
1import{getTransfer,updateTransfer}from"./fulfillment";23exportasyncfunctionhandler({transferId,status,reason}:Input){4constallowed=["packing","manual_review","done"];5if(!allowed.includes(status))thrownewError("Unknown status");67consttransfer=awaitgetTransfer(transferId);8if(transfer.status==="done")thrownewError("Transfer is already Done");910returnupdateTransfer({11transferId,12status,13reason,14token:process.env.FULFILLMENT_TOKEN,15});16}
Packing operationsRunsTest run
Run
TookStarted
update_packing_statusadad920e
ClaudeforKonrad
1.6sjust now
update_packing_statuseec12717
ChatGPTforAAlice
0.9s12m ago
update_packing_status5b7c1d43
Bedrock agentforMMarcus
1.3s1h ago
update_packing_status0a94f8e2
ClaudeforAAlice
1.1s3h ago
update_packing_statusc31e07ab
ChatGPTforKonrad
1.5sYesterday
update_packing_status8d2b64f0
Bedrock agentforMMarcus
0.8sYesterday
01Code
The code you wrote
Read and diff the implementation that is actually deployed.
Packing operationsCodeEdited 13d ago
src/update_packing_status.ts
1import{getTransfer,updateTransfer}from"./fulfillment";23exportasyncfunctionhandler({transferId,status,reason}:Input){4constallowed=["packing","manual_review","done"];5if(!allowed.includes(status))thrownewError("Unknown status");67consttransfer=awaitgetTransfer(transferId);8if(transfer.status==="done")thrownewError("Transfer is already Done");910returnupdateTransfer({11transferId,12status,13reason,14token:process.env.FULFILLMENT_TOKEN,15});16}
02Intent
Why it exists
Your write-up of the behavior, the boundaries, and the reasoning.
Packing operationsIntentEdited 13d ago
Packing operations
Purpose
Tools for the packing queue in the fulfillment system.
Expected behavior
update_packing_status moves one transfer to a new status and records the reason on the order.
Boundaries
Refuse any status the fulfillment system does not define. Refuse to move a transfer that is already Done.
Press ‘/’ for commands…
Type / for commands•Select text for formatting•Drag ⋮⋮ to reorder
03Runs
Every call, recorded
Who asked, what it reached, and what came back.
Packing operationsRunsTest run
Run
TookStarted
update_packing_statusadad920e
ClaudeforKonrad
1.6sjust now
update_packing_statuseec12717
ChatGPTforAAlice
0.9s12m ago
update_packing_status5b7c1d43
Bedrock agentforMMarcus
1.3s1h ago
update_packing_status0a94f8e2
ClaudeforAAlice
1.1s3h ago
update_packing_statusc31e07ab
ChatGPTforKonrad
1.5sYesterday
update_packing_status8d2b64f0
Bedrock agentforMMarcus
0.8sYesterday
What a tool is
Your script. Your documentation. One endpoint.
The documentation you write
The questions people keep asking you, answered once.
Intent is your own write-up of what the tool does and why you built it that way, versioned in the repo next to the code. The teammate inheriting it, the person approving it, and you in six months all read that instead of asking you.
“What counts as stuck?”
Last month
“Why two hours and not one?”
Last week
“Can it move an order itself?”
Monday
Returns orders that have been stuck in packing for more than two hours, longest wait first.
Two hours because that is when the afternoon carrier pickup is at risk. Ops set the number, so change it there, not here.
BoundaryReads only. Moving an order is a separate tool.
The code you write
Your TypeScript. Your Python. Your tests.
An ordinary script with its dependencies pinned, written by you and reviewed the way the rest of your code is. Open it, diff it, download it, run it somewhere else.
MCP for the assistants and agent platforms your team uses, plain HTTP for your cron jobs and your own services. One permission model, one run record.
ClaudeChatGPTAny assistant
Build vs buy
The MCP server is the easy afternoon.
What follows is the part that lasts. Every internal tool that reaches a production system needs the same list, and the list does not get shorter because you wrote the server yourself.
On your own
Everything that comes after the server, none of it optional.
Somewhere to run it, and a sandbox, because it reaches a production system.
Secret storage, injection, and rotation.
Version history, and a rollback that does not mean redeploying an old commit.
An audit trail, written before anyone asks you for one.
Permissions per caller, so an agent cannot do more than the person behind it.
The same list again for the next agent platform your company adopts.
On Kitted
The same list, already built, around code that stays yours.
Push a TypeScript or Python project, or connect the repo. No Dockerfile, no registry, no cluster.
A fresh sandbox per invocation, discarded when the call ends.
Secrets declared in the manifest and injected at run time, never in the code.
A preview you can call yourself before anyone else can reach it.
Release and rollback as one action, each with an actor and a timestamp.
One tool over MCP and HTTP, under one permission model and one run record.
When not to bother
Three cases where you should keep this yourself.
One tool, one client, one developer.Nothing sensitive behind it and nobody who has to approve it. Write the server. It really is an afternoon.
Latency or throughput-critical paths.A fresh sandbox per call costs milliseconds you may not have. Put those calls on your own runtime.
Heavy data processing.If one call has to chew through ten gigabytes or scan a whole warehouse table, run it where the data lives and point a tool at the result.
For the people who approve it
Your tools reach production. IT can see exactly how far.
A useful tool needs access to a system of record. An approvable one makes that access specific, scoped, and reviewable, without the developer having to book a meeting to get it live.
What exists, and what it reached
One catalog, and a record of every call.
Every tool with who built it and what it can reach. Every call with who asked, which hosts it touched, and what came back. The developer debugs from the record the auditor reads.
Who may call it, and with what
Permission per person and per client.
Alice in her desktop assistant and Alice's nightly script are two grants, not one. Credentials stay with the workspace, injected at run time and separated by environment, so a preview never holds production keys.
When you need it to stop
An off switch, and a seat that cannot act.
Promotion to production is an admin action; building and previewing is not. Kill one tool or the whole workspace immediately, and give review a role that reads everything and invokes nothing.
FAQ
The technical read.
Real scripts, one endpoint over MCP and HTTP, secrets in the environment, and portable enough to run without us.
How is this different from Lambda or Cloud Run?
Same shape, different surface area. Lambda gives you compute and leaves you the rest: an MCP server in front of it, OAuth for the clients that call it, permissions per caller, secret rotation, and a run record an auditor can read. Then a second stack when the same logic has to answer plain HTTP. Kitted is the function plus that surface. If you already run all of it in your own account, you do not need us.
Why not just build my own MCP server?
You can, and the server itself is the easy afternoon. What follows is the part that lasts: somewhere to run it, secret storage and rotation, a sandbox because these tools reach production systems, version history with a rollback that isn't a redeploy, an audit trail before someone asks you for one, and the same work again for every agent platform your company adopts. Kitted is that second list, and you still get the code.
We already have REST APIs. Why not point the AI at those?
Usually you should, through a tool. Your API is the system underneath, and a Kitted tool calls it. What the endpoint does not carry is a contract shaped for a model, the business rules that decide when a call is allowed, permissions per person and per client, and a record tying the call back to whoever asked for it. Wrapping an API you already own is the normal case here, not the exception.
We already run an MCP gateway. Where does Kitted sit?
Behind it. Kitted is an origin server: the place a tool is built, holds its credentials, and records what it reached. A gateway aggregates origins and fronts them for your clients, which is a different job. Point yours at your workspace endpoint and keep your RBAC and your single address. The two are not alternatives, and a team that has the gateway usually still has nowhere to build the tools it serves.
What does a tool actually run as?
A TypeScript or Python script with a typed input, your logic, and a typed result. Dependencies pinned in package.json or requirements.txt, secrets arriving as environment variables, and every invocation in its own sandbox with hard time and output caps. Your assistant sees a tool it can call; you see a script you can open and diff.
Which clients can call it?
Anything that speaks MCP, over stdio or HTTP: Claude, ChatGPT, Cursor, and the agent platforms your company standardises on. The same tool is also a plain HTTP endpoint, so a cron job or one of your own services calls exactly what the assistant calls, under the same permissions.
Where do credentials live?
With the workspace, not in the code, which matters because the code is downloadable. The manifest declares which secrets a tool needs, the platform injects only those into an isolated per-tool environment, and environments are separated so a preview never holds production credentials. Every run records who asked, which tool ran, and which hosts it reached.
Can I take the code and leave?
Yes. Every tool is a self-contained package: your logic, its dependencies pinned, and a manifest. Download it and it runs with node script.ts or python main.py plus a few environment variables. Nothing in the code calls back to a proprietary runtime, so the same artifact runs on your laptop, in your CI, or here.
One system is enough
Ship one tool. Let every AI call it.
Bring one internal system and one job your team still does by hand against it. That is the first tool, and the second one costs you an afternoon.