Most agents aren’t in an MCP host. They still shouldn’t hold your keys.
A LangChain tool, a scheduled job, a worker that reconciles invoices at 3am. None of them speak MCP, and all of them tend to end up with a token in an environment variable. The client libraries are the same broker, reached from ordinary code: your process proves who it is, and AgentValet holds everything else.
One package, no server to run
Node and Python are ports of each other: same endpoints, same approval behaviour. Node 18 or later, or Python 3.9 or later.
Install the client for your language.
Terminal npm install @agentvalet/client # or pip install agentvaletRegister the agent. The command prints
AGENT_ID,OWNER_ID,PROXY_URLandAGENT_PRIVATE_KEY_PATHwhen it finishes; set them where your code runs. From Python without Node,agentvalet register --code <code>does the same with an invite or enrolment code, and keeps the key in~/.agentvalet/agent.key.Terminal npx @agentvalet/registerGrant platforms and scopes in the dashboard. What you grant is exactly what this agent can reach.
Make a call. You name the platform, the endpoint and the scope; AgentValet checks it, decrypts the real credential in memory, makes the call and writes the audit row.
notify.ts import { AgentValet } from "@agentvalet/client"; const av = AgentValet.fromEnv(); const result = await av.call({ platform: "slack", endpoint: "/api/chat.postMessage", method: "POST", scope: "chat:write", data: { channel: "#general", text: "Deploy finished." }, });
The same call in Python
reasonis shown to whoever approves, if this scope needs approval.notify.py from agentvalet import AgentValet with AgentValet.from_env() as av: result = av.call( platform="slack", endpoint="/api/chat.postMessage", method="POST", scope="chat:write", data={"channel": "#general", "text": "Deploy finished."}, reason="Notify the team that the deploy completed", )
Where the client finds its key
In order:
AGENT_PRIVATE_KEY_B64,AGENT_PRIVATE_KEY_PATH,AGENT_PRIVATE_KEY, then~/.agentvalet/agent.key. Ids come fromAGENT_IDandOWNER_ID(anAGENTVALET_prefix wins if both are set). In a container, mount the key or pass it base64-encoded; nothing else needs to travel with your agent.
What’s governed here
Nothing is allowed until you grant it. This is a typical first grant for Your own code; you decide every row, and you can change it without touching the agent.
| What the agent tries | Platform | Decision |
|---|---|---|
| Post a deploy notice | Slack | Allowed within grant |
| Read invoices | Xero | Allowed within grant |
| Void an invoice | Xero | Asks you |
| Anything you haven’t granted | Any | Not granted |
A human in the loop is just a slower function call.
Mark a scope as needing approval and your code doesn’t change. The broker holds the action, your call() waits, you approve from your phone, and the result comes back. From your program’s point of view it simply took longer.
If nobody answers in time you get ApprovalTimeoutError, and that isn’t a failure: the action is still queued. Keep the approval id and resume with waitForApproval(approvalId) later, from this process or another one.
Governance you can’t handle in code is just an outage.
Every failure is a typed error, so your agent can tell a refusal from a Slack outage from a person saying no, without matching strings.
- AccessDeniedError
- No grant for this platform and scope, or your policy blocked it. Recoverable:
requestAccess()asks an admin and waits for the answer. - ApprovalDeniedError
- A person looked at this action and said no. The one error your agent should never retry.
- ApprovalTimeoutError
- You stopped waiting; the action didn’t. Still queued, resumable from any process.
- UpstreamError
- Allowed, run, and the platform itself returned an error.
- ConfigError
- Missing or malformed identity or key, raised before any network call.
- NetworkError
- The connection failed, with a hint pointing at DNS, TLS interception, a firewall or a timeout.
Node and Python SDK referenceThe longer walkthrough, kept with the product docs.
Put Your own code behind AgentValet.
Register the agent, grant only what it needs, and approve the risky calls from your phone. Free to start, no credit card.