Your AI Agent Doesn't Have an Identity. Here's Why That's a Problem.
I built an MCP server that gives any Claude Code or Cursor agent a cryptographic identity with 60-second credentials. No SDK. One JSON block. Here's the whole story.
Your AI Agent Doesn't Have an Identity. Here's Why That's a Problem.
I've been running Claude Code as my primary development loop for months. It writes code, runs tests, calls APIs, deploys infrastructure. It does real work. And for all of that real work, it authenticates as me.
Not as an agent acting on my behalf. Not with scoped, time-limited access to a specific resource. It uses my API keys, sitting in environment variables, with the same standing access I have. Every MCP server in my config can read those variables. Every tool call goes out with my full credentials.
There is no audit trail. There is no per-action scoping. If the agent hallucinates a destructive API call -- say, a DELETE on a production resource it misidentified -- there is no cryptographic receipt proving what happened, when, or why. Just my API key in the logs, looking like I did it myself.
This bothered me enough to build something.
The Leak That Made It Urgent
On March 31, 2026, the Claude Code source was leaked. The fallout was mostly about Anthropic's internal prompts, but the part that caught my attention was structural: it confirmed what anyone running MCP servers already suspected about the security model.
Astrix Security published research showing that 53% of MCP servers use static secrets for authentication. Hardcoded tokens. Long-lived API keys. Secrets stuffed into environment variables that any server in your MCP config can access.
The MCP protocol itself has no identity layer. When your agent calls a tool, the server gets raw JSON-RPC. There is no concept of "who is asking" or "are they allowed to do this specific thing right now." The protocol trusts that the client is authorized because it has access to the transport. That is the entire security model.
For local development, maybe that is tolerable. For agents making real API calls, deploying real code, spending real money -- it is not.
What I Built
vaos-kernel is an MCP server that gives your agent a cryptographic identity. 6 tools. 8.7MB binary. Zero config.
You add one JSON block to your claude_desktop_config.json and your agent gets:
- Per-action credentials scoped to a specific intent (action + resource), valid for 60 seconds
- Ed25519-signed receipts for every tool call
- A hash-chained audit ledger where each entry references the previous one, so tampering with any record breaks the chain
- Chain verification you can run at any time to prove integrity
No SDK to install. No OAuth flow to set up. No separate identity provider. The MCP server is the identity layer.
How It Works
The flow is simple. Your agent calls request_credential with an intent -- what it wants to do and what resource it wants to act on. The server:
- Hashes the intent with BLAKE2b-256 to produce a fingerprint
- Issues a JWT valid for 60 seconds, embedding the intent and fingerprint
- Signs a receipt with Ed25519
- Appends the entry to a hash-chained ledger, where each entry includes the hash of the previous entry
Here is the actual JSON-RPC exchange from my dogfood test:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "request_credential",
"arguments": {
"action": "read",
"resource": "github:repos/jmanhype/vaos-kernel"
}
},
"id": 1
}
The server responds with a scoped credential:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"fingerprint": "e3a5c7698dd8ca79ab9e44048470521b...",
"signature": "e6277a510700a67d03a12fc61beb0241...",
"expires_in_seconds": 60,
"intent": {
"action": "read",
"resource": "github:repos/jmanhype/vaos-kernel"
}
}
60 seconds. One action. One resource. After that, the agent has to ask again. Every request is a new entry in the ledger.
Setup
Add this to your claude_desktop_config.json:
{
"mcpServers": {
"vaos-kernel": {
"command": "/path/to/vaos-mcp",
"args": [],
"env": {
"VAOS_JWT_SECRET": "your-secret-here"
}
}
}
}
That is the entire setup. The binary handles key generation, ledger initialization, and chain management on first run. No accounts. No cloud dependency. Everything runs locally.
The six tools exposed over MCP:
| Tool | What it does |
|---|---|
request_credential | Issues a 60s scoped JWT for a declared intent |
verify_credential | Validates a credential is authentic and not expired |
record_audit | Records an audit entry with cryptographic attestation |
verify_chain | Validates the entire audit ledger integrity |
get_public_key | Returns the Ed25519 public key for signature verification |
register_agent | Registers a new agent identity in the registry |
The Dogfood
I tested vaos-kernel by piping raw JSON-RPC through stdin -- the same transport Claude Code uses. No wrapper. No test harness. Just the binary reading and writing newline-delimited JSON.
All 6 tools passed. Chain verified. Signatures valid. Here is the output:
=== REQUEST CREDENTIAL ===
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Fingerprint: e3a5c7698dd8ca79ab9e44048470521b...
Signature: e6277a510700a67d03a12fc61beb0241...
Expires in: 60s
=== VERIFY CHAIN ===
Chain valid: True
Entries verified: 2
Chain status: ok
Sig status: ok
Sigs verified: 2
Two ledger entries -- the credential request and the chain verification itself -- both signed, both hash-linked. Changing a single byte in any entry would cause verify_chain to fail.
What This Actually Gets You
Every tool call your agent makes now has a cryptographic receipt. If something goes wrong -- and with agents making autonomous decisions, things will go wrong -- you can:
-
Prove exactly what happened. The signed receipt includes the action, resource, timestamp, and credential fingerprint. This is not a log file that could be edited. It is a signature you can verify against the server's public key.
-
Prove when it happened. The JWT has a 60-second window. If a receipt's timestamp falls outside that window, something is wrong.
-
Prove the chain was not tampered with. Each entry hashes the previous entry. Break one link, the whole chain fails verification. This is the same integrity property that makes git commits trustworthy.
-
Scope blast radius. A credential for
readongithub:repos/jmanhype/vaos-kernelcannot be used todeleteonaws:s3/production-bucket. The intent is baked into the fingerprint.
This is not theoretical. I run Claude Code agents against production infrastructure. The question is not whether an agent will make a bad call. The question is whether you will be able to reconstruct what happened when it does.
The Bigger Problem
vaos-kernel solves the identity and audit problem at the local level. But there is a harder version of this problem: what happens when you have 5 agents, running across 3 sessions, over 2 days, sharing state through MCP servers that have no concept of session continuity?
The audit ledger resets. The keys rotate. The chain starts over. You lose the ability to trace a decision back through the agent's history.
That is the problem I am working on next -- persistent identity and audit continuity across sessions. The local kernel handles the cryptography. A coordination layer handles the persistence.
Try It
vaos-kernel is open source at github.com/jmanhype/vaos-kernel. Clone it, build it, add the JSON block, and your agent has an identity.
If you want managed hosting with persistent audit logs across sessions, cross-agent identity federation, and a dashboard for reviewing what your agents actually did -- that is what vaos.sh does.