@akms/mcp-ssh 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,53 @@
2
2
 
3
3
  All notable changes to `@akms/mcp-ssh`. Dates are `YYYY-MM-DD`.
4
4
 
5
+ ## [0.3.1] - 2026-10-26
6
+
7
+ ### Verification
8
+
9
+ - Stabilize Windows test cleanup: temporary test directories are removed with one bounded asynchronous retry budget for transient file locks, while persistent errors still fail. Tests only; the published package changes only its version.
10
+ - 0.3.0 was committed but never published to npm; 0.3.1 is the first published 0.3 release.
11
+
12
+ ## [0.3.0] - 2026-10-26
13
+
14
+ - Detect older registry formats in standalone config and the helper menu. Add reviewed, ordered migrations with default-No approval, script APIs, complete pre-migration backup, rollback preservation and post-apply startup checks. Runtime can change the default for future kinds without changing existing modes.
15
+
16
+ - Start new registries in version 2 session mode. Register/Add/Import create per-kind bundles automatically; missing runtimes keep imported legacy entries until installation and Sync. Existing v1 migration and v2 per-kind rollback choices are preserved.
17
+
18
+ - Add session servers (default for new catalogs, opt-in migration for existing version 1 catalogs): one direct-Node `akms_<kind>` entry per client session, connection-prefixed tools, registry version 2, reviewed migration and rollback, and startup tool coverage checks.
19
+ - Preserve one atomic `registry.previous.json` revision per catalog-changing operation; keep externally edited client entries for Sync and retain old entries until replacements are verified.
20
+ - Validate connection-name budgets; document credential location and recovery in session mode. Show runtime paths in startup failures, accept string protocol versions, and explain file-lock update failures.
21
+
22
+ - Check MCP startup after saves, runtime conversion and Updates; add an on-demand Updates screen and default registration removal to No.
23
+
24
+ - Document plaintext catalog credentials, platform permissions, transfer-guard limits and recovery; show one privacy notice during Register review and a catalog notice in --help.
25
+ - Keep custom-command edits and host-key saves independent of the managed runtime; continue with a still-usable installed runtime after an update failure.
26
+
27
+ - Install managed server runtimes under `<AKMS_MCP_HOME or ~/.akms/mcp>/runtime`, independent of Node versions. Convert existing npx and global paths through Runtime; preserve development links.
28
+ - Offer older-runtime updates before Add/Edit and check installation before host-key saves. Include the last npm error lines without ANSI controls, and recognize Unix npm JavaScript paths while skipping version-manager shims.
29
+
30
+ - Generate direct Node launches using the dedicated runtime installation instead of npx. Install the latest runtime on first Add/Edit when missing; reuse installed versions with update prompts when the setup package is newer. Runtime converts existing standard entries together, preserving connection values, custom commands and external edits; linked development packages are protected.
31
+
32
+ - Clarify Sync choices with numbered AKMS/service versions, highlighted differences, wrapped values, and explicit apply destinations.
33
+
34
+ - Separate terminal menu, comparison and result screens; wait for acknowledgement before returning, while keeping piped commands unchanged.
35
+
36
+ - Keep all configuration menus visible; Add requires at least one registered AI service.
37
+ - Summarize registration/sync results, show only differing fields during review, and distinguish pending imports from shared settings conflicts.
38
+
39
+ ### Changed
40
+
41
+ - Discover earlier client settings before registration, merge matching sync copies on Apply, and preserve differing versions for review.
42
+ - Add standalone `register` and `sync` commands and a persistent shared connection catalog. Save once to apply a connection to all registered AI services without installing `@akms/mcp`.
43
+ - Import existing client entries with explicit conflict choices; preserve external edits, retry partial failures and retain old names until renames succeed. Honor `CODEX_HOME`.
44
+
45
+ ## 0.2.1 — 2026-10-19
46
+
47
+ ### Documentation
48
+
49
+ - Add a minimum key-based connection example to README and clarify that host/user alone require an available authenticated SSH agent; document password alternatives and Windows launch settings.
50
+ - Make the jump-host/proxy example a complete JSON client configuration.
51
+
5
52
  ## 0.2.0 — 2026-10-19
