Skip to main content
Docs navigation

MCP CLI & reference

The fixed tools, identifiers, and recovery semantics of the emisar MCP server. For client setup, see Connect a cloud LLM.

Calling the endpoint

A custom client uses an agent key with the emk- prefix. Create one from Manage agents & keys. Send JSON-RPC requests to the HTTPS endpoint below. Use the method sequence for your protocol version.

shell
# This legacy-compatible request returns the tool list.
$ curl -X POST https://emisar.dev/api/mcp/rpc \
    -H "Authorization: Bearer $EMISAR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Use MCP tools from the shell

The MCP bridge also exposes all tools as a CLI. This lets any LLM use emisar in scripts too, without the usual limits of the MCP protocol.

Authenticate once — with emisar-mcp auth, or during the bridge install — and direct commands work with no environment exports. The credential is stored in owner-only local state.

Run emisar-mcp by itself to see one command reference grouped into Fleet, Actions, Runbooks, Continuations, Accounts, and MCP client commands. list_tools shows the live server catalog in the same operational groups. MCP clients start this program automatically and send MCP requests through stdin.

shell
$ emisar-mcp auth
$ emisar-mcp list_tools
$ emisar-mcp help find_actions
$ emisar-mcp get_action --help

auth opens the approval page in your browser. Choose an account there. The CLI stores a dedicated key for that account and makes it current. Use auth status to inspect the current account and endpoint without contacting the control plane or printing the key.

list_tools fetches and groups the live catalog. help <tool> shows the server-owned description and top-level arguments. <tool> --help is a shorthand for non-conflicting tool names. Add --json to list_tools or help for exact descriptors and complete input schemas.

Authenticate each account once. accounts list shows the accounts stored on this machine. It marks the current one with a star. accounts use <slug-or-id> changes the current account. A leading --account <slug-or-id> uses another account for one command without changing the current one.

shell
$ emisar-mcp auth
$ emisar-mcp accounts list
$ emisar-mcp accounts use immersive
$ emisar-mcp --account blitz list_runners
Use --json in scripts and LLM workflows

--json makes one logical tool invocation, follows no continuations, and prints the exact structuredContent object with no styling. The transport may resend that identical request once under the same operation ID after a network failure. Put --json last, pass - to read one JSON object from stdin, and parse stdout as JSON. For conditional or mutually exclusive arguments, use help <tool> --json and treat that complete schema as authoritative.

Fleet#

These commands cover fleet inventory. Their default output is written for a person scanning a terminal: runner records and compact pack summaries. Add --json to receive the exact MCP structuredContent object instead.

  • list_runners shows connectivity, hostname, group, labels, packs, issues, and exact runner_ref values. JSON arguments can filter by status, runner name/group/host text, runner, pack, action, or issues.
  • list_packs shows trusted versions, availability, action counts, issues, and exact pack_ref values. The default includes executable packs; use availability: "all" to diagnose trusted unavailable packs.
shell
$ emisar-mcp list_runners
$ emisar-mcp list_runners '{"statuses":["connected"]}'
$ emisar-mcp list_packs
$ emisar-mcp list_packs '{"availability":"all"}'

Actions#

find_actions accepts a plain-text task and shows ranked matches. get_action shows the selected action's side effects, trusted arguments, and compatible runner refs. recent_runs and get_operation provide run history and mutation recovery.

Human run_action prints the operation ID, then follows only exact wait_for_run continuations tied to the returned runs. It waits on several runners concurrently and shows approvals, terminal status, exit codes, and output. Ctrl-C stops waiting and exits 130; it does not cancel the action. The diagnostic prints a get_operation command for later recovery.

shell
$ emisar-mcp find_actions "postgres replication"
$ emisar-mcp get_action '{"action_id":"postgres.status","pack_ref":"postgres@1.2.0/sha256:..."}'
$ emisar-mcp recent_runs '{"scope":"own","limit":10}'
$ emisar-mcp get_operation '{"operation_id":"op_..."}'

Runbooks#

list_runbooks shows live releases, unpublished changes, and workflow size. get_runbook shows inputs, stages, and action steps. Draft commands show the content digest, current live release, and review link.

Human execute_runbook follows only continuations tied to the returned execution, waits through approval or expiry, and retrieves the available output for each action. It prints up to 16,384 characters per action and links to the run page when more remains. Ctrl-C stops observation only. Add --json when a script or LLM should receive the original execution response and decide whether to call wait_for_run itself.

Call an exact tool name with one JSON object. Omit the object when the tool accepts {}, or pass - to read it from stdin. Stdin keeps operational details out of the process list and works cleanly with JSON-producing tools such as jq. Put --json last when a script needs the exact structuredContent object.

