keywarden
Keywarden is a local encrypted credential vault that lets AI agents use API keys without ever reading them, exposing tools for metadata lookup, authenticated proxying, command execution with injected secrets, and audit access.
List secrets metadata –
list_secretsreturns refs, providers, field names, tags, and last-used times, never values.Describe a single credential –
describe_secretshows usage metadata: whether HTTP proxying is allowed, allowed hosts, and env-var mappings for injection.List provider presets –
list_providersshows known providers, their allowed hosts, expected fields, and environment mappings.Make authenticated HTTP requests –
http_requestattaches a vaulted credential to an HTTPS request; redirects are not followed, and only allowed hosts are reachable.Run local commands with injected credentials –
runspawns a process with chosen credential refs injected as environment variables; output is redacted for any credential values.Tail the audit log –
audit_tailshows recent allowed/denied credential usage with host/command details, optionally filtered by ref.No secret retrieval tool – there is no way for the agent to read raw credential values, only to use them indirectly.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@keywardenUse my OpenAI prod key to call the models endpoint"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
keywarden
Your AI agent can use your API keys. It can never read them.
keywarden is a local, encrypted credential vault that speaks MCP. Claude Code, Claude Desktop, Cursor, or any MCP client connects to it and gets two capabilities: make an authenticated API call, and run a command with credentials in its environment. Neither one ever puts the credential itself into the model's context.
There is no get_secret tool. That absence is the whole product.
Just want to use it? docs/USING.md is the short version: install, the four ways in, and how to wire it into Claude Code, Claude Desktop or your own app.
agent keywarden upstream
| | |
| "POST /v1/chat | |
| using openai/prod"| |
|-------------------->| |
| | check policy |
| | decrypt key |
| | attach Authorization |
| |------------------------->|
| |<-------------------------|
| response only | scrub any key from body |
|<--------------------| append to audit log |Why
Right now the normal way to let an agent use your OpenAI key is to put the key in a .env file and
let the agent read it. The moment it does, the key is in a model's context window. From there it is
in a provider's logs, possibly in a training set, possibly in a crash report, and definitely in your
own transcript history that you will paste into a bug report six months from now.
Rotating a key is annoying. Not knowing whether it leaked is worse.
keywarden removes the step where the model sees the key at all.
Related MCP server: SecretVault MCP
Install
npm install -g keywarden-mcpThat gives you two commands: keywarden (the CLI and console) and keywarden-mcp (the MCP server
your agent client spawns). The npm package is keywarden-mcp because keywarden was already taken
on npm by an unrelated project; the command you type is still keywarden.
Node 20.10 or newer. Two runtime dependencies: the MCP SDK and zod. No native modules, no compiler, no daemon.
Quickstart
keywarden init --passphrase
keywarden add openai/prod --provider openai
keywarden mcp-configinit creates ~/.keywarden/ with an encrypted vault and a deny-by-default policy. add prompts
for each field, so nothing lands in your shell history. mcp-config prints the block to paste into
your MCP client.
Then, in Claude Code:
Call the OpenAI models endpoint with my prod key and tell me which ones I have access to.
The model calls http_request with ref: "openai/prod". keywarden attaches the key, makes the
call, returns the response. Ask it to print the key and it will tell you it cannot.
The tools an agent gets
Tool | What it does |
| Metadata only: refs, providers, field names, last used. Never values. |
| One credential plus how it may be used, which hosts, which env vars. |
| Built-in presets and what each one expects. |
| Authenticated HTTPS call. keywarden attaches the credential. |
| Spawn a local process with credentials injected as env vars. |
| Recent entries from the tamper-evident log. |
Set KEYWARDEN_DISABLE_EXEC=1 to drop run entirely and expose only the HTTP proxy.
Drop it in front of code you already have
The adoption problem with a credential proxy is that using it usually means rewriting how your code
calls the API, and nobody rewrites working code for a security property they cannot see. So
keywarden presents the provider's shape at a keywarden URL. Point an existing SDK's base_url
here, put a keywarden key where the provider key went, change nothing else:
from anthropic import Anthropic
client = Anthropic(
base_url="http://127.0.0.1:8787/x/anthropic/prod",
api_key="kw_live_...", # a keywarden key, not an Anthropic one
)Or set the variables most frameworks already read, and point a whole app at keywarden without touching its source:
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787/x/anthropic/prod
export ANTHROPIC_API_KEY=kw_live_...keywarden shim <ref> prints the exact snippets for a credential, and the console has the same
under Drop-in SDK. Streaming works and streamed calls are still metered — keywarden reads token
counts out of the event stream as it passes, with redaction applied over a sliding window so a
secret straddling a chunk boundary is still caught.
The shim is a different doorway to the same pipeline, not a bypass. A key without the http
capability, a ref outside the key's scope, a path outside policy, and an exhausted budget are all
refused exactly as they are on /v1/proxy.
About naming, and environments
A ref is just a name. Environments only matter if you hold more than one key from the same provider
a real one and a throwaway for testing. If you hold one key each, skip them and call it
anthropic.
keywarden list --env dev # filters on the part after the slashThat is a view, not a boundary. It changes what you are shown, never what a key may reach. The control that actually restrains something is a scoped key, and that is for agents, which run unattended.
What keywarden does not protect you from
Read THREAT_MODEL.md before you trust it with anything expensive. The short version:
If the agent can run arbitrary local commands through some other tool, it can read your vault file and, in keyfile mode, your master key. keywarden protects the model's context, not your disk.
rungives the credential to a real process. If you allowlist a command that can be steered into exfiltrating its own environment, the credential leaves. Allowlist narrowly.Redaction is a safety net with holes. A credential that an API returns re-encoded in a way we do not recognise will not be caught.
keywarden does not stop an agent from doing something expensive or destructive with a credential it is legitimately allowed to use. That is what policy scoping and rate limits are for.
Reference
Everything below is reference material for when you need it. Click a heading to expand.
The failure that actually happens is not a broken cipher. It is one broad key, handed out because it was convenient, turning up somewhere it should not be.
Name the set, do not glob it
openai/** is easy to write and quietly grows every time you add a credential. If what you meant
was "the two an intern may touch", say that:
keywarden group set interns openai/dev anthropic/dev
keywarden apikey create intern-alice --ref @interns --http --owner dinakarMembership resolves at check time, so adding a credential to the group grants it and removing one revokes it, without reissuing anyone's key. An unknown group expands to nothing — a typo narrows access, never widens it. The groups file is MACed like the vault, because editing it silently widens every key scoped to it.
The tool tells you when a key is too big
keywarden apikey create admin-everything --ref '**' --http --write --reveal --exec --audit
reaches 10 of 10 credential(s)
! this key reaches every credential and carries reveal + write + exec - losing it loses everything
! reveal means this key is equivalent to the credentials it covers
! write plus reveal is the combination to keep to a console you are looking at
! 10 credentials in one key - consider a group with only what it needsAdvice nobody reads is not advice. The number is printed at the moment you create the key, and again in the console beside every key you already have.
Delegation may only narrow
A key can never issue a key more powerful than itself — not a capability it lacks, not a scope
wider than its own. Without that rule write was the only capability that mattered: a console key
with no reveal could mint one that had it, and the gate on reading credentials was a single extra
request.
When a key is loose
keywarden panic --group interns # everything scoped to that group
keywarden panic --owner alice # everything that person holds
keywarden panic # every key, and every live grantRevocation takes effect on the next request, including on servers already running. And keywarden
says the thing people forget: revoking a key does not rotate the credentials it could reach. If
you believe it was used, rotate them — and keywarden audit tail shows exactly what it touched.
Most keywarden keys are not developers. They are agents, and an agent is a non-human identity that needs exactly what a person needs: an owner, a scope, a bill, and a name in the log.
keywarden apikey create triage-bot --ref 'anthropic/**' --http --agent triage-bot --owner dinakar --project support --ttl 30d
keywarden apikey create research-bot --ref 'anthropic/**' --http --agent research-bot --owner dinakar --project growth --ttl 30dA run is the unit, not a request. An agent makes forty calls on its own, and "which credential
was used at 03:14" is not a useful question — "what did that run touch, and what did it cost" is.
Over MCP an MCP server is spawned by one client for one session and exits with it, so the process
is the run. keywarden stamps a session id at boot and every call inherits it. Over HTTP a
framework sends X-Keywarden-Session and X-Keywarden-Agent.
A run making 30+ calls a minute over 20+ calls is flagged high-rate. Five or more denials is
flagged repeated-denials. Both are plain thresholds on purpose: a heuristic you can explain is
one you will act on.
Provider dashboards tell you what an organisation spent, not who spent it. keywarden is already in the request path with an actor on every call, so attribution is free.
ACTOR CALLS IN OUT COST
http:alice 412 418,220 96,410 $12.84
http:bob 38 92,004 31,887 $3.11Rates are yours, not ours. keywarden ships no price list. Prices change, differ by contract and region, and a stale hardcoded number produces a confident wrong figure in a finance report. You enter the rates you are on, each records when you last checked it, and anything over 90 days old is flagged as stale.
Budgets that can actually stop something:
scope everything | one API key (a person, a service) | one credential glob
period day | week | month
action warn - records and notifies
block - refuses with HTTP 402 before the credential is touched
alerts 50% / 80% / 95% by default, fired once per periodA block budget is the difference between finding out at 3am and finding out at the end of the
month. Alerts POST to any https webhook — n8n, Zapier, Slack.
keywarden uiStarts the agent, mints a console key that expires on its own, and opens a browser at
127.0.0.1:8787. One self-contained page, no build step, no external requests.
Credentials — add, import, search, filter. Shows field names, last-used, allowed hosts.
Copy test prompt — every credential row has a button that copies a ready-to-paste prompt for your AI agent, so a key you just added can be tested in one paste. A "Provider test prompts" panel at the bottom lists every template for reference.
"Not sure" flow — the Add-credential picker starts with a "Not sure - help me figure it out" option that generates a prompt for your agent to identify the right provider preset for a service it does not recognise, without ever seeing your key value.
How to use — the panel that opens after adding: a prompt to paste into your agent, a
curlcommand, the env vars injection sets, and a Test it button that makes a real call.Approvals — a rule with
requireGrantdenies until a human says yes. Denials land here with exactly what was attempted; approving issues a grant scoped to that request and nothing wider.Activity — every decision with the actor that caused it, and a live check on the hash chain.
Usage — token totals by credential, actor and model.
Grants, API keys, Policy — issue, revoke, edit.
Importing what you already have. Paste or drop a .env into the console. Variable names are
matched against known providers, so OPENAI_API_KEY becomes an openai credential. Parsing
happens in the page; nothing reaches even the local agent until you have seen what it found.
Any API, without editing JSON.
keywarden add attio/prod --url https://api.attio.comInfers the provider id, env var (ATTIO_API_KEY), and host allowlist from the URL, then prompts
for the value. A wildcard host is refused because it would defeat the control that stops a prompt
injection mailing your key somewhere.
Reveal, rotation and history. The promise is "your agent cannot read it", not "nobody can ever
read it". keywarden reveal has always existed at the terminal; the console can do the same only
when its key carries reveal. reveal is off by default, is never implied by any other
capability, and every use is written to the audit log with the value's fingerprint. It exists on
the HTTP surface only — no MCP tool returns a credential, ever.
Rotation keeps the old value. keywarden history <ref> lists retained versions; --rollback N
restores one. Ten versions are kept per credential.
Serving a page next to a secrets API. Binding to 127.0.0.1 keeps the network out. It does
not keep the browser out: any site you visit can make your browser issue requests to a loopback
port. So every request is checked for Origin, Host must be a literal loopback address (blocks DNS
rebinding), and the page ships under a CSP of default-src 'none' loading nothing remote.
The same vault, policy engine, grants and audit log are reachable three ways. Which one you use changes nothing about what is allowed.
surface | for | how the caller is identified |
MCP (stdio) | Claude Code, Claude Desktop, Cursor | the client that spawned the server |
CLI | you, at a terminal | filesystem access to the vault |
HTTP (loopback) | any language, CI, a script, the console | a scoped keywarden API key |
The HTTP surface is what makes keywarden usable from code that does not speak MCP:
keywarden apikey create ci-runner --ref 'openai/**' --http --audit --ttl 30d
keywarden serve --port 8787Routes: /v1/secrets, /v1/secrets/:ref, /v1/proxy/:ref, /v1/run, /v1/audit, /v1/usage,
/v1/whoami, /healthz. The server binds 127.0.0.1 and refuses a routable interface without
--allow-remote.
Proxy, for HTTP APIs. The agent describes a request, keywarden attaches the credential and makes the call. Works for OpenAI, Anthropic, Stripe, GitHub, Slack, Cloudflare, Vercel, Supabase, and any API that authenticates with a header or a query parameter.
{ "ref": "openai/prod", "method": "POST", "url": "/v1/chat/completions", "body": { "model": "gpt-4o", "messages": [] } }Inject, for everything else. AWS needs SigV4 signing, a Postgres URL is not HTTP, and
terraform apply wants real environment variables. keywarden spawns the process itself:
{ "command": "aws", "args": ["s3", "ls"], "inject": ["aws/prod"] }The child process gets AWS_ACCESS_KEY_ID and friends. The model gets stdout, with any credential
appearing in it masked on the way out.
~/.keywarden/policy.json decides which credential may be used, by which capability, against what.
Rules are evaluated top to bottom, first match wins, and the default is deny.
{
"version": 1,
"default": "deny",
"redactResponses": true,
"rules": [
{ "ref": "openai/**", "http": { "allow": true, "methods": ["POST"], "paths": ["/v1/**"] }, "rateLimitPerMinute": 30 },
{ "ref": "aws/prod", "exec": { "allow": true, "commands": ["aws", "terraform"] }, "expiresAt": "2026-12-31T00:00:00.000Z" }
]
}Or from the CLI: keywarden policy allow "openai/**" --http --path "/v1/**" --method POST.
* matches inside one path segment, ** spans segments. expiresAt makes a rule temporary.
Naming a command is not enough on its own. Allowlist aws for aws s3 ls and the same binary
does aws s3 cp into a bucket someone else owns. That is the sequence-level gap the MCP threat
literature keeps pointing at. Rules constrain arguments too:
"exec": {
"allow": true,
"commands": ["aws"],
"argsDeny": ["s3://*", "--endpoint-url"],
"argsAllow": ["s3", "ls", "--region", "*"]
}Policy is standing configuration. It is the wrong shape for "let the agent do this one thing, now, for fifteen minutes", which today means widening a rule and forgetting to narrow it again.
keywarden grant aws/prod --exec aws --ttl 15m --uses 5 --arg-deny "s3://*"
keywarden grant openai/prod --http --path "/v1/chat/**" --method POST --ttl 1h --uses 20
keywarden grant list
keywarden grant revoke <id>Grants expire on their own, die when their use budget runs out, and are HMACed with a key derived
from your vault, so a hand-edited grants.json is rejected. A denied attempt does not burn a use.
Set "requireGrant": true on a policy rule and standing configuration becomes necessary but not
sufficient. That is the human-in-the-loop approval step without needing an interactive prompt
inside a stdio server.
Encrypting the secrets is half the job. policy.json decides whether a credential may be used and
providers.json decides where it is sent. Both are plain files. Someone who cannot decrypt a
single byte can still add a provider whose hosts are theirs and repoint your credential at it.
So the vault pins a hash of both files and refuses to act on either until you have looked at the change:
keywarden trust show # what drifted
keywarden trust # review, then pin the current contentsThe vault file itself is MACed as a whole, not just per-field, because flipping
provider: "openai" to something else never touches a ciphertext and would otherwise verify
cleanly.
No plaintext tool. The MCP surface has no code path that returns a credential value.
Egress allowlist. A credential can only be sent to hosts its provider declares.
HTTPS only, no redirect following. A 302 to another origin will not replay your
Authorizationheader off-host.SSRF guard. Loopback, private ranges, CGNAT, and link-local (which covers the
169.254.169.254cloud metadata endpoint) are blocked. Address is validated in the DNS lookup the socket actually uses, so DNS rebinding does not open a window.No shell.
runpasses an argv array tospawnwithshell: false.Constructed child environment. The child gets an allowlist of inherited variables plus the injected ones. Your other secrets and keywarden's own passphrase are not inherited.
Output redaction. Every tool result is scanned for known credential values, their base64 and URL-encoded forms, and about a dozen well-known key shapes.
Tamper-evident audit. Every decision, allow or deny, is appended to a hash-chained log.
Whole-file integrity. The vault is MACed including metadata, so a credential cannot be repointed at another provider without detection.
Environment hardening. The server refuses to start when
NODE_TLS_REJECT_UNAUTHORIZED=0,NODE_OPTIONS, orSSLKEYLOGFILEare set. A process whose job is attaching credentials must not start when the request path is under someone else's control.Argument constraints.
argsAllow/argsDenynarrow which invocations of an allowlisted command are permitted, not just which binary.Attenuated grants. Expiring, use-capped, operator-issued capabilities, forgery-resistant via a vault-derived MAC.
Untrusted-data framing. Proxied response bodies are labelled as untrusted content from a named host, so an injected instruction in an API response is presented to the model as data.
Envelope encryption, all from node:crypto, no third-party crypto libraries.
A random 256-bit data key encrypts each field with AES-256-GCM, with the credential's ref and field name as additional authenticated data.
The data key is wrapped by a key derived from your passphrase with scrypt at
N=2^17, r=8(about 128 MiB and roughly a second per attempt).Rotating your passphrase rewraps 32 bytes. It does not re-encrypt every secret.
--passphrase is the strong mode. The MCP server needs KEYWARDEN_PASSPHRASE in its environment
to unlock without a prompt.
--keyfile writes a random key to ~/.keywarden/masterkey so nothing has to prompt. It is
convenient, and it means anyone who can read your home directory can open the vault. Still far
better than plaintext .env files, because the key is in one place, its use is policy-gated, and
every use is logged. On Windows, file modes are set but not enforced the way POSIX enforces
0600. See THREAT_MODEL.md.
keywarden init --passphrase|--keyfile create the vault
keywarden doctor check the install, flag weak settings
keywarden trust [show] re-pin policy.json + providers.json after a change
keywarden grant <ref> ... issue a temporary, use-capped capability
keywarden grant list | revoke <id>
keywarden add <ref> --provider <id> store a credential (prompts for each field)
keywarden add <ref> --url <base> add against any HTTP API without editing providers.json
keywarden list metadata only
keywarden describe <ref> metadata plus how it can be used
keywarden reveal <ref> print plaintext, asks first, always audited
keywarden history <ref> [--rollback N] version history, and undo a rotation
keywarden rm <ref> [--field f] delete
keywarden exec <ref[,ref]> -- <cmd> run a command with credentials injected
keywarden policy show|init|allow|deny|test
keywarden audit [tail|verify]
keywarden passphrase rotate
keywarden providers built-in presets
keywarden mcp-config print the MCP client config
keywarden ui open the browser consoleAnything not built in goes in ~/.keywarden/providers.json. See
docs/PROVIDERS.md.
{
"acme": {
"label": "Acme Internal API",
"hosts": ["api.acme.internal", "*.acme.io"],
"baseUrl": "https://api.acme.io",
"fields": ["token", "tenant"],
"required": ["token"],
"auth": { "type": "header", "name": "X-Acme-Key", "template": "{{token}}" },
"env": { "ACME_TOKEN": "{{token}}", "ACME_TENANT": "{{tenant}}" }
}
}Reading
THREAT_MODEL.md — what is in scope, and what is honestly not
docs/USING.md — install, four ways in, MCP client wiring
docs/PROVIDERS.md — writing a custom provider
docs/RESEARCH.md — the 2026 literature this design draws from
docs/COMPETITORS.md — landscape, and where keywarden is actually different
docs/TEAM.md — multi-developer architecture
docs/HOSTED.md — hosted version plans
CONTRIBUTING.md — building from source, running tests
Hosted
A hosted version is planned for people who want a team vault, browser-based management, and sync across machines, with the same zero-exposure guarantee. Everything in this repository stays MIT and stays fully usable standalone. See docs/HOSTED.md.
License
MIT
Available Tools
6 toolsaudit_tailA
Recent entries from keywarden's tamper-evident audit log: which credential was used, by which capability, against which host or command, and whether it was allowed or denied.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Optional: only entries for this credential ref. | |
| limit | No | How many entries. Default 20, max 200. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the behavioral burden. It discloses that the tool returns recent entries, that the source log is tamper-evident, and what fields an entry contains. It does not explicitly discuss ordering, permissions, or read-only guarantees, but the audit-tail nature and field list make the behavior reasonably transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, tightly written sentence that immediately states the resource and the most important properties of the returned entries. Every phrase earns its place and there is no redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple two-optional-parameter contract and a fully documented schema, the description covers everything needed for both selection and correct invocation. It explains what the tool does, what an entry includes, and the recent-history nature of the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Both parameters (ref and limit) are already fully described in the input schema, so the description adds no additional parameter meaning. The description reinforces the overall audit-log scope but does not go beyond what the schema already provides, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the exact resource: recent entries from the tamper-evident audit log, and enumerates the kinds of information the entries contain. It is easily distinguished from the sibling tools because it is about audit history, not secret lookup, provider listing, HTTP calls, or command execution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The use case is clearly implied: the agent should use this when it needs recent audit log entries about credential use, capability, target host/command, and allow/deny results. It does not explicitly name alternatives or define when-not-to-use conditions, but the context is not ambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_secretB
Metadata for one credential plus how it can be used: whether it can be proxied over HTTP, which hosts it may reach, and which environment variables it maps to when injected.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes | Credential ref, e.g. "openai/prod". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry some behavioral burden. It reveals what information the tool returns at a high level (proxying, hosts, env vars) but does not disclose things like whether it exposes secrets themselves, side effects, or auth requirements. It adds some value beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is one clear sentence, front-loaded with the main intent and then enumerating the specific metadata categories. No waste, though it could be slightly more structured with a colon or list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one well-documented parameter and no output schema, the description covers the main purpose and key return aspects. However, it does not mention whether it returns the secret value itself, which could be relevant for an agent deciding between this and list_secrets. That gap leaves it merely adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already covers the ref parameter with 100% coverage including an example. The description does not add further meaning beyond referring to the credential, so it doesn't push above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: retrieving metadata for one credential and its usage characteristics. It specifies the resource (credential) and the relevant aspects (HTTP proxying, reachable hosts, environment variable mappings). It doesn't explicitly differentiate from sibling tools, but the focus is specific enough to avoid major confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage is for inspecting a credential's metadata and how it can be used. It doesn't explicitly state when to use this over alternatives like list_secrets, nor does it provide exclusions. Context is clear but not fully explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
http_requestA
Make an authenticated HTTPS request using a vaulted credential. keywarden attaches the credential itself; you never see it. The destination must be an allowed host for that credential. Redirects are not followed and non-HTTPS is refused.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes | Credential ref, e.g. "openai/prod". | |
| url | Yes | Absolute https URL, or a path resolved against the provider base URL (e.g. "/v1/models"). | |
| body | No | Request body. An object is JSON-encoded automatically; a string is sent verbatim. | |
| method | No | HTTP method. Defaults to GET. | |
| headers | No | Extra request headers. Auth headers are managed by keywarden and will be rejected here. | |
| timeout_ms | No | Per-request timeout. Default 60000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and excels: it discloses that the credential is attached by keywarden and invisible to the caller, that the host must be allow-listed, that redirects are not followed, and that non-HTTP requests are rejected. This exceeds the typical transparency and preempts common failure modes, giving the agent a realistic picture of runtime behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four concise sentences front-load the core purpose and immediately follow with critical behavioral constraints. Every clause adds unique value—no redundant or fluff content—making it easy to parse and highly digestible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers authentication, host authorization, redirects, and HTTPS enforcement, which are the most critical behavioral aspects. However, since there is no output schema, the absence of any mention of response format or error handling is a minor gap—an agent might wonder what the tool returns. Still, for a generic HTTP client, the description is largely sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all parameters with 100% coverage (ref, url, body, method, headers, timeout_ms). The description adds general behavioral context (auth, host restrictions) but does not elaborate on parameter-specific semantics beyond what the schema provides. This meets the baseline for full schema coverage without adding parametric nuance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool makes an authenticated HTTPS request using a vaulted credential. It differentiates itself from sibling tools (audit_tail, list_secrets, etc.) by focusing on outgoing requests, and the scope is crisply defined: a single request with auth handled internally. The verb 'Make' plus the resource 'authenticated HTTPS request' is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on when to use the tool, emphasizing the need for a vaulted credential and an allowed host, and explicitly notes restrictions (redirects not followed, non-HTTPS refused). It does not explicitly name alternatives or provide when-not-to-use guidance, but given the distinct sibling tools, the context is sufficient. A minor deduction for not explicitly contrasting with alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_providersA
List known provider presets (openai, aws, stripe, ...) with their allowed hosts, expected field names, and env-var mappings. Useful before asking the user to add a new credential.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the burden. The verb 'list' strongly implies a read-only, side-effect-free operation, which is a core behavioral trait. However, it does not explicitly confirm a read-only nature, nor does it disclose any network calls, authentication dependencies, or failure modes, leaving some uncertainty.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that moves from the general operation to specific examples and output attributes. It is highly compact, with no redundant words. Every phrase adds value, and the essential 'List known provider presets' is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description takes responsibility for defining what is returned; it does so by naming permitted hosts, expected field names, and environment variable mappings. It also adds a practical use-case with clear context. It does not mention edge cases like empty providers or exact formatting, but these are not strongly demanded for such a simple read-only tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero properties, so there are no parameters to describe. The description correctly focuses on the operation and its output without mentioning input requirements. According to the baseline rule for zero-parameter tools, a score of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the verb ('List'), the resource ('provider presets'), and the output contents ('allowed hosts, expected field names, and env-var mappings'). It clearly distinguishes itself from sibling secret-related tools by focusing on the provider domain. There is no tautology; it goes beyond merely restating the tool name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear when-to-use signal: 'Useful before asking the user to add a new credential.' This grounds the tool as a prerequisite step in a credential-adding workflow. It does not explicitly name alternative tools or state when-not-to-use, but the given context is sufficient for most cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_secretsA
List every credential in the vault as metadata only: ref, provider, description, which field names exist, when it was last used. Never returns credential values. Start here.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Optional: only secrets carrying this tag. | |
| provider | No | Optional: only secrets for this provider id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and meaningfully discloses that the tool only returns metadata and never credential values. It also surfaces the output fields and last-use flag, which is useful behavioral context. It does not mention edge behaviors such as pagination or permission failures, but those are minor for this tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences front-load the main action and output format, then add the critical safety note and a usage cue. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple optional-filter list tool with no output schema, the description sufficiently covers the return shape, the read-only metadata behavior, and the intended starting point. The schema covers the parameters, and no critical calling information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: both optional filters already have clear descriptions in the schema (filter by tag, filter by provider). The description adds no additional meaning to the parameters, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Describes a specific verb ('List') and resource ('every credential in the vault'), and explains the metadata-only output fields (ref, provider, description, field names, last used). It distinguishes itself from sibling tools by explicitly disclaiming credential values, so an agent can tell it apart from describe_secret.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Start here' gives a clear entry-point cue for exploring the vault, and the metadata-only behavior makes it appropriate for discovery before retrieving a single secret. It does not explicitly name alternatives or state when not to use it, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
runA
Run a local command with one or more vaulted credentials injected as environment variables (e.g. aws, terraform, gh, psql, a build script). The command is executed directly with no shell, so pass arguments as an array. Output is scanned and any credential appearing in it is masked before you see it.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Working directory. Defaults to the server's cwd. | |
| env | No | Extra non-secret environment variables. | |
| args | No | Arguments as separate strings, e.g. ["s3", "ls"]. No shell parsing happens. | |
| stdin | No | Optional text written to the process stdin. | |
| inject | Yes | Credential refs to inject, e.g. ["aws/prod"]. | |
| command | Yes | Executable name or path, e.g. "aws". | |
| timeout_ms | No | Wall-clock limit. Default 60000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the no-shell execution model, the need to pass arguments as an array, and the key credential-masking behavior. It does not mention exit-code or error-handling behavior, but the most important safety-relevant traits are surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences deliver the core behavior, execution model, and output masking with no filler. The most important information is front-loaded and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The schema documents all seven parameters in detail, and the description covers the core execution semantics and output privacy behavior. It stops the short of explicitly describing the full output contract, such as stdout/stderr or exit-code handling, but for its complexity the definition is still reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the structured parameter descriptions already handle most meaning. The prose adds marginal clarification by tying 'inject' to environment variables and 'args' to the no-shell array convention, but it does not substantially go beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action and resource: run a local command with vaulted credentials injected as environment variables. It gives concrete examples (aws, terraform, gh, psql) and clearly positions itself as a local command runner, distinguishing it from the secret-management and HTTP sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: running local CLIs or scripts that need injected secrets. It does not explicitly state exclusions or compare against siblings, but the 'local command' framing and examples make the intended use obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v0.3.0- First observed
audit_tail - First observed
describe_secret - First observed
http_request - First observed
list_providers - First observed
list_secrets - First observed
run
TDQS
Scored across 6 tools
Each tool targets a clearly distinct concern: auditing, listing all secrets, inspecting one secret, listing provider presets, making an HTTP request, and running a local command. Even http_request and run, which both consume credentials, are clearly separated by remote HTTP vs local execution.
list_secrets, list_providers, and describe_secret follow a readable verb_noun pattern, but audit_tail, http_request, and run break it: audit_tail is noun-first, http_request is a noun phrase, and run is a bare verb. The set is understandable but mixes conventions.
Six tools is a well-scoped size for a credential vault/usage server. Each tool covers a meaningful part of the workflow without redundancy or bloat.
The server covers the core credential-usage workflow well: list, describe, use over HTTP, use locally, and audit past use. Credential creation/update/delete is absent, but the descriptions suggest new credentials may be added by the user outside the tool set, so this is a minor workaround gap rather than a fatal one.
Maintenance
Related MCP Connectors
- FullmaktOAuthai.fullmakt
Credential broker for AI agents: scoped, revocable API access with policy enforcement and audit.
Give your AI hands. Identity, credential vault, and API gateway for autonomous agents.
Secrets for developers and agents—secure context and workflows without exposing secret values.
Security gateway for AI agents: policy, approval, and audited execution, no secrets shared.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to securely access authenticated services (HTTP, SSH, SMTP) without exposing secrets, by acting as a server-side proxy that injects authentication.MIT
- AlicenseNot gradedqualityBmaintenanceBounded egress gateway & secret proxy for AI agents and applications, enabling safe credential injection into upstream requests while keeping raw secrets out of LLM prompt contexts.3 npmMIT
- FlicenseNot gradedqualityBmaintenanceEnables agents to securely use credentials for GitHub, Cloudflare, OpenAI, Stripe, and xAI without ever reading the secret values, including credential health, rotation, and audit features.-
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to call external endpoints under per-endpoint policy enforcement, with credentials and personal data kept inside a hardware enclave and every allowed or denied attempt recorded to an immutable audit ledger.2-