6
53
 
7
54
  ### Changed
package/README.md CHANGED
@@ -6,63 +6,122 @@ MCP server that lets an AI agent run shell commands and transfer files on a remo
6
6
 
7
7
  The host is **pre-registered** in the server's own environment; the agent never receives a hostname, key or password as an argument, and no tool takes one. Every command and path is screened against the guard policy before anything reaches the network.
8
8
 
9
+ Use **session server mode** to share one process among this kind's connections in each client session. Each connection keeps its own target, credentials and policy; its tool names carry the connection prefix. The environment-based examples below describe individual mode. See [Session server mode](#session-server-mode).
10
+
9
11
  ## 📦 Installation
10
12
 
11
13
  Requires Node.js 18 or later.
12
14
 
13
15
  ```bash
14
- npm install -g @akms/mcp-ssh # installs the `akms-mcp-ssh` command
15
- npx -y @akms/mcp-ssh --help # or run it straight from the registry
16
+ npm install -g @akms/mcp-ssh@latest # installs the `akms-mcp-ssh` command
17
+ akms-mcp-ssh --help
16
18
  akms-mcp-ssh --version # show the installed version
17
19
  ```
18
20
 
19
- ## ⚙️ MCP client setup
21
+ ## Minimum working configuration
20
22
 
21
- **Let the CLI write it.** `config` opens a small manager for the hosts registered in a client's config. It asks plain questions — host, user, key or password, jump host, read-only — tests the connection, offers to pin the host key, and writes the entry. No `SSH_*` name has to be remembered.
23
+ Install the server from **Runtime** before using these manual examples. On Windows its script is `<AKMS_MCP_HOME or ~/.akms/mcp>/runtime/node_modules/@akms/mcp-ssh/lib/cli.js`; on macOS/Linux insert `lib/` before `node_modules`. Replace the placeholder below with that absolute path. Use the Node executable from `node -p "process.execPath"` as `command`. The `config` command writes both paths for you.
22
24
 
23
- ```bash
24
- npx -y @akms/mcp-ssh config # opens on the first client found on this machine
25
- npx -y @akms/mcp-ssh config --target codex # claude-code | codex | claude-desktop | cursor
25
+ For a direct SSH connection using a private key, use this MCP client entry. Replace the host, user and key path with your own. The SSH server must be reachable on port `22`, and the matching public key must already be authorized for that user.
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "ssh": {
31
+ "command": "node",
32
+ "args": ["/absolute/akms/mcp/runtime/node_modules/@akms/mcp-ssh/lib/cli.js"],
33
+ "env": {
34
+ "SSH_HOST": "ssh.example.com",
35
+ "SSH_USER": "deploy",
36
+ "SSH_KEY": "~/.ssh/id_ed25519"
37
+ }
38
+ }
39
+ }
40
+ }
26
41
  ```
27
42
 
28
- Starting in **0.1.5**, `config` is the only configuration command. Update scripts and shortcuts to use `akms-mcp-ssh config`; `--target` works as before. The former `setup` command exits with code 1 and a reminder to use `config`.
43
+ `SSH_HOST` and `SSH_USER` are required. The example also supplies authentication explicitly: `SSH_KEY` must point to an existing private key file; add `SSH_PASSPHRASE` if it is encrypted. For password authentication, replace `SSH_KEY` with `SSH_PASSWORD`. Omit both only when the MCP process can access an SSH agent with an authorized key (`SSH_AUTH_SOCK`, or the OpenSSH agent on Windows). No default key file or `~/.ssh/config` is loaded automatically.
29
44
 