shell
$ query='diagnose postgres replication'
$ jq -cn --arg query "$query" '{query:$query}' \
    | emisar-mcp find_actions - --json >actions.json
$ jq -e '.candidates' actions.json

A successful tool call exits 0 and writes readable text, or exact JSON when --json is present. Tool, MCP, authentication, and post-send transport failures exit 1. Invalid commands or JSON exit 2. In JSON mode, when the CLI cannot be sure whether the server received a mutation, stdout includes data.operation_id. Recover it with get_operation before sending new work. Human run_action exits 1 for any terminal status except success. Human execute_runbook exits 1 for halted or cancelled. Policy, approvals, signed dispatch, and audit still apply.

Tool and MCP error objects stay on stdout in the selected format, so a script can read recovery data such as data.operation_id. A safe local diagnostic may also appear on stderr. Configuration and usage failures write their diagnostic to stderr. Color appears only in a terminal; pipes and redirected output stay plain. Set NO_COLOR to turn terminal color off. --json output on stdout never contains styling.

When both authentication environment variables are absent, direct commands use the current account. A leading --account <slug-or-id> selects another stored account for that command. Use accounts list --json to see immutable account IDs. Setting EMISAR_URL and EMISAR_API_KEY together overrides it for that command. Setting only one is an error. Do not combine the pair with --account. Stdio MCP clients never use direct-CLI account storage. Run emisar-mcp auth and choose the account again if its credential expires or is revoked. Revoke connected keys from AI agents.

The local auth, accounts, help, and list_tools commands do not hide server tools with the same names. Prefix an exact tool call with --, for example emisar-mcp -- help '{}'.

MCP clients#

connect detects the AI clients installed on this machine and writes the emisar server into each one you choose; an already-connected client is left alone. disconnect removes that entry and does not change anything else in those files.

  • --client <id> names one client; repeatable. --all takes every detected client without asking.
  • --auto-permit (connect only) also turns off the client's own "allow this tool?" prompt for the emisar server alone — emisar still decides every call server-side. Claude Code, Gemini CLI, Codex CLI, and Grok CLI support this per-server setting.
  • --forget (disconnect only) also deletes the stored direct-CLI accounts. A key removed from a config keeps working until you revoke it under AI agents.
shell
$ emisar-mcp connect --all --auto-permit
$ emisar-mcp disconnect --client cursor

Protocol methods

emisar serves three protocol revisions on one stateless endpoint — it does not issue an Mcp-Session-Id or require sticky routing.

Revision Start Other methods Cancellation
2026-07-28 server/discover tools/list, tools/call No protocol cancellation method.
2025-11-25
2025-06-18
initialize ping, tools/list, tools/call notifications/cancelled stops observation and does not send a response.

A 2026-07-28 request declares its version in _meta. It also sends MCP-Protocol-Version and Mcp-Method headers. A tools/call request also sends Mcp-Name. Modern results include resultType and cache hints.

Request IDs are strings or integers and are returned with the same JSON type. A frame without an ID is a notification, and a mutation sent as one never runs — a mutation needs a request ID for safe recovery.

Thirteen fixed tools

Actions are data, not MCP tool descriptors. Runner and pack changes appear in discovery results. Clients never need a hand-maintained action allowlist and never load hundreds of action schemas during setup.

Tool Purpose
list_packs List currently trusted in-scope packs with bounded action summaries and deployment issues.
list_runners Inspect runner connectivity, compatibility, and exact runner refs.
find_actions Find a bounded set of actions by task or exact identifiers.
get_action Read one immutable action contract and its compatible runners.
run_action Dispatch one exact action to one or more selected runners.
get_operation Recover one exact mutation after an ambiguous response.
wait_for_run Wait for one run to change or reach a terminal state.
recent_runs Inspect scoped run history with exact identity filters.
list_runbooks List every runbook with its live release and any unpublished change.
get_runbook Read one runbook's live release, or its unpublished change.
execute_runbook Execute the live release, or an explicitly allowed unpublished change.
create_runbook_draft Start a new runbook as an unpublished change.
update_runbook_draft Replace a runbook's unpublished change without changing its slug.

Discovery

Start broad only when the task needs it. list_packs gives a bounded overview. find_actions ranks candidates. get_action returns the exact argument schema and the current compatible runner refs. Use list_runners for fleet diagnosis or target selection. Pack and runner pages default to 15 items. Continue a list by passing the previous response's next_cursor (find_actions returns a ready-to-send next call), and a cursor is bound to the identical query — a mismatched one is rejected.

availability: "executable" is the normal path and omits capabilities that cannot run anywhere in scope. availability: "all" is diagnostic: it preserves trusted but unavailable packs and actions together with deployment issues such as no connected runner, a missing executable, or a descriptor mismatch. Pending, rejected, revoked, and retirement-blocked pack refs are operator-only facts that discovery omits — when an expected ref is absent, review it in Packs.

