# Agent reference. The CLI, in one page.

You don't need to read this. Your agent does. It is also served as [/cli.md](https://emfirge.cloud/cli.md). `emfirge` is a thin client for the hosted engine. It signs in, tokenizes identifiers on your machine, sends one command, and prints the answer as JSON, or as short text with `--human`. The verbs follow an agent's workflow: context, branch, try, check, request, report. `request` is listed but not built yet.

Human version: https://emfirge.cloud/cli/

*Figure 1. The six verbs follow an agent's loop: ask what is true, open a branch, try a change, check it, ask the owner (not built yet), get the hand-back of what was applied. The highlighted verb is the section you are reading.*

## Setup, loop and rules

**Your human gave you emfirge. Set it up with them once, then do the rest yourself.**

You run the commands. Your human does three things only they can do: approve the browser sign-in, create the read-only role in their AWS console, and give you the role ARN. Everything after that is yours.

| Step | Command | Who |
|---|---|---|
| Check it runs | `npx -y emfirge guide` | you (Node.js 20 or later; `-y` skips npx's first-run prompt) |
| Sign in | `emfirge login` | you start it; **your human approves in the browser** (GitHub or Google). It waits 5 minutes. If the browser does not open, show them the address it prints, then wait. |
| No browser (cloud session, CI) | `EMFIRGE_API_KEY` | your human makes a key on their own computer (`emfirge key create`) and sets it in your environment's secret settings. Skip `login`. See [API keys](#keys). |
| Get the role | `emfirge connect` | you run it and **show your human the link**; they create the stack and copy the `RoleArn` from its Outputs. `connect` takes no ARN and does not detect the role. |
| First scan | `emfirge context --refresh --role-arn ARN --region REGION` | you, with the ARN they gave you. Ask which region; there is no default. Keep the ARN: `check --evidence` needs it again. |
| Know the account | `emfirge context inventory` | you |

Not signed in is exit code 2 and the CLI never waits for a browser by itself, so run `login` and wait for your human. Sign-in is kept in `~/.emfirge/credentials.json`; you need your human again only if it expires. The sign-in page is served on `127.0.0.1` of the machine you run on, so it cannot be used from a remote sandbox: there, use an API key ([API keys](#keys)).

### The loop

- `emfirge context inventory`: ask what is true.
- `emfirge branch open --analysis ID --name NAME`: make a safe copy.
- `emfirge try BRANCH ...`: put your change on the branch.
- `emfirge check BRANCH`: read the facts and the unknowns.
- Not what you wanted? Fix your own plan and go back to `try`. `emfirge branch rollback BRANCH` clears the last change.
- `emfirge request`: ask the owner. Not built yet: ask your human in your own channel.
- Apply the change yourself, with your own access. Emfirge never writes to the cloud.
- `emfirge report BRANCH`: the hand-back for what you applied. Then tell your human what changed.

### Rules

- Emfirge never writes to the cloud. You apply your own change, with your own access.
- Facts, not fixes. Emfirge will not tell you what to do. You decide.
- Never apply a change that did not pass. Emfirge is advisory and stops nothing, so this is on you.
- Unknown means not checked. It never means safe. Read every `unknown` entry.
- Names and IDs come back as tokens (`S3_001`, `NAME_003`, `TAG_001`). Pass them back as they are. Emfirge turns them into real IDs on your machine.
- Emfirge keeps no plan text. Apply your own original plan. The hand-back is tied to it by sha256.
- `check --policy` and `check --evidence` show an estimate first and send nothing. Run them with `--accept-estimate ID` (and `--approve` for policy) only after your human agrees.
- Run `npx emfirge@latest` only when emfirge tells you to (exit code 6), never as a habit.

`emfirge guide` prints this guide from the package itself. Add `--human` for short readable output, and `--help` to any verb.

## Install and sign in

**Run it with npx. There is nothing to install. Two of these steps need your human.**

Terminal:

```
npx emfirge login      # sign in with GitHub or Google in your browser
npx emfirge connect    # print the link that creates the read-only role
```

The npm package is `emfirge` and the command is `emfirge`. Node.js 20 or later. It is one file with no dependencies. Agents add `-y` to skip npx's first-run prompt: `npx -y emfirge context inventory`. For a permanent command, `npm install -g emfirge` puts `emfirge` on your PATH.

| Command | What it does |
|---|---|
| `emfirge login` | Sign in with GitHub or Google in your browser. Your human approves it there; waits 5 minutes. Keeps the session in `~/.emfirge/credentials.json`. If `EMFIRGE_API_KEY` is set, it says so and uses the key. |
| `emfirge logout` | Sign out on this device. |
| `emfirge connect` | Print the one-click CloudFormation link that creates the read-only role, with the ExternalId and the next steps. Show the link to your human: they create the stack. When it is ready, they give you the role ARN from its Outputs; use it in `emfirge context --refresh --role-arn ARN --region REGION`. |
| `emfirge connect --link` | Link your saved sign-in to an existing API-key project. Needs `EMFIRGE_API_KEY`. |
| `emfirge key create`, `key list`, `key revoke` | Make, list and revoke API keys for your human's project, for where no browser can open. See [API keys](#keys). |
| `emfirge guide` | Print the agent guide: the loop, the rules, the exit codes. |
| `emfirge --help`, `emfirge help COMMAND`, `emfirge COMMAND --help` | Help, from the server's current command list. |
| `emfirge --version` | Print the version. |

Nothing here asks for AWS access keys. The only thing that reaches the account is the role from `connect`; see [Security & privacy](https://emfirge.cloud/security.md#role). The commands `status`, `privacy`, `tokens` and `purge` belong to the [MCP adapter](#mcp-adapter), not to `emfirge`.

## API keys

**Where no browser can open, your human gives you a key instead of a sign-in.**

A cloud agent session or CI cannot finish `emfirge login`. Your human makes an API key for their own project, once, on their own computer after `emfirge login`, and sets it as `EMFIRGE_API_KEY` in your environment's secret settings. You do not make keys: a call made with a key cannot create one (HTTP 403, exit code 2, `forbidden`).

| Command | What it does |
|---|---|
| `emfirge key create [--name LABEL]` | Make a key for the project. Prints the key once, with `key_id`, `prefix` and `created_at`. Needs a browser sign-in, not a key. A project can hold 10 active keys; the eleventh is exit code 5 (`conflict`). The label is up to 80 characters. |
| `emfirge key list` | The project's keys: `key_id`, `name`, `prefix` (the first 8 characters after `emf_`), `created_at`, `last_used_at` and `active`. Never the key itself. |
| `emfirge key revoke KEY_ID` | Stop that key at once. Get the id from `key list`. |

Where `EMFIRGE_API_KEY` is set, every command sends it and skips browser sign-in; `emfirge login` only says so. `key list` and `key revoke` also work with a key. A key works for the whole project, like the sign-in. It does not create the read-only role: your human still creates it and gives you the role ARN and a region. Never print the key into a chat or commit it.

## Where the commands come from

**The server owns the command list, so a new command works without a new install.**

`emfirge` fetches its command list from the server (`GET /cli/manifest`, public, with no customer data, 3 second timeout), builds its help from it, parses your arguments by it, and sends the request each command describes. If the server cannot be reached, it uses the copy built into the package, and says so when a command is unknown. The copy and the server's list are the same document, pinned by a test.

Only login, logout, connect, guide and `request` are built in. A few manifest commands (`try`, and some modes of `context` and `check`) run code built into the CLI, because they need more than one request, a file or stdin. Run `npx emfirge@latest` only when emfirge tells you to: a command that needs a newer emfirge exits with code 6.

Today the list has 15 commands: `context`, `branch open|fork|list|get|rollback|rollback-to|discard|compare`, `try`, `check`, `report` and `key create|list|revoke`.

## Global options and exit codes

**JSON on stdout. Errors on stderr. One exit code per kind of failure.**

| Flag or variable | Meaning |
|---|---|
| `--human` | Short readable output instead of JSON. |
| `-h`, `--help` | Show help for the command. |
| `--version`, `-v` | Print the version and exit. |
| `EMFIRGE_API_KEY` | An API key made with `emfirge key create`, for a cloud agent or CI where no browser can open. Skips browser sign-in. See [API keys](#keys). |
| `EMFIRGE_BASE_URL` | Backend API URL. Defaults to `https://emfirge.cloud/api`. |
| `EMFIRGE_PRIVACY` | `strict` (default), `balanced` or `off`. Strict tokenizes every recognized AWS identifier before a model sees it. |
| `EMFIRGE_NO_BROWSER` | Set to `1` and `login` does not open a browser; it prints the sign-in address. |

Output is one JSON document on stdout. An error is one JSON line on stderr, `{"error":{"code","message","exit"}}`, and stdout stays empty. Names and IDs in the answer are tokens such as `S3_001`; pass them back as they are and emfirge turns them into real IDs on your machine. Local state lives in `~/.emfirge/`: your sign-in and the token map, which never leaves your machine.

### Exit codes

| Code | Error code | Meaning |
|---|---|---|
| `0` |  | Ok. The command ran. A finding does not change this: `check` and `try` exit 0 whatever they report. |
| `1` | `usage` | A bad command or option, a missing argument, or input the server rejected (HTTP 400 or 422). Also AWS CLI shorthand, and `request` (`not_built`). |
| `2` | `not_signed_in`, `forbidden` | Not signed in (HTTP 401) or not allowed (HTTP 403). Run `emfirge login`. |
| `3` | `not_found` | The branch, analysis or resource was not found (HTTP 404). |
| `4` | `server_error`, `rate_limited` | A server or network error, or a rate limit (HTTP 429). Try again later. |
| `5` | `conflict` | The branch changed since you read it, or 10 branches are already open on one base scan (HTTP 409). Read it again, or discard branches you no longer need, then retry. |
| `6` | `update_needed` | The server's command is newer than this install. Run `npx emfirge@latest`, then retry. |

## context

**Ask what is true before you change anything.**

Synopsis:

```
emfirge context QUESTION [--analysis ID | --branch ID] [--resource ID]
emfirge context --refresh --role-arn ARN --region REGION
emfirge context --findings | --attack-paths | --compliance --analysis ID
emfirge context --simulate "what if ..." --analysis ID
```

| Question | What it answers |
|---|---|
| `inventory` | What exists. |
| `resource` | One resource: its type, tags and relationships. Needs `--resource`. |
| `depends_on` | What a resource depends on. Needs `--resource`. |
| `dependents` | What depends on a resource. Needs `--resource`. |
| `reachable` | What the internet can reach. |
| `access` | Who can access what, from the identity policies Emfirge has collected. |
| `data` | Data stores and their recovery points. |
| `cost` | Monthly list price of what is provisioned. |
| `live` | Recent use. |
| `marks` | Owner tags. `emfirge.md` is not built yet, so tags are all it shows. |
| `baseline` | Counts for the whole snapshot. |

| Flag | Meaning |
|---|---|
| `--analysis ID` | The analysis (scan) to ask about. Defaults to your latest. |
| `--branch ID` | Ask about a branch instead of a scan. Not together with `--analysis`. |
| `--resource ID` | A resource ID or token such as `S3_001`. |
| `--refresh` | Run a fresh scan of your account. Needs `--role-arn` and `--region`. |
| `--findings` | List the findings of a scan. Add `--severity Critical\|Moderate\|Low` to filter. |
| `--attack-paths` | Paths from the internet to inside resources. |
| `--compliance` | CIS AWS Foundations 1.5 or SOC 2 status. Add `--framework cis-aws-1.5\|soc2` to filter. Controls Emfirge does not evaluate are `not_evaluated`, never `pass`. |
| `--simulate "…"` | Walk a what-if kill chain; the value is the question. |

Use one mode at a time. `--findings`, `--attack-paths`, `--compliance` and `--simulate` need `--analysis`. Every answer has `facts`, `known` (what was checked) and `unknown` (what was not, and why).

Example (abridged output from the engine's synthetic test account):

```
$ emfirge context data
{
  "question": "data",
  "source": { "kind": "scan", "analysis_id": "ANALYSIS_1", "branch_id": null,
              "collected_at": "2026-10-01T00:00:00Z", "region": "ap-south-1" },
  "facts": [
    { "resource_id": "NAME_002", "resource_type": "rds_instance",
      "has_recovery_point": false, "recovery_resource_ids": [], "recovery_kinds": [] },
    { "resource_id": "NAME_004", "resource_type": "rds_instance",
      "has_recovery_point": true, "recovery_resource_ids": ["NAME_005"],
      "recovery_kinds": ["rds_snapshot"] }
  ],
  "known": [ { "topic": "data_stores", "detail": "5 data stores assessed" } ],
  "unknown": [ { "topic": "data_contents", "reason": "what a data store holds is not read; …" } ]
}
```

### For agents

- Run `context` first; do not infer from names. Facts come from your account's last scan, with what was checked and what was not.
- Read `unknown`. Unknown means not checked. It never means safe.
- `source.collected_at` is the age of the answer. Run `--refresh` before a change that depends on fresh state. A scan counts against a daily limit per AWS account; the reply says how many remain.
- `--refresh` scans through the read-only role. `check --policy` and `check --evidence` also use it, and only after the owner accepts a cost estimate.

## branch

**A workspace for a change. Open, fork, compare, roll back, discard.**

Synopsis:

```
emfirge branch open --analysis ANALYSIS --name NAME
emfirge branch fork BRANCH --name NAME [--revision REVISION]
emfirge branch list [--analysis ANALYSIS]
emfirge branch get BRANCH
emfirge branch rollback BRANCH [--revision REVISION] [--expected-count N]
emfirge branch rollback-to BRANCH --count N [--revision REVISION]
emfirge branch discard BRANCH [--revision REVISION] [--expected-count N]
emfirge branch compare BRANCH BRANCH [BRANCH ...]
```

| Subcommand | What it does |
|---|---|
| `open` | Open a branch: a safe copy of a scan. With no changes it equals live. Never touches your cloud. |
| `fork` | Copy a branch, with its changes, under a new name. |
| `list` | List your branches. `--analysis` limits it to one base scan. |
| `get` | Read one branch and its ordered changes. Never the base snapshot. |
| `rollback` | Remove the most recent change. On a branch with no changes it does nothing. |
| `rollback-to` | Keep the first `--count` changes and drop the rest. `--count 0` returns to the base. |
| `discard` | Discard the branch. It deletes the branch and everything stored with it (plans, evidence, policy checks). Nothing in your cloud changes. |
| `compare` | Compare two or more branches. |

`--revision` is the `branch_revision` you last saw (a SHA-256). `--expected-count` is the change count you last saw. A stale one is rejected with HTTP 409, which is exit code 5. By default at most 10 branches can be open on one base scan; past that the server answers HTTP 409, which is exit code 5: discard branches you no longer need.

Example:

```
emfirge branch open --analysis ANALYSIS_ID --name close-ssh
emfirge branch fork BRANCH_ID --name close-ssh-v2
emfirge branch compare BRANCH_ID BRANCH_ID_2
```

### For agents

- One idea per branch. To try a different plan, `fork` or open a new branch instead of stacking a contradicting change.
- Several agents on one base: pass `--revision` from `branch get`. Exit code 5 means someone else changed the branch; read it again.
- Only open branches take changes. Clean up with `discard` when you are done.

## try

**Put a change on a branch, in whatever form you already have it.**

Synopsis:

```
emfirge try BRANCH --typed JSON
emfirge try BRANCH --aws-cli "aws ec2 ..." [--aws-cli "aws ..."]
emfirge try BRANCH --aws-api FILE|JSON|-
emfirge try BRANCH --terraform FILE|JSON|-
emfirge try BRANCH --cloudformation FILE|JSON|-
emfirge try --verify-fix --rule RULE --resource ID --analysis ID
```

| Flag | Meaning |
|---|---|
| `--typed JSON` | One typed change as JSON: `{op, resource_type, resource_id, fields}`. `op` is `add`, `modify` or `delete`. Add `branch_revision` or `expected_change_count` to refuse a stale branch. |
| `--aws-cli CMD` | An AWS CLI command, written out in full. Repeat the flag for several, or pass a JSON list. |
| `--aws-api` | AWS API calls as JSON: `{"format":"aws-api-calls/1","calls":[...]}`. |
| `--terraform` | The output of `terraform show -json PLAN`. Emfirge never runs the plan. |
| `--cloudformation` | The output of `aws cloudformation describe-change-set`. |
| `--verify-fix` | Model the fix for one finding on a copy of a scan, with no branch. Needs `--rule`, `--resource` and `--analysis`. |

Give exactly one input. A JSON input is a file path, inline JSON, or `-` for stdin. AWS CLI shorthand (`--target Arn=…,RoleArn=…`) is refused before anything is sent, with exit code 1; pass the value as JSON. Emfirge keeps only a SHA-256 of a plan, never its text, so apply your own original plan.

For the four plan formats the answer lists what was **applied**, **rejected** (impossible input or a value AWS would reject), **unmodeled** (read but not modeled, so the verdict gets stricter) and **unknown_fields** (a value the plan left out, never guessed). It also carries a `verdict` (`pass`, `warn` or `block`, with reason codes), a `verdict_id`, the `branch_revision` and the hand-back. The resource types you can change are on [Coverage](https://emfirge.cloud/coverage.md#resources).

Example (abridged output from the engine's synthetic test account):

```
$ emfirge try BRANCH_ID --aws-cli "aws ec2 authorize-security-group-ingress --group-id SG_001 --protocol tcp --port 22 --cidr 0.0.0.0/0"
{
  "plan_id": "64ded399-…",
  "input_sha256": "7304d5f4…",
  "applied": [ "calls[0] ec2.AuthorizeSecurityGroupIngress" ],
  "rejected": [], "unmodeled": [], "unknown_fields": [],
  "verdict": {
    "decision": "block",
    "reasons": [
      { "level": "block", "code": "introduced_critical_finding", "resources": ["SG_001"] },
      { "level": "block", "code": "introduced_critical_exposure", "resources": ["EC2_001"] },
      { "level": "warn", "code": "new_exposure", "resources": ["EC2_001"] }
    ]
  },
  "verdict_id": "32b82c7e…",
  "branch_revision": "dc62be73…"
}
```

### For agents

- Send the change you were already going to run. Do not translate it into the typed form.
- If the answer lists an unmodeled change, read it: the verdict cannot pass. Do not retry the same change.
- Use the exact ID or token you were given. `emfirge context resource --resource ID` first when you are unsure.

## check

**Ask what the branch changed. Six answers, each with what was checked and what is unknown.**

Synopsis:

```
emfirge check BRANCH
emfirge check BRANCH --verdict | --diff
emfirge check BRANCH --policy [--approve --accept-estimate ID]
emfirge check BRANCH --evidence [--source S] [--accept-estimate ID --role-arn ARN]
```

| Flag | Meaning |
|---|---|
| (none) | The six answers (data, exposure, money, availability, control, outside world), with `checked` and `unknown` for each, plus `changed_settings`. No verdict. |
| `--verdict` | The older verdict: `pass`, `warn` or `block`, with reason codes. |
| `--diff` | The diff against the base scan. |
| `--policy` | Ask AWS IAM Access Analyzer about changed policies. It costs money (about $0.002 a policy, billed to your AWS account), so it prints an estimate first and sends nothing. Run it with `--accept-estimate ID` and `--approve` once the owner agrees. |
| `--evidence` | Read CloudTrail and CloudWatch use of deleted resources. Estimate first. `--source cloudtrail_events` or `cloudwatch_metrics`, repeatable. Run it with `--accept-estimate ID --role-arn ARN`. |

A check never says pass, warn or block on its own. Each answer lists **facts** (what changed), **checked** (what was looked at) and **unknown** (what was not, and why). `changed_settings` lists every setting that changed, by name and never by value: **judged** by a check, or named as **not judged**. Not judged is not safe. How to read it is on [How it works](https://emfirge.cloud/how-it-works.md#checks).

Example (abridged output from the engine's synthetic test account):

```
$ emfirge check BRANCH_ID --human
Branch check: BRANCH_ID (2 change(s))
- data: 0 fact(s), 4 unknown
- exposure: 1 fact(s), 1 unknown
    fact: {"resource_id":"EC2_001","resource_type":"ec2_instance","change":"newly_exposed","protocol":"tcp","ports":[22,22],"so...
    unknown (not checked, not safe): {"topic":"observed_traffic","reason":"observed traffic, host firewalls and application-level controls are not collect...
- money: 0 fact(s), 1 unknown
- availability: 0 fact(s), 3 unknown
- control: 0 fact(s), 2 unknown
- outside_world: 0 fact(s), 2 unknown
changed settings: 3 (1 judged by a check, 2 not judged)
Changed, not judged:
    security_group SG_002: attached_instances
    security_group SG_002: attached_to
```

### For agents

- Read the facts, then read the unknowns and the changed settings. A check that did not run did not find nothing.
- A fact is about your change. Change the plan and retry on a new branch; do not argue with it or route around it.
- `--policy` and `--evidence` show an estimate first and send nothing. Run them only after the owner agrees.

## request

**Ask the owner. Not built yet.**

Synopsis:

```
emfirge request BRANCH [--reason TEXT]
```

The command is listed in `emfirge --help`, but it is planned for a later version. It makes no request: it exits with code 1 and a JSON error, `not_built`. Until it exists, ask the owner yourself, then use `emfirge report` after you apply.

### For agents

- Do not wait on `request`. Ask the owner in your own channel when a check shows facts they should see.

## report

**Say what you applied. For now it returns the hand-back, and can verify it.**

Synopsis:

```
emfirge report BRANCH [--plan PLAN] [--verify]
```

| Flag | Meaning |
|---|---|
| (none) | The hand-back of the branch: the exact AWS API calls its typed changes stand for, their `input_sha256`, the base scan, the `branch_revision`, the `verdict` and a `verdict_id`. |
| `--plan PLAN` | The hand-back of one plan from `emfirge try`. |
| `--verify` | Send the hand-back back to the server, which checks the binding. |

The hand-back ties the exact calls to the verdict they were judged with. `--verify` answers `{"ok": true}`, or fails with exit code 5 and one `reason_code`: `unknown_plan`, `input_hash_mismatch` (these are not the calls that were judged), `branch_revision_changed`, `base_snapshot_changed` or `verdict_changed`. It checks the binding only. It does not read CloudTrail, and Emfirge never applies anything.

### For agents

- Apply your own original change with your own access, then run `report` so the record shows what was judged.
- If `--verify` names a mismatch, tell the owner. Do not edit the calls to make it match.

## MCP adapter

**The same engine, for agents that speak MCP.**

**Note:** the npm adapter (`@emfirge/mcp` 0.2.3) is behind the repo (0.2.9) and an update is coming. The CLI is the supported path today.

`@emfirge/mcp` exposes 27 tools over stdio, so a client that cannot run a shell can still use emfirge. The CLI is built on the same handlers, so both paths share one engine and one privacy layer. The tool names are unchanged. It also carries the local commands the CLI does not have.

| Command | What it does |
|---|---|
| `npx @emfirge/mcp install` | Wire emfirge into the MCP clients it detects. |
| `npx @emfirge/mcp uninstall` | Remove it from those clients. |
| `npx @emfirge/mcp status` | Show wired clients, the backend URL and the privacy mode. |
| `npx @emfirge/mcp privacy [strict\|balanced\|off]` | Show or set the privacy mode. |
| `npx @emfirge/mcp tokens` | List the local identifier-to-token mappings. |
| `npx @emfirge/mcp purge --role-arn ARN` | Delete the data the backend holds for that AWS account and your local token map. Read what it removes on [Security & privacy](https://emfirge.cloud/security.md#retention). |

| Verb | MCP tools behind it |
|---|---|
| `context` | `emfirge_context`, `emfirge_scan`, `emfirge_get_findings`, `emfirge_attack_paths`, `emfirge_check_compliance`, `emfirge_simulate_breach` |
| `branch` | `emfirge_create_branch`, `emfirge_list_branches`, `emfirge_get_branch`, `emfirge_fork_branch`, `emfirge_discard_branch`, `emfirge_rollback_branch`, `emfirge_rollback_branch_to_count`, `emfirge_compare_branches` |
| `try` | `emfirge_apply_change`, `emfirge_plan_verdict`, `emfirge_verify_fix` |
| `check` | `emfirge_check`, `emfirge_branch_verdict`, `emfirge_branch_diff`, `emfirge_policy_checks`, `emfirge_in_use_evidence` |
| `request` | none |
| `report` | `emfirge_branch_handback` |
| `connect`, `login`, `logout` | `emfirge_setup_help`, `emfirge_login`, `emfirge_logout`, `emfirge_link_project` |

Or add it by hand, then restart the client.

Manual MCP config (JSON):

```
{
  "mcpServers": {
    "emfirge": {
      "command": "npx",
      "args": ["-y", "@emfirge/mcp"],
      "env": { "EMFIRGE_PRIVACY": "strict" }
    }
  }
}
```

Codex (~/.codex/config.toml):

```
[mcp_servers.emfirge]
command = "npx"
args = ["-y", "@emfirge/mcp"]

[mcp_servers.emfirge.env]
EMFIRGE_PRIVACY = "strict"
```

---

All pages as markdown: https://emfirge.cloud/llms.txt. Source: https://github.com/theanshsonkar/emfirge. Contact: ansh@emfirge.cloud.