30
- ```
31
- Claude Code (user scope) /home/me/.claude.json
32
-
33
- ? 1 SSH host — pick it to manage it
34
- ❯ ssh-prod deploy@10.0.0.5:22 key · readonly, pinned
35
- ────────────────────────
36
- Add a host
37
- Switch client also found: Codex CLI
38
- Quit
39
- ↑↓ move · enter select · esc back
45
+ `SSH_PORT` defaults to `22`; jump-host and proxy settings are optional. Writes are allowed by default; add `"SSH_READONLY": "true"` for a read-only entry.
46
+
47
+ The JSON example fits an MCP client's `mcpServers` configuration, such as a project `.mcp.json` or Cursor's `mcp.json`. The direct Node command also works on Windows. For Codex TOML, open Register from `akms-mcp-ssh config --target codex` (or choose another client below).
48
+
49
+ ## ⚙️ MCP client setup
50
+
51
+ Register the AI services you use once, then manage connections in one shared list. **This package works independently; installing or running `@akms/mcp` is optional.**
52
+
53
+ ```sh
54
+ akms-mcp-ssh register # toggle services, then Apply registration
55
+ akms-mcp-ssh config # add, edit, check, print or remove connections
56
+ akms-mcp-ssh sync # review differences and retry pending changes
40
57
  ```
41
58
 
42
- The hosts are the menu: pick one to edit, check, copy, print or remove it. Adding or editing a host opens a settings form — every setting listed with its value, picked and changed in any order, with **Test the connection** and **Save** below. Choose a private key from the keys found in `~/.ssh`, and a route: directly, through a jump host, through a proxy command, or through both.
59
+ ### AKMS runtime and existing connections
43
60
 
44
- On an interactive terminal:
61
+ Managed connections start Node directly using a dedicated installation at `<AKMS_MCP_HOME or ~/.akms/mcp>/runtime`. This directory is independent of Node version managers. The setup CLI may be installed globally as above or opened once with `npx -y @akms/mcp-ssh@latest config`; it is separate from the server runtime saved in client settings.
62
+
63
+ Before Add or a standard-launch Edit, setup installs a missing runtime with `npm install --global --prefix "<AKMS runtime directory>" --prefer-online --no-fund --no-audit @akms/mcp-ssh@latest`. If the installed version is older than this setup package, it offers an update (default Yes); declining continues with the installed version. Linked development packages skip this prompt. Host-key saves for standard launches also check the runtime before writing. Custom launch commands keep their existing command and require no managed-runtime installation. If an update fails but an installed runtime is still usable, setup reports the error and continues with that version. Servers do not invoke npm or query updates when AI clients connect.
64
+
65
+ To migrate existing entries, open `akms-mcp-ssh config`, choose **Runtime**, install the runtime if needed, then choose **Use for existing connections**. Both legacy npx entries and direct paths in ordinary global installations can be converted. Review and apply the list, then **restart or reconnect the AI clients** to replace running processes. Connection values and credentials stay intact; custom commands and external client edits are preserved for individual review. Register/import legacy entries first if they are missing from the shared list. Version-pinned npx entries switch to the installed version shown in the preview.
66
+
67
+ **Runtime > Update runtime installation** explicitly installs the latest release into this same directory. The Node executable keeps its existing alias path, allowing nvm-windows to switch Node versions while the package path stays fixed. If the Node command path or `AKMS_MCP_HOME` moves, reapply current paths from Runtime. Removing the runtime directory breaks entries that use it.
68
+
69
+ For development, build the checkout and link it with `npm install -g --prefix "<AKMS runtime directory>" "<checkout path>"`. Linked packages retain the runtime alias path; automatic updates do not overwrite the checkout link. See [README_DEV.md](README_DEV.md). `@akms/mcp` remains optional.
70
+
71
+ `config` always shows the connection menu, including Add, Register, Sync, Import and Runtime. With no registered services, Add displays a message asking you to open Register and returns to the menu without opening a form or changing settings. Claude Code, Codex, Claude Desktop and Cursor are supported; Enter toggles each service and Apply saves the selection. `--target codex` preselects Codex in Register; it does not restrict subsequent saves to Codex.
72
+
73
+ On an interactive terminal, connection menus, registration and comparisons use separate screens. Results and errors stay visible until Enter or Esc; returning to the menu shows current services and any connections needing attention. Piped commands keep plain output and need no extra answers. Sync labels the saved AKMS version and the current service version separately. Numbered choices show which service receives a value or whether it becomes the AKMS value for all registered services. Long values wrap, changed text is highlighted, and confirmation names the destinations.
74
+
75
+ Service selection is shared across the AKMS packages. Every saved connection is applied to all registered services, and a newly registered service receives existing shared connections. Unregistering removes only entries managed by AKMS from that service and retains the shared catalog. Restart or reconnect the MCP client to load changed settings.
76
+
77
+ ### Startup checks and updates
78
+
79
+ After saving a changed connection, applying Runtime launch commands, or updating from **Updates**, setup starts each distinct saved command once without shell interpolation. It sends MCP `initialize` and `tools/list`, then closes stdin; it does not invoke database, SSH, WSL or S3 tools. The check takes at most about 10 seconds per entry, plus bounded process cleanup. Results show the server version and tool count, or the exit code and masked stderr tail. Standard runtime script paths and spawn command paths stay visible for diagnosis. Session checks also verify a tool-name prefix for every saved connection. A failed check keeps the saved settings: fix it before restarting or reconnecting AI clients. Identical command/arguments/environment values share one check.
80
+
81
+ Open **Updates** in the launcher or any package config menu to see installed and latest published runtime versions. Version lookup runs only when this screen opens or **Refresh versions** is chosen, with a short timeout; offline results show **Unavailable**. Update one runtime or all installed runtimes with newer releases; missing runtimes can be installed individually. Development links are displayed but never updated, and WSL is listed only on Windows. Updates use the same dedicated AKMS runtime directory and check that kind's saved connections afterward. Reconnect your AI clients to use the new runtime. The helper itself is not updated here.
82
+
83
+ Register confirmation defaults to **No** when deselecting a previously registered service; otherwise it defaults to **Yes**.
84
+
85
+ ### Session server mode
86
+
87
+ New catalogs start in version 2 with session mode enabled. Register your AI services, then add connections; setup creates each kind's session entry automatically. Existing version 1 catalogs keep individual mode until you approve **Migrate registry** or a per-kind **Runtime > Switch to session server** conversion (default No). Register/import their existing connections first. Each registered AI service gets one `akms_db`, `akms_ssh`, `akms_wsl` or `akms_s3` entry for that kind, running Node directly with `--catalog`. The helper package is optional. A client session still owns its own stdio process; connections of the same kind share that process.
88
+
89
+ The server reads its connections from the shared catalog at startup. Tools include the connection name, for example `production__db_query`; their arguments stay unchanged. Add/Edit/Remove updates the catalog; reconnect your clients to load changes. Removing the last connection removes the session entry. An invalid connection is excluded while valid ones remain available; `<kind>_catalog_status` reports the loaded/excluded names without credentials. No database, SSH, WSL or S3 connection opens just to list tools.
90
+
91
+ Converting an existing version 1 catalog upgrades it to version 2 and keeps the previous revision. Older setup packages stop without modifying version 2. New kinds in a new catalog also default to sessions; each kind's explicit rollback choice is retained. AKMS removes managed individual entries only after verifying the session entry; external edits stay for **Sync** review. Custom launch commands are retained in the catalog for rollback but are not executed in session mode.
92
+
93
+ **Runtime > Switch back to per-connection entries** previews and restores the saved individual entries, including their credentials and launch commands. It removes the session entry after the replacements are verified. The registry stays version 2. **Reapply session launch command** updates paths after moving Node or the runtime. Restart/reconnect clients after either change.
94
+
95
+ Connection names use ASCII letters, digits, underscores or hyphens: DB up to 35 characters, SSH/WSL 30, S3 37. The four `akms_<kind>` names are reserved. These limits keep client-prefixed tool names within 64 characters; rename longer legacy entries before conversion.
96
+
97
+ ### Migrate an older registry
98
+
99
+ When a version 1 registry or a version 2 registry without a default-mode marker is opened, the helper and each config menu show **Registry update available** and **Migrate registry**. Select it to review the ordered format steps, every kind's current layout, per-service additions/removals, and settings kept for Sync. Approval defaults to **No**.
100
+
101
+ Migration upgrades v1 to v2, records `defaultMode: "catalog"`, and converts individual kinds through the existing session conversion rules. Kinds explicitly switched back to individual entries keep that choice. Already bundled kinds keep their launch commands; an unmarked v2 containing only bundles receives the marker without client-file changes. Missing runtimes leave existing entries in place for **Runtime** installation and **Sync**. Startup checks verify the affected session tools after approval.
102
+
103
+ One `registry.previous.json` revision covers the whole migration. Repeating migration on a current registry does nothing. Runtime still offers per-kind conversion and rollback. **Runtime > Use individual entries for new kinds** turns the future-kind default off, and **Start new kinds as session servers** turns it back on; existing kinds retain their modes. The explicit `individual` default is also current format, so turning it off does not trigger another migration notice.
104
+
105
+ ### Catalog security
106
+
107
+ The shared catalog is `~/.akms/mcp/registry.json`, or `$AKMS_MCP_HOME/registry.json`. It contains complete connection settings, including passwords and secret values **in plaintext**. In individual mode these values also appear in AI client entries. After successful session-mode conversion and resolution of any retained legacy entries, the catalog is the only active location for that kind's connection credentials; one previous-revision copy also contains them. SSH secrets include SSH_PASSWORD, SSH_PASSPHRASE, SSH_JUMP_PASSWORD and SSH_JUMP_PASSPHRASE. SSH private-key settings store file paths, not the key files themselves.
108
+
109
+ On POSIX, new catalog files request mode `0600` and new catalog directories `0700`; existing permissions are not tightened. Windows uses inherited parent-directory ACLs (normally the user profile), not POSIX owner/group modes. Check access permissions when choosing a custom location.
110
+
111
+ Keep both catalog files private: do not commit it, share it, copy it to another person or PC, paste its contents into chats/issues/AI conversations, or ask an AI agent to print it. Exclude it from cloud sync and shared backups, or protect those copies. Prefer SSH key authentication over passwords where possible. If exposed, change the affected passwords or rotate the affected keys/tokens, then update the connections through `config`.
112
+
113
+ SSH blocks local uploads from and downloads into `.akms/mcp`. A custom `AKMS_MCP_HOME` outside that path is not protected as a whole: its `registry.json` and `registry.previous.json` are additionally blocked when the SSH process has that environment variable. Remote SSH paths have no catalog-specific block. WSL protects these paths through `/mnt/<drive>/`; native Linux paths have no catalog-specific block, and local Windows transfers depend on the installed SSH guard. The locked SSH 0.1.9 dependency does not block the catalog in those local transfers. Do not rely on these guards to keep the file private.
114
+
115
+ Each successful catalog-changing operation atomically keeps one previous revision as **`registry.previous.json`** in the same directory. Internal application bookkeeping does not replace that pre-operation revision, and a no-op Sync leaves it unchanged. The copy requests the catalog's existing file permissions; Windows uses inherited ACLs. This is one revision, not a history.
116
+
117
+ To recover, close configuration commands, preserve the current file if needed, and copy `registry.previous.json` over `registry.json` in that directory. Then reopen setup, review **Sync**, and reconnect clients. Recovery does not automatically revert client files.
118
+
119
+ A running session keeps its startup snapshot. If `registry.json` is missing or invalid, a newly started session exposes only its status tool; its empty client entry cannot reconstruct credentials through Import. Restore the previous revision or enter the connections again. Individual mode still uses each entry's environment, so its existing client entries keep working and can be imported after registering services again.
120
+
121
+ Each standalone package manages this versioned file directly and does not call the optional helper.
122
+
123
+ Register shows existing AKMS entry counts even before registration. Applying registration automatically imports existing connections whose versions match, merging identical copies into one shared item. In session mode, it replaces owned individual entries after verifying the session launch. If a runtime is missing, the existing entries stay in place: install it from Runtime, then run Sync. Differing versions remain intact for review. Results summarize completed connections and list only items needing attention. The comparison shows changed fields, labels description-only differences, and keeps secrets hidden. Use **Import existing connections** to review differences later or import all remaining matching entries together. When versions differ, review the masked settings and choose which version to apply, or give the imported connection another name to keep both. The menu shows per-connection application counts. Failed writes keep the saved values and successful service updates; **Sync** retries pending changes and offers explicit choices for external edits. Unrelated or conflicting unmanaged entries are preserved.
45
124
 
46
- | Keys | Action |
47
- |---|---|
48
- | ↑ / ↓, Enter | Move through a menu and select a setting or action |
49
- | Esc | Go back one level; inside a field or choice, return to the form with that setting unchanged |
50
- | ← / →, Home / End | Move the cursor within text being entered |
51
- | Backspace / Delete, Ctrl+U | Delete characters or clear the current input line |
52
- | Enter with no input | Keep the displayed value; enter `-` to clear an optional value |
53
- | Ctrl+C / Ctrl+D | Exit configuration |
54
-
55
- Esc also undoes a choice when pressed in its follow-up question: choosing a jump route and then pressing Esc at the jump-host prompt restores the previous route. Esc at the **Write it?** preview reopens the form with the entered values. Leaving a changed form with Cancel or Esc asks whether to discard changes.
56
-
57
- Without an interactive terminal (a pipe, or Git Bash's mintty without winpty), the same menus use numbered choices; enter a number, key or label followed by Enter. After saving, restart the MCP client or reconnect the server from its MCP menu to load the updated entry.
58
-
59
- **Copy to another client** opens a destination picker for Claude Code, Codex, Claude Desktop
60
- and Cursor. It copies the saved server name, command, arguments and all environment
61
- variables, keeping the source entry and current client unchanged. If that name already
62
- exists at the destination (including another package or HTTP server), **Overwrite it?**
63
- defaults to **No**. Esc at confirmation returns to the destination picker. Confirming
64
- overwrite replaces the destination entry; unrelated entries and global settings stay.
65
- Client-specific options such as tool approvals are not copied.
66
125
  Codex configs are validated before and after editing. Inline/dotted server definitions
67
126
  are recognized, but automatic edits require the `[mcp_servers.<name>]` table layout;
68
127
  unsupported edits are rejected without changing the file. JSON and TOML saves use a
@@ -76,20 +135,20 @@ Release notes are in [CHANGELOG.md](CHANGELOG.md).
76
135
  | Client | Config file | How it is written |
77
136
  |---|---|---|
78
137
  | Claude Code | `~/.claude.json` (user scope) | through `claude mcp add-json … -s user`, never by editing the file |
79
- | Codex | `~/.codex/config.toml` | only the `[mcp_servers.<name>]` tables are rewritten; keys you added to them stay |
138
+ | Codex | `$CODEX_HOME/config.toml` (defaults to `~/.codex/config.toml`) | only the `[mcp_servers.<name>]` tables are rewritten; keys you added to them stay |
80
139
  | Claude Desktop | `claude_desktop_config.json` | `mcpServers.<name>` is set, every other key kept |
81
140
  | Cursor | `~/.cursor/mcp.json` | same |
82
141
 
83
- Only entries that launch this package are listed for management. An edit keeps every `SSH_*` variable the wizard does not ask about (timeouts, deny patterns, `SSH_CWD`, …). **Print** shows an entry as JSON, as a Codex TOML table and as a `claude mcp add-json` line, for when pasting is easier. On Windows the entry launches through `cmd /c npx`, the form Claude Code expects for npx servers there.
142
+ Only entries that launch this package are listed for management. An edit keeps every `SSH_*` variable the wizard does not ask about (timeouts, deny patterns, `SSH_CWD`, …). **Print** shows an entry as JSON, as a Codex TOML table and as a `claude mcp add-json` line, for when pasting is easier. Entries use the absolute Node executable and the script in the AKMS runtime directory on every platform.
84
143
 
85
- **Or by hand — one server entry per host** — plain `SSH_*` variables, no config file, no JSON inside JSON. Claude Code reads `.mcp.json` in the project or `~/.claude.json` globally; Claude Desktop takes the same block inside `claude_desktop_config.json`:
144
+ **Or by hand — one server entry per host** — plain `SSH_*` variables, no separate server-side config file, no JSON inside JSON. Claude Code reads `.mcp.json` in the project or `~/.claude.json` globally; Claude Desktop takes the same block inside `claude_desktop_config.json`:
86
145
 
87
146
  ```json