A pack_ref has the immutable form pack@version/sha256:hash. A runner_ref has the identity-bound form name~sha256-prefix. Copy both exactly from discovery: a reconnect or reinstall that reuses the same external ID keeps the ref, while a new external ID or a pack change can make a selection stale.

Running an action

run_action accepts one explicit execution intent:

Field Requirement Meaning
action_id Required Exact action returned by get_action.
pack_ref Required Immutable pack generation returned by discovery.
runner_refs Required One to sixteen distinct, explicit targets.
args Required One JSON object validated against the trusted action schema.
reason Required Operator-facing audit reason for this execution.
evidence Optional What you already observed that makes the action necessary — prior findings or run ids.
expected Optional The outcome you expect if it works. It is stored with the run and shown to approvers.
wait Optional Duration string: "0", "1s"–"60s", or "1ms"–"60000ms". The default and maximum are 60s.

Dispatch preflight re-resolves the complete target set, pack trust, descriptor, schema, policy, certificate window, and signature requirement, and creates the complete fan-out or nothing — it never silently drops a stale target. Policy can still produce a mix of allowed, pending-approval, and denied runs inside the accepted operation. A parked run is not an error: it comes back in a successful response with run status pending_approval, an approval URL, and a wait_for_run continuation — wait on it rather than treating it as a failure.

Operations and recovery

Every run_action, execute_runbook, create_runbook_draft, and update_runbook_draft receives a private operation_id. The stdio bridge derives it from its private process nonce and request sequence. For native HTTP clients, the portal derives it from the exact request and credential lineage. Automatic rotation successors share that lineage. The portal reserves the operation ID in the same transaction as the mutation. Repeating the same request and facts returns the original resource; changed facts conflict. Models never create operation identifiers.

A successful mutation returns its operation ID. If the bridge loses an HTTP response, its correlated JSON-RPC error includes that same ID. After a mutation, pass it to get_operation before deciding whether to issue new work. Read calls retry normally. Run history is for investigation — it is not a substitute for exact operation recovery.

Waits and cancellation

run_action waits up to 60 seconds. wait_for_run waits up to 60 seconds and returns the current state when its deadline expires. One credential lineage can hold eight waits per portal node; the stdio bridge keeps up to eight requests in flight on a 90-second HTTP deadline, and other calls stay responsive during a wait. Legacy clients can also use ping. Cancellation stops observation only — it does not undo committed infrastructure work.

Runbooks and signing

A runbook is one slug carrying a live release, slug@N, and at most one unpublished change. Discovery returns the live release by default. To edit an existing runbook, read it, then call update_runbook_draft with the definition_sha256 you read. The slug never changes, the edit lands as the runbook's one unpublished change, and a concurrent write answers draft_changed instead of being overwritten.

Execution runs the live release. An older slug@N answers not_live rather than silently running current content. An unpublished change never enters ordinary discovery or default execution. Read it with status: "draft", then pass the slug to execute_runbook with allow_draft: true and the exact definition_sha256 you consent to run. A draft test uses the same target, trust, policy, approval, scheduler, runner, and audit path as a live execution — it can cause the actions' real effects, and it publishes nothing: publication remains a human action in Runbooks.

A definition can contain 32 inputs, 16 stages, and 16 target refs per step within 64 KiB. A resolved execution can contain 256 items. Execution returns after the durable execution and its initial stage state commit. The response groups exact items under stages and shows extracted output and condition evidence, wait state, stable blocking reason, and only the latest physical attempt. Follow its wait_for_run continuation while it remains active. Use recent_runs for paginated attempt history.

Customer-CA signing currently protects only run_action. A runbook that targets a signature-enforcing runner fails closed with signed_runbook_unsupported.

Errors

Code Meaning Next step
target_contract_changed The selected action, pack, or runner generation is stale. Call get_action again and make a fresh selection.
action_unavailable No currently visible exact action contract is executable. Follow the returned list_runners continuation to see why no runner can execute it.
operation_conflict One operation ID was reused with different facts. Treat it as a security error. Do not retry.
signed_runbook_unsupported A runbook includes signature-enforcing targets. Use individually signed run_action calls.

These codes are the contract. When you have a symptom instead of a code — a client that cannot connect, an outdated bridge, a refused tool call — start from troubleshooting, which routes back here once it identifies the problem.

Approval gates, denials, decisions, and terminal results are recorded. See the audit trail and policies & approvals.

MCP methods and tool inputs are v1 compatibility surfaces. Read Compatibility and deprecation.

Last reviewed August 23, 2026