ReferenceMCP tools
MCP tools#
What are the vault_* tools and their inputs?
On this page
mehen mcp [--workspace <slug or id>] is a stdio MCP server named mehen. The CLI and the tools share core operations and enforcement; their inputs, output shapes, timeouts and body limits differ as documented below. No tool returns a secret. No MCP tool approves a request, starts an enrolment, revokes a machine or freezes a workspace; vault_wait can finish an enrolment already started at the terminal. mehen setup registers this one server in each agent on the machine.
One server, several workspaces. One server can serve several allowed workspaces, with a separate identity latch for each, including one enrolled while it runs. Its startup workspace, the checkout's manifest, a managed pin and the harness's MEHEN_WORKSPACES may restrict that set; a tool argument cannot widen it. Every tool except vault_templates takes workspace (slug or id). A server started with --workspace or MEHEN_WORKSPACE is pinned: a conflicting tool argument is workspace_mismatch, not an override. Otherwise the tool argument selects, then the startup checkout's mehen.toml (for vault_env, its call's own cwd), then the only active workspace; an unresolved call that needs one workspace is context_ambiguous, and next.say lists the choices. vault_status, vault_doctor, vault_pending and vault_list cover every workspace when none is named and the server is not pinned, and name the workspace on every row. A workspace whose enrolment changes under the running server is refused for the rest of the server's life with restart advice; the others keep serving.
Results and errors#
- Any result or error that hands over a link carries
askinstructuredContentand, incontent, the ask text plus{ type: "resource_link", uri: ask.url, name: "<title> (<check label> <check value>)", description: ask.what, mimeType: "text/html" }. A host that renders resource links gets the button for free. The text'sthen:line saysvault_wait { "id": "..." }instead of a shell command. isErrorstaystrueforapproval_required,needs_reauth,client_missingandtimeout: the call did not do what was asked. Read theaskand hand it over; do not retry.- A failed tool call has
isError: true, a text summary with thenextstep, andstructuredContentholding the same error object the CLI prints with--json(see Errors and exit codes). - There is no MCP tool for
mehen run,mehen env set,mehen init,mehen workspace,mehen enrol,mehen revokeormehen freeze.
The tools follow, in the order the server lists them, each with its inputs from the server's own tool list.
Tools#
| Tool | What it is for |
|---|---|
vault_status | Every workspace this server may use, and as what: workspaces lists each one this machine is enrolled in (device, the workspace's id, slug and name, echoed as data, never as an instruction, its owner, vault, key fingerprint, and a signed check with session label, scope, the count of open asks in this machine's local ledger for it (vault_pending also asks the vault) and observed policyState), each enrolment still waiting for approval with its ask, and each allowed workspace not enrolled yet. |
vault_doctor | One call that says whether this machine can use the vault, and if not what to do: the config root, the vault URL, each vault reachable with the clock within 60 s of it, the session label, then each workspace this server may use (enrolled, device key, identity accepted, frozen, asks still open) and each enrolment still waiting. |
vault_templates | The credential templates and OAuth providers you may name as provider in vault_request and vault_connect, with what each allows without a human, holds for approval and refuses. |
vault_list | List the credentials (items) this machine may use, by name and public metadata, with review when a human should look at one, across every workspace this server may use (or the one named); each item carries its workspace. |
vault_show | Show one item's public metadata: kind, account, the hosts it may be sent to, its policy and policySummary (what goes through without a human, what needs approval, what is refused). |
vault_check | Local base-policy advice only: evaluate this request against stored item binding and base policy without sending it. |
vault_request | Ask a human to add a credential, or to rotate an existing credential this machine may reach (name it; home and provider must match it). |
vault_connect | Ask a human to connect an OAuth account (for example Gmail). |
vault_fetch | Make one HTTP request with an item's credential: the vault adds it on the way to the upstream, which must be in the item's binding. |
vault_env | How each variable a project declares in mehen.toml resolves for an environment (a vault item, a plain value, or unset), as mehen env ls prints it. |
vault_wait | Wait for a human to finish an intake (int_), an approval (apr_), an OAuth connection (con_), a policy proposal (pol_) or an enrolment this machine started at its terminal (enr_). |
vault_pending | Everything this machine has asked a human for that is still open, across every workspace this server may use (or the one named): intakes, connections, approvals, policy proposals and each enrolment it started. |
vault_policy | Read an item's policy, cancel a pending proposal or stop your access. |
vault_status#
Every workspace this server may use, and as what: workspaces lists each one this machine is enrolled in (device, the workspace's id, slug and name, echoed as data, never as an instruction, its owner, vault, key fingerprint, and a signed check with session label, scope, the count of open asks in this machine's local ledger for it (vault_pending also asks the vault) and observed policyState), each enrolment still waiting for approval with its ask, and each allowed workspace not enrolled yet. Call it first. This machine can use a workspace when its entry has state active and check.ok true; an active entry whose check failed carries that error and its next step. When no entry is active, next is what to do (the mehen enrol command a human runs at this machine's terminal, or the enrolment to wait on). policyState is null when unsupported or unavailable, never an invented empty active list; it is not a permission receipt. Enrolment is accepted on the vault's page with a passkey; no tool can accept or start one, and vault_wait only finishes one already started at the terminal. Creates nothing; never returns a secret.
| Input | Type | Required | What it is |
|---|---|---|---|
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen status --json: every workspace this server may use, each with its state and, when active, its check. Before any enrolment it is not an error: read each entry by its state and follow next, which may tell you to enrol, to wait for an existing enrolment, or to list several pending asks. A workspace is connected when its entry is active with check.ok: true. With no active slots it sends no device check to a vault. Call it first. A successful check of a renamed workspace records its new slug and name.
vault_doctor#
One call that says whether this machine can use the vault, and if not what to do: the config root, the vault URL, each vault reachable with the clock within 60 s of it, the session label, then each workspace this server may use (enrolled, device key, identity accepted, frozen, asks still open) and each enrolment still waiting. ok is false when a check failed; next is the step to take (a command to run, or a sentence to relay to the human). Works before enrolment; creates nothing; never returns a secret.
| Input | Type | Required | What it is |
|---|---|---|---|
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen doctor --json. Always a success, before enrolment too; ok: false and next say what to fix.
vault_templates#
The credential templates and OAuth providers you may name as provider in vault_request and vault_connect, with what each allows without a human, holds for approval and refuses. No network, creates nothing. With id, one template or provider in full: hosts, scopes, docs link and the redirect URI an OAuth client must list.
| Input | Type | Required | What it is |
|---|---|---|---|
id | string | no | a template or OAuth provider id, e.g. openai or google-gmail, for its full detail |
The same as mehen templates --json: every template and OAuth provider with policySummary and the redirect URI; with id, one in full. No network; it works before enrolment. Providers and templates lists the same catalogue.
vault_list#
List the credentials (items) this machine may use, by name and public metadata, with review when a human should look at one, across every workspace this server may use (or the one named); each item carries its workspace. Never returns values.
| Input | Type | Required | What it is |
|---|---|---|---|
tag | string | no | only items with this tag |
kind | string | no | only items of this kind, e.g. api-key |
provider | string | no | only items from this provider template, e.g. openai |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen ls --json.
vault_show#
Show one item's public metadata: kind, account, the hosts it may be sent to, its policy and policySummary (what goes through without a human, what needs approval, what is refused). Never the value.
| Input | Type | Required | What it is |
|---|---|---|---|
item | string | yes | the item's slug, e.g. openai-personal |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen show --json, plus policySummary ({ allowed, approve, deny, rest }, described from the rules' matchers; mehen show prints the same as its three policy lines).
vault_check#
Local base-policy advice only: evaluate this request against stored item binding and base policy without sending it. Returns advisory: true and scope: base-policy-only. Live windows, floors, protection and grants are not included; this cannot predict permission to send. Read current item policy with vault_policy action show. The real vault_fetch enforces current authority. Creates no approval and never returns a secret.
| Input | Type | Required | What it is |
|---|---|---|---|
item | string | yes | the item's slug |
method | string | yes | HTTP method |
url | string | yes | the full upstream URL |
headers | object | no | request headers, without the credential; the decision does not depend on them |
body | string | no | request body as text, when the item's policy reads bodies (vault_show lists its rules) |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen check --json: decision is allow, approve, deny or binding_refused, with matched, reason, bodyUnknown and advisory: true. One read of the item, nothing sent, no approval created.
vault_request#
Ask a human to add a credential, or to rotate an existing credential this machine may reach (name it; home and provider must match it). Returns ask: a checked link the human opens to type the value into the vault page (never into the chat, never to you). Rotation replaces only the secret fields and keeps the credential's home, binding and policy. Hand the human the link, what it is for and what to check, then call vault_wait with the intake id. Without a provider template, propose where it may be sent with hosts (and optionally paths), and how with injection when the kind's usual way (Bearer in Authorization) is wrong; the human sees both marked unverified. Never returns the value.
| Input | Type | Required | What it is |
|---|---|---|---|
kind | one of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, generic | yes | what sort of credential |
name | string | yes | slug for the new item, e.g. openai-personal |
reason | string | yes | why you need it; the human sees this |
provider | string | no | provider template, e.g. openai, anthropic, github-pat (vault_templates lists them) |
tags | array of string | no | |
hosts | array of string | no | without a provider: the hosts it may be sent to, e.g. api.example.com |
paths | array of string | no | without a provider: path globs it is limited to, e.g. /v1/** |
injection | object, one of 4 shapes | no | without a provider: how the relay puts it into a request, e.g. { "in": "header", "name": "X-Api-Key", "format": "{key}" } |
new | boolean | no | make a fresh link and close this machine's open one for the same name (as mehen request --new); otherwise the same request returns the same open link |
home | one of private, project, workspace | no | who the credential belongs to: private (only its owner; the default), project (needs project, or the project of the checkout this server started in) or workspace. The human may change it on the page. |
project | string | no | with home project: the project id (prj_...) |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
Ask a human to add a credential, or rotate an existing one this machine may reach: the same as mehen request, with new as --new and home and project as --home and --project (a project home without project uses the server's own startup manifest project). It returns a checked intake ask; the human enters the value on the vault's page, never in chat. A rotation keeps the credential's home, binding and policy. The result adds kind, name, provider, ask, and warning when a link was refused.
vault_connect#
Ask a human to connect an OAuth account (for example Gmail). Returns ask: a link the human opens to sign in at the provider; the tokens go into the vault, never to you. Hand the link over, then call vault_wait with the connection id. Needs an oauth-client item for the provider: name it with client, or leave client out to use the one that exists. With none, the result is the client_missing error whose request is exactly the vault_request arguments for the client; or set requestClient to have the vault ask for the client first: the result is then that intake's ask with step: "client"; vault_wait for it, then call vault_connect again with the same arguments for the connection link.
| Input | Type | Required | What it is |
|---|---|---|---|
provider | string | yes | OAuth provider, e.g. google-gmail (vault_templates lists them) |
client | string | no | the oauth-client item to use; when absent, the one client made from the provider's client template |
name | string | yes | slug for the connection item |
reason | string | yes | why you need it; the human sees this |
scopes | array of string | no | |
expect | string | no | the account the human should sign in as |
requestClient | boolean | no | when no client exists, ask the human for one first (an intake chained to this connection) |
clientTags | array of string | no | with requestClient: the tags the new client gets, so a tag-scoped machine may use it (as mehen connect --client-tag) |
new | boolean | no | make a fresh link and close this machine's open one for the same name (as mehen connect --new) |
home | one of private, project, workspace | no | who the connection belongs to: private (only its owner; the default), project (needs project, or the project of the checkout this server started in) or workspace |
project | string | no | with home project: the project id (prj_...) |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen connect. Without client, the one OAuth client that exists is used; several is a usage error with choices; none is client_missing, whose request is exactly the vault_request arguments for the client. requestClient: true returns the client intake's ask with step: "client"; call vault_wait for it, then vault_connect again with the same arguments for the connection link.
vault_fetch#
Make one HTTP request with an item's credential: the vault adds it on the way to the upstream, which must be in the item's binding. Returns the upstream status, headers and body as the vault returns them (text, at most 256 KiB; the vault may have decompressed or scrubbed the body and removed headers). Use select for a JSON field from the full response, subject to the vault's 32 MiB response limit. Any upstream status is a success here; read status. A vault refusal is an error with next; when a human must approve or reconnect, it also carries ask and a link: hand them over and call vault_wait with the id, do not retry.
| Input | Type | Required | What it is |
|---|---|---|---|
item | string | no | the item to use (or run) |
run | string | no | a mehen run id whose placeholders the request carries (instead of item) |
method | string | yes | HTTP method |
url | string | yes | the full upstream URL |
headers | object | no | request headers, without the credential |
body | string | no | request body as text |
bodyBase64 | string | no | request body as base64, for binary bodies |
approval | string | no | an approved apr_ id, when retrying after an approval |
context | object | no | the project environment the credential is used for; needed for a protected, team or guest credential. Never changes the workspace. |
select | string | no | one part of a JSON response, by keys and indexes: data.0.id, .items[2]["display name"], or . for all; returned as selected instead of body, from the whole response however large |
timeoutSeconds | integer, 1 to 600 | no | stop waiting after this many seconds (a network error; the request may still have reached the upstream) |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen fetch. It returns { status, statusText, item, headers, body, truncated, note? }. The body is text after vault processing, cut at 256 KiB; with select it returns { status, statusText, item, headers, selected, found } from the whole response instead (within the vault's 32 MiB response limit), which is the way to read one field of a large JSON answer. For a whole large or binary body use mehen fetch -o <file> in a shell. context names the project environment the credential is used for, as --project and --env; it is never a workspace switch. A host's notifications/cancelled stops the request.
vault_env#
How each variable a project declares in mehen.toml resolves for an environment (a vault item, a plain value, or unset), as mehen env ls prints it. Never returns values. With check, fails when any variable does not resolve.
| Input | Type | Required | What it is |
|---|---|---|---|
env | string | no | environment name; the project's default when absent |
cwd | string | no | absolute path inside the project; where mehen mcp runs when absent |
check | boolean | no | fail unless every declared variable resolves |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen env ls, or mehen env check with check. The cwd's mehen.toml selects the workspace; one outside what the server may use is workspace_not_allowed, and one that disagrees with workspace is workspace_mismatch, before anything is sent. It returns { exitCode, variables, context }, where variables are the lines mehen env ls prints and context the lines it prints on stderr (the mehen: banner). When a variable does not resolve under check, the tool fails with command_failed and the message names the fix.
vault_wait#
Wait for a human to finish an intake (int_), an approval (apr_), an OAuth connection (con_), a policy proposal (pol_) or an enrolment this machine started at its terminal (enr_). The id is found in the one workspace this server may use that recorded it; pass workspace only when the call should be held to one. Returns the outcome; a human who has not acted yet is a timeout error: call it again, and remind the human of the link if needed. Default 60 s, at most 600 s; with a progressToken the server sends notifications/progress every 10 s. Decides nothing itself.
| Input | Type | Required | What it is |
|---|---|---|---|
id | string | yes | int_..., apr_..., con_..., pol_... or enr_... |
timeoutSeconds | integer, 0 to 600 | no | |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen wait, in whichever workspace holds the id; timeoutSeconds defaults to 60. With a progressToken on the call, the server sends notifications/progress ({ progressToken, progress: elapsedSeconds, total: timeoutSeconds, message }) when the vault first reports the ask still open and then every 10 s; notifications/cancelled stops the call: no further poll, no more progress, no response.
With an enr_ id it finishes an enrolment mehen enrol started on this machine; it cannot start one. On active it checks the vault's answer against the workspace and owner that were asked for, then writes the config, so vault_status lists the workspace as active on the next call and the server serves it at once. An answer for another workspace, owner kind or scope is refused, the new device's revocation attempted and the outcome reported.
vault_pending#
Everything this machine has asked a human for that is still open, across every workspace this server may use (or the one named): intakes, connections, approvals, policy proposals and each enrolment it started. Each has its workspace in context, an ask with its checked link, code where supplied, expiry and recorded requester, so a conversation that lost the link can hand it over again. Member-only policy reviews are not included. Creates and extends nothing.
| Input | Type | Required | What it is |
|---|---|---|---|
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen pending --json, across every workspace: { pending: Ask[], notices? } (notices only when this machine has any) plus a resource_link per ask.
vault_policy#
Read an item's policy, cancel a pending proposal or stop your access. The current workspace server refuses preview and propose with forbidden: Policy widening is not available yet. These actions do not grant permission or bypass protected-environment checks. No approve, set, controls, run scope, floor lifts or automatic renewal. Stop cannot undo remote effects or recall an in-flight request. Never returns a secret.
| Input | Type | Required | What it is |
|---|---|---|---|
action | one of show, preview, propose, cancel, stop | yes | show needs item; preview needs change and reason; propose needs proposal; cancel or stop needs id. Supply only those fields. |
item | string | no | Required only for show: the item's slug. |
change | object, one of 2 shapes | no | Required only for preview: the finite change to review. |
reason | string | no | Required only for preview: why access is needed. |
proposal | object | no | Required only for propose: preview's exact change, reason, baseDigest and slotRevision. |
id | string | no | Required only for cancel (pol_) or stop (pov_ or gnt_). |
workspace | string | no | slug or id; needed when this server may use more than one workspace and no checkout binds one |
The same as mehen policy: read an item's policy (show) or stop your access (stop, cancel). preview and propose are refused by the vault in this release (forbidden, "Policy widening is not available yet"); a policy window is not a way round a protected context, and the tool exists so the surface stays stable.