88
147
  {
89
148
  "mcpServers": {
90
149
  "ssh-prod": {
91
- "command": "npx",
92
- "args": ["-y", "@akms/mcp-ssh"],
150
+ "command": "node",
151
+ "args": ["/absolute/akms/mcp/runtime/node_modules/@akms/mcp-ssh/lib/cli.js"],
93
152
  "env": {
94
153
  "SSH_HOST": "10.0.0.5", "SSH_USER": "deploy", "SSH_KEY": "~/.ssh/id_ed25519",
95
154
  "SSH_READONLY": "true", "SSH_ALLOWED_PATHS": "/var/log,/opt/app"
@@ -99,7 +158,7 @@ Only entries that launch this package are listed for management. An edit keeps e
99
158
  }
100
159
  ```
101
160
 
102
- `SSH_HOST` + `SSH_USER` is the whole minimum, and the **private key stays a file on disk** — only its path goes in the config. Because each server fronts one host, the agent never names it: `ssh_exec({ command: "df -h" })` is a complete call. The server name (`ssh-prod`) is what the agent sees in its tool list, so name it after the host.
161
+ `SSH_HOST` + `SSH_USER` is sufficient only when an SSH agent with an authorized key is available; otherwise also provide a key path or password as shown in [Minimum working configuration](#minimum-working-configuration). The **private key stays a file on disk** — only its path goes in the config. Because each server fronts one host, the agent never names it: `ssh_exec({ command: "df -h" })` is a complete call. The server name (`ssh-prod`) is what the agent sees in its tool list, so name it after the host.
103
162
 
104
163
  The server speaks MCP over **stdio**: stdout carries the JSON-RPC stream and all logging goes to stderr. Running it by hand in a terminal only prints the startup line and waits. When the client goes away — stdin ends, or the process is simply gone — the server closes its sessions and exits within a few seconds on its own; a stderr nobody reads is never a reason to stay. Its log says `mcp server ready on stdio` with its `pid`, for when one has to be found among a client's processes.
105
164
 
@@ -137,12 +196,16 @@ Authentication is tried in this order: **private key by path** (with `SSH_PASSPH
137
196
  `~/.ssh/config` is **not** read — the server never shells out to `ssh` — so a `ProxyJump` or `ProxyCommand` that works on the command line has to be stated in the entry. Both OpenSSH shapes are available, and they compose:
138
197
 
139
198
  ```json
140
- "ssh-dev": {
141
- "command": "npx", "args": ["-y", "@akms/mcp-ssh"],
142
- "env": {
143
- "SSH_HOST": "10.0.16.12", "SSH_USER": "ubuntu", "SSH_KEY": "~/.ssh/id_ed25519",
144
- "SSH_JUMP_HOST": "dev-ak-ssh.example.com",
145
- "SSH_PROXY_COMMAND": "cloudflared access ssh --hostname %h"
199
+ {
200
+ "mcpServers": {
201
+ "ssh-dev": {
202
+ "command": "node", "args": ["/absolute/akms/mcp/runtime/node_modules/@akms/mcp-ssh/lib/cli.js"],
203
+ "env": {
204
+ "SSH_HOST": "10.0.16.12", "SSH_USER": "ubuntu", "SSH_KEY": "~/.ssh/id_ed25519",
205
+ "SSH_JUMP_HOST": "dev-ak-ssh.example.com",
206
+ "SSH_PROXY_COMMAND": "cloudflared access ssh --hostname %h"
207
+ }
208
+ }
146
209
  }
147
210
  }
148
211
  ```
@@ -191,11 +254,11 @@ Add a server entry per host. Each one carries its own connection and its own pol
191
254
  {
192
255
  "mcpServers": {
193
256
  "ssh-prod": {
194
- "command": "npx", "args": ["-y", "@akms/mcp-ssh"],
257
+ "command": "node", "args": ["/absolute/akms/mcp/runtime/node_modules/@akms/mcp-ssh/lib/cli.js"],
195
258
  "env": { "SSH_HOST": "10.0.0.5", "SSH_USER": "deploy", "SSH_READONLY": "true" }
196
259
  },
197
260
  "ssh-dev": {
198
- "command": "npx", "args": ["-y", "@akms/mcp-ssh"],
261
+ "command": "node", "args": ["/absolute/akms/mcp/runtime/node_modules/@akms/mcp-ssh/lib/cli.js"],
199
262
  "env": { "SSH_HOST": "192.168.0.10", "SSH_USER": "ubuntu" }
200
263
  }
201
264
  }
@@ -205,7 +268,7 @@ Add a server entry per host. Each one carries its own connection and its own pol
205
268
  ### Check it before wiring it up
206
269
 
207
270
  ```bash
208
- akms-mcp-ssh --check # or: npx -y @akms/mcp-ssh --check
271
+ akms-mcp-ssh --check
209
272
  ```
210
273
 
211
274
  Connects to the configured host and reports what happened — exit code 0 when it is reachable. Otherwise a setup mistake is indistinguishable from a policy rejection when the agent tries something. Warnings still print during the check (a missing key file, the proxy command's stderr); add `SSH_MCP_LOG_LEVEL=debug` to see the handshake.
@@ -280,7 +343,7 @@ The file tools run with this server's own privileges on your machine, so `localP
280
343
 
281
344
  SSH and its crypto runtime load on the first connection instead of during idle MCP startup or local configuration work. The same loaded client supports direct, proxy and jump-host routes. Concurrent callers share the connection attempt, and disconnecting during module loading prevents a later transport from opening. The runtime stays loaded after first use; disconnecting a session closes its transport rather than unloading the module.
282
345
 
283
- Each configured host in each MCP client runs its own process. An `npx` registration also keeps an npm wrapper running. For a stable local/global installation, an entry can instead use the absolute Node executable as `command` and the installed package's absolute `lib/cli.js` path as its sole argument, retaining its existing `env`. Avoid paths inside npm's temporary execution cache. The configuration form continues to generate portable `npx` registrations and may restore that launch style when saving an edit.
346
+ Individual mode starts one server process per configured connection in each client session. Session mode combines that kind's connections in one stdio process per client session. Both use the dedicated runtime directly, avoiding a resident npm/npx wrapper. Convert from Runtime and reconnect clients to load the new layout. Connections to remote services remain lazy.
284
347
 
285
348
  Restart MCP connections after updating to apply the new code. Compare process counts and Windows Private Bytes separately from resident memory (RSS), including npm wrappers in the total.
286
349