host-execution-mcp 1.0.1 → 2.0.0

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +13 -11
  3. package/SECURITY.md +3 -3
  4. package/dist/access/index.d.ts +21 -10
  5. package/dist/access/index.js +55 -27
  6. package/dist/access/index.js.map +1 -1
  7. package/dist/access/paradi-auth.d.ts +3 -3
  8. package/dist/access/paradi-auth.js +4 -4
  9. package/dist/access/paradi-auth.js.map +1 -1
  10. package/dist/access/paradi-transport.d.ts +1 -1
  11. package/dist/access/paradi-transport.js +3 -3
  12. package/dist/access/paradi-transport.js.map +1 -1
  13. package/dist/access/paradi-username.d.ts +1 -1
  14. package/dist/access/paradi-username.js +2 -2
  15. package/dist/access/paradi-username.js.map +1 -1
  16. package/dist/access/session-pool.d.ts +5 -0
  17. package/dist/access/session-pool.js +7 -0
  18. package/dist/access/session-pool.js.map +1 -1
  19. package/dist/access/ssh-transport.d.ts +1 -1
  20. package/dist/access/ssh-transport.js +3 -2
  21. package/dist/access/ssh-transport.js.map +1 -1
  22. package/dist/config-yaml.d.ts +54 -0
  23. package/dist/config-yaml.js +172 -0
  24. package/dist/config-yaml.js.map +1 -0
  25. package/dist/config.d.ts +45 -1
  26. package/dist/config.js +126 -22
  27. package/dist/config.js.map +1 -1
  28. package/dist/index.js +3 -3
  29. package/dist/index.js.map +1 -1
  30. package/dist/instructions.d.ts +4 -1
  31. package/dist/instructions.js +73 -51
  32. package/dist/instructions.js.map +1 -1
  33. package/dist/kubectl/runner.d.ts +7 -8
  34. package/dist/kubectl/runner.js +18 -21
  35. package/dist/kubectl/runner.js.map +1 -1
  36. package/dist/link-runtime.d.ts +39 -0
  37. package/dist/link-runtime.js +134 -0
  38. package/dist/link-runtime.js.map +1 -0
  39. package/dist/server.d.ts +2 -1
  40. package/dist/server.js +10 -12
  41. package/dist/server.js.map +1 -1
  42. package/dist/sources/guides.d.ts +34 -0
  43. package/dist/sources/guides.js +50 -0
  44. package/dist/sources/guides.js.map +1 -0
  45. package/dist/sources/index.d.ts +5 -0
  46. package/dist/sources/index.js +22 -0
  47. package/dist/sources/index.js.map +1 -0
  48. package/dist/sources/yaml-template.d.ts +31 -0
  49. package/dist/sources/yaml-template.js +35 -0
  50. package/dist/sources/yaml-template.js.map +1 -0
  51. package/dist/ssh/access-client.d.ts +6 -2
  52. package/dist/ssh/access-client.js +58 -27
  53. package/dist/ssh/access-client.js.map +1 -1
  54. package/dist/ssh/access-errors.js +1 -1
  55. package/dist/ssh/access-errors.js.map +1 -1
  56. package/dist/ssh/access-sftp.js +3 -3
  57. package/dist/ssh/access-sftp.js.map +1 -1
  58. package/dist/tools/copy-job-schemas.d.ts +96 -581
  59. package/dist/tools/copy-job-schemas.js +9 -9
  60. package/dist/tools/copy-job-schemas.js.map +1 -1
  61. package/dist/tools/register.d.ts +2 -10
  62. package/dist/tools/register.js +174 -331
  63. package/dist/tools/register.js.map +1 -1
  64. package/dist/tools/remote-schemas.d.ts +156 -708
  65. package/dist/tools/remote-schemas.js +99 -103
  66. package/dist/tools/remote-schemas.js.map +1 -1
  67. package/dist/utils/copy-executor.d.ts +3 -1
  68. package/dist/utils/copy-executor.js +39 -25
  69. package/dist/utils/copy-executor.js.map +1 -1
  70. package/dist/utils/copy-transfer.d.ts +2 -0
  71. package/dist/utils/copy-transfer.js.map +1 -1
  72. package/dist/utils/remote-executor.d.ts +3 -4
  73. package/dist/utils/remote-executor.js +8 -18
  74. package/dist/utils/remote-executor.js.map +1 -1
  75. package/dist/utils/remote-target.js +1 -1
  76. package/dist/utils/remote-target.js.map +1 -1
  77. package/docs/AGENT_GUIDE.md +31 -103
  78. package/docs/CONFIGURATION.md +30 -9
  79. package/docs/GUIDE.md +186 -0
  80. package/docs/PARADI_ACCESS_PLAN.md +6 -6
  81. package/docs/TODO.md +4 -11
  82. package/docs/USER_GUIDE.zh-CN.md +26 -173
  83. package/docs/host-execution.yaml +92 -0
  84. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"remote-executor.js","sourceRoot":"","sources":["../../src/utils/remote-executor.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,OAAO,cAAc;IAEN;IACA;IACA;IAHnB,YACmB,MAAqB,EACrB,OAAsB,EACtB,MAAiB;QAFjB,WAAM,GAAN,MAAM,CAAe;QACrB,YAAO,GAAP,OAAO,CAAe;QACtB,WAAM,GAAN,MAAM,CAAW;IACjC,CAAC;IAEJ,KAAK,CAAC,WAAW,CACf,MAAoB,EACpB,OAAe,EACf,SAAkB;QAElB,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE;oBACpC,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB;iBACrD,CAAC,CAAC;YACL,KAAK,SAAS;gBACZ,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE;oBACpC,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB;iBACrD,CAAC,CAAC;YACL,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CACtB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,GAAG,EACV,OAAO,EACP,MAAM,CAAC,SAAS,EAChB,SAAS,CACV,CAAC;YACJ,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,UAAU,GAAU,MAAM,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"remote-executor.js","sourceRoot":"","sources":["../../src/utils/remote-executor.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,OAAO,cAAc;IAEN;IACA;IACA;IAHnB,YACmB,MAAqB,EACrB,OAAsB,EACtB,MAAiB;QAFjB,WAAM,GAAN,MAAM,CAAe;QACrB,YAAO,GAAP,OAAO,CAAe;QACtB,WAAM,GAAN,MAAM,CAAW;IACjC,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,MAAuB,EAAE,OAAe,EAAE,SAAkB;QAC5E,MAAM,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC;QAC1D,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE;gBACpC,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,SAAS,EAAE,OAAO;aACnB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CACtB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,GAAG,EACV,OAAO,EACP,MAAM,CAAC,SAAS,EAChB,OAAO,EACP,MAAM,CAAC,UAAU,CAClB,CAAC;IACJ,CAAC;CACF"}
@@ -11,7 +11,7 @@ export function resolveRemotePassword(password, defaultPassword) {
11
11
  export function resolveRemoteUser(user, defaultUser) {
12
12
  const resolved = user?.trim() || defaultUser?.trim();
13
13
  if (!resolved) {
14
- throw new Error('ssh_exec and host-target tools require "user" parameter or TARGET_USER environment variable. Do not assume root.');
14
+ throw new Error('Second-hop / Paradi host tools require "user" or TARGET_USER. Do not assume root.');
15
15
  }
16
16
  return resolved;
17
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"remote-target.js","sourceRoot":"","sources":["../../src/utils/remote-target.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-target.js","sourceRoot":"","sources":["../../src/utils/remote-target.ts"],"names":[],"mappings":"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"}
@@ -1,110 +1,45 @@
1
1
  # Agent Guide — host-execution-mcp
2
2
 
3
- Extended reference for LLM agents. A shorter version is injected as MCP server `instructions` at handshake (KIND-aware for `ssh` vs `paradi-gateway`).
3
+ Operational cookbook. User-facing usage and config are in [GUIDE.md](./GUIDE.md) (MCP Resource `host-execution://guides/user`).
4
4
 
5
- ## Naming (5.0.0)
5
+ **GUIDE.md is the capability the user wants this MCP to provide.** If a tool error, missing path, timeout, or implementation gap means that capability is not met, tell the user promptly — do not hide it or invent a workaround that pretends the tool worked.
6
6
 
7
- Agent-facing tools use ACCESS/Context naming: `access_check`, `shell_exec`, `context_derive`, `contextKey`, `target=landing|pod|context`. Error code: `ACCESS_UNAVAILABLE`.
7
+ Handshake `instructions` stay short. Once per conversation, `listResources` and read `host-execution://guides/user`, `host-execution://guides/agent`, and `host-execution://guides/yaml` (before creating or appending a roster link). Reuse for the session. Do not look for repo file paths.
8
8
 
9
- | ACCESS_KIND | Landing Context | `shell_exec` / `target=landing` means |
10
- |-------------|-----------------|----------------------------------------|
11
- | `ssh` (default) | ACCESS host | ACCESS OS |
12
- | `paradi-gateway` | TARGET host | TARGET OS (not the gateway) |
9
+ ## Tool returns
13
10
 
14
- User config is `ACCESS_*` / `TARGET_*` only. Async copy root: `ACCESS_COPY_JOB_ROOT`.
11
+ On **success** (`exitCode===0`), remote stdout and stderr are merged into `stdout`; `stderr` is empty.
15
12
 
16
- ## Architecture (read this first)
17
-
18
- **On this MCP path**, there is no laptop SSH to pods or cluster nodes.
19
-
20
- ### Shape A — ACCESS_KIND=ssh
21
-
22
- ```
23
- ┌─────────────┐ Hop 1 (automatic) ┌──────────┐ Hop 2 (tools) ┌────────────┐
24
- │ MCP Client │ ─── SSH (ssh2) ──────► │ ACCESS │ ── kubectl exec ────► │ Pod │
25
- │ + MCP Server│ │ landing │ ── ssh/sshpass ─────► │ Host/node │
26
- └─────────────┘ │ │ ── shell / docker ──► │ ACCESS OS │
27
- └──────────┘ └────────────┘
28
- ```
29
-
30
- `TARGET_*` (optional) = **default derive selector only** — not a second Context at init. `ssh_exec` = derive + shell.
31
-
32
- ### Shape B — ACCESS_KIND=paradi-gateway
33
-
34
- ```
35
- ┌─────────────┐ Hop 1 ┌──────────┐
36
- │ MCP Client │ ── SSH (encoded user) ►│ Gateway │──► landing Context = TARGET
37
- └─────────────┘ ACCESS_USER/TARGET_HOST/TARGET_USER
38
- ```
39
-
40
- Runtime tools run on **TARGET**. Disabled: `context_derive`, `remote_*` / `remote_copy_*` with `target=context`. Use `shell_exec` / `target=landing` / `docker_*` (omit contextKey). SFTP is `degraded` — avoid parallel hammering; prefer smaller copies / `remote_copy_start`.
41
-
42
- | Hop | Who initiates | What |
43
- |-----|---------------|------|
44
- | **Hop 1** | MCP server on user's machine | SSH to `ACCESS_HOST` (always; not exposed as a tool) |
45
- | **Hop 2** | Landing Context | `shell_exec`, `k8s_*`, `ssh_exec` (ssh only), `docker_*`, `remote_*` |
46
-
47
- **Common misconception:** `ssh_exec` is **NOT** "local laptop SSH to remote host". It means **ACCESS SSHs to the target** (`ACCESS_KIND=ssh` only).
48
-
49
- ## Capability boundary
13
+ On **command failure** (`exitCode≠0`, `success=false`, no thrown exception): merged remote output is still in **`stdout`**. Only tool/connection exceptions (e.g. `ACCESS_UNAVAILABLE`) put the message in `stderr`.
50
14
 
51
- Remote execution primitives only. No project-specific paths or namespace defaults.
15
+ Always check both `success` / `exitCode` and `stdout`.
52
16
 
17
+ - Host Docker engine → `docker_*`. Kubernetes container → `k8s_exec` / `k8s_logs`.
53
18
  - `docker_*` auto-probes `capabilities.docker` (unknown ≠ true).
54
- - `k8s_*` does **not** gate on `capabilities.kubectl` — failures surface as exitCode; use `context_probe` for presence.
55
-
56
- ## Three Runtime paths (ssh)
57
-
58
- | Path | Tool(s) | Action |
59
- |------|---------|--------|
60
- | **Landing shell** | `shell_exec`, `remote_*` target=landing | Run on ACCESS (or TARGET under Paradi) |
61
- | **Pod** | `k8s_exec`, `k8s_logs`, `remote_*` target=pod | kubectl exec / logs |
62
- | **Derived host** | `context_derive` → `ssh_exec`, `remote_*` target=context | ssh/sshpass — **ssh kind only** |
63
-
64
- ### Decision matrix
65
-
66
- | User intent | Tool (ssh) | Tool (paradi) |
67
- |-------------|------------|---------------|
68
- | List/find pods | `k8s_list_pods` | same |
69
- | Run script in container | `k8s_exec` | same |
70
- | Read file in container | `remote_read_file` target=pod | same |
71
- | Host OS shell on landing | `shell_exec` | `shell_exec` (TARGET) |
72
- | Host OS after jump | `context_derive` + `ssh_exec` / target=context | **disabled** — already on TARGET |
73
- | Docker on landing | `docker_*` | `docker_*` (no host) |
74
- | Docker on worker | `docker_*` + contextKey | **disabled** under Paradi |
75
- | Copy short | `remote_copy_file` | same; no `target=context` under Paradi |
76
- | Copy large | `remote_copy_start` | same; SFTP degraded |
19
+ - `k8s_*` does not gate on `capabilities.kubectl` — failures surface as exitCode; use `context_probe` for presence.
77
20
 
78
- ## ssh_exec vs k8s_exec vs docker_* vs shell_exec
79
-
80
- | Tool | Reaches | Auth / notes |
81
- |------|---------|----------------|
82
- | `shell_exec` | Landing OS shell | ACCESS_* (Paradi: TARGET via gateway); optional contextKey |
83
- | `k8s_exec` | Inside pod container | Landing kubeconfig |
84
- | `ssh_exec` | Host OS (derive + shell) | ACCESS→host / TARGET_*; unavailable under Paradi |
85
- | `docker_ps` / `docker_exec` / `docker_logs` | Docker on landing or derived Context | SessionPool; contextKey; auto-probes docker; unknown ≠ true |
86
- | `context_probe` | Same Context | Returns docker/kubectl tri-state |
87
-
88
- **Derived-host defaults (`TARGET_USER` / `TARGET_PASSWORD`):** optional under ssh. When both set, omit `user`/`password`. Password-only: omit password, still pass user. See one-line status in server instructions. Under Paradi, derive guidance is replaced by a “landing=TARGET / derive unsupported” note.
89
-
90
- **Docker vs k8s:** container on host Docker engine → `docker_*`; container in Kubernetes → `k8s_exec` / `k8s_logs`.
91
-
92
- ## Handshake behavior
21
+ ## First remote calls
93
22
 
94
23
  1. Connectivity unknown / first remote ops: `access_check` (ACCESS SSH probe ≤10s; ephemeral; not kubectl)
95
24
  2. Kubernetes ops only: then `shell_exec({"command":"kubectl cluster-info --request-timeout=5s"})`
96
25
 
97
- If `access_check.reachable=false`: stop; read JSON `message`/`hints` (VPN / `ACCESS_HOST`). If other tools return `code=ACCESS_UNAVAILABLE`: stop; Chinese hints are usually in `stderr`.
26
+ If `access_check.reachable=false`: stop **this YAML link**; read JSON `message`/`hints` (VPN / `ACCESS_HOST`). Other `description` values may still work. If other tools return `code=ACCESS_UNAVAILABLE` for the same link: stop that link; Chinese hints are usually in `stderr`.
98
27
 
99
- Always obtain from user or context: namespace, container name for multi-container pods. For host SSH (ssh kind): only ask user/password when `TARGET_*` are unset.
28
+ Always obtain from user or context: namespace, container name for multi-container pods. Omit `host` to stay on the link landing. Pass `host` to hop-2 from ACCESS (or to select a Paradi TARGET). For hop-2 SSH: only ask user/password when the selected link has no `TARGET_*`. Passwords already in the YAML roster: do not ask again or put them in tool arguments.
100
29
 
101
- ## Tool return format
30
+ ## YAML roster
102
31
 
103
- On **success** (`exitCode===0`), remote command output (stdout and stderr combined) is in `stdout`; the `stderr` field is empty.
32
+ The roster is a file, not a tool: `~/.agents/host-execution.yaml` (Windows `%USERPROFILE%\.agents\host-execution.yaml`). There is no `list_links` / `config_write`.
104
33
 
105
- On **command failure** (`exitCode≠0`, `success=false`, no thrown exception): merged remote output is still in **`stdout`**. Only tool/connection exceptions (e.g. `ACCESS_UNAVAILABLE`) put the message in `stderr`.
34
+ Before creating or appending a link, read `host-execution://guides/yaml`. Copy one commented block, uncomment it, set a unique `description`. Do not invent field names.
106
35
 
107
- Always check both `success` / `exitCode` and `stdout`.
36
+ - Same link = user+IP on ACCESS and on TARGET. `root@10.0.0.5` and `mccxadmin@10.0.0.5` are two links — do not merge them into one `TARGET_HOSTS`.
37
+ - New user+IP in this conversation → append to the roster unless the user says not to. Same ACCESS + same `TARGET_USER` + an extra IP → append that IP to that link's `TARGET_HOSTS`.
38
+ - `description` is a scenario label, not a frozen key. If it is misleading for how you are using the link (e.g. 「本机直连」 for a remote Xiaomo OpenClaw host), rewrite it in the YAML now — keep ACCESS/TARGET fields, make the label unique and scenario-accurate — then pass the **new** exact string. Do not keep a wrong label just because tool calls require exact match.
39
+ - Keep using the current link while the conversation still points at it. Many links: pass the exact `description`. Do not fuzzy-match. The server does not remember "last link".
40
+ - Laptop-direct hosts are each their own ACCESS landing — do not dump them into another link's `TARGET_HOSTS`. `TARGET_HOSTS` is only hop-2 from that ACCESS (same `TARGET_USER` and password).
41
+ - 0 links: tell the user to write a link from the yaml Resource. 1 link: `description` may be omitted. Many links without exact `description`: fail; list the descriptions.
42
+ - If a tool cannot meet GUIDE, tell the user.
108
43
 
109
44
  ## Shell / I/O pitfalls
110
45
 
@@ -116,21 +51,13 @@ Always check both `success` / `exitCode` and `stdout`.
116
51
  | DOCKER_CONFIG | If permission denied: `export DOCKER_CONFIG=$HOME/dockertmp && mkdir -p "$DOCKER_CONFIG"`. |
117
52
  | Registry SOP | Host with egress; `docker login` once; quoted Registry API probe. Never bare `&` in URLs. |
118
53
 
119
- ## MCP prompts
120
-
121
- | Prompt | Purpose |
122
- |--------|---------|
123
- | `tool-selection` | Pick the right tool for a scenario |
124
- | `remote-debug-workflow` | list → read/tail → ps workflow |
125
-
126
- ## Error handling
54
+ ## Errors
127
55
 
128
56
  | Situation | Action |
129
57
  |-----------|--------|
130
58
  | `truncatedByLines: true` | Increase `maxLines`, use `offset`, or use `remote_copy_file` |
131
59
  | `truncatedByChars: true` | Raise `MAX_OUTPUT_CHARS` or use `remote_copy_file` |
132
- | `ssh_exec` under Paradi | Expected error — use `shell_exec` / `target=landing` |
133
- | `ssh_exec` Permission denied | Add password or use `k8s_exec` for pods |
60
+ | hop-2 `host` Permission denied | Pass password (or use keys on ACCESS); for pods use `k8s_exec` |
134
61
  | Command `success=false` / exit≠0 | Read **stdout** |
135
62
  | Empty stdout + exit 0 (docker) | Normal for non-TTY |
136
63
  | `k8s_logs` empty | Use `remote_read_file` mode=tail for file logs |
@@ -142,7 +69,7 @@ For multi-GB landing↔local (or pod→local last hop):
142
69
 
143
70
  ```json
144
71
  {
145
- "source": { "target": "landing", "path": "/tmp/big.pt" },
72
+ "source": { "target": "remote", "path": "/tmp/big.pt" },
146
73
  "dest": { "target": "local", "path": "C:/data/big.pt" },
147
74
  "skipIfComplete": true,
148
75
  "totalTimeoutMs": 3600000,
@@ -154,8 +81,9 @@ For multi-GB landing↔local (or pod→local last hop):
154
81
  - `skipIfComplete`: skip gate follows `verify`
155
82
  - Result includes `transferId`; async jobs expose `remote_copy_status`
156
83
 
157
- | Layer | Responsibility |
158
- |-------|----------------|
159
- | **host-execution-mcp** | Access-mediated remote exec |
160
- | **User Skill** | Namespace, paths, scripts |
161
- | **User** | Approving destructive ops |
84
+ ## MCP prompts
85
+
86
+ | Prompt | Purpose |
87
+ |--------|---------|
88
+ | `tool-selection` | Pick the right tool for a scenario |
89
+ | `remote-debug-workflow` | list → read/tail → ps workflow |
@@ -1,12 +1,21 @@
1
1
  # Configuration
2
2
 
3
+ ## YAML roster (preferred when you have more than one link)
4
+
5
+ Fixed path: `~/.agents/host-execution.yaml` (Windows `%USERPROFILE%\.agents\host-execution.yaml`). No path env.
6
+
7
+ - One link = the same GUIDE §2 fields as a `mcp.json` `env` block, plus a unique `description`.
8
+ - At least one real link → YAML only. Empty `links: []` + `ACCESS_*` env → JSON below.
9
+ - Commented examples live in MCP Resource `host-execution://guides/yaml`. The user file is seeded with a short header only; existing files are never overwritten.
10
+ - Process-level `DEFAULT_TIMEOUT_MS` / `MAX_OUTPUT_CHARS` / copy job root stay in env, not per link.
11
+
3
12
  ## Access shapes (user mental model)
4
13
 
5
14
  | Shape | Env | Meaning |
6
15
  |-------|-----|---------|
7
16
  | Single host | `ACCESS_*` only | Land on ACCESS; shell / kubectl / docker there |
8
- | Bastion → target | `ACCESS_*` + `TARGET_*` | Land on ACCESS; `TARGET_*` is **default derive selector** (not a second Context at init) |
9
- | Paradi gateway | `ACCESS_KIND=paradi-gateway` + `TARGET_HOST` + `TARGET_USER` | SSH to gateway with encoded identity; landing Context = TARGET |
17
+ | Bastion → target | `ACCESS_*` + `TARGET_*` | Land on ACCESS; `TARGET_USER`/`TARGET_PASSWORD` are derive auth; `TARGET_HOSTS` is a known hop-2 list (one host = default; many = pass `host`) |
18
+ | Paradi gateway | `ACCESS_KIND=paradi-gateway` + `TARGET_HOSTS` + `TARGET_USER` | SSH to gateway with encoded identity; landing = selected TARGET (one concrete = omit `host`; many = pass `host`) |
10
19
 
11
20
  Runtime (shell / docker / kubectl) is **not** configured in mcp.json — Agent chooses from Context capabilities.
12
21
 
@@ -26,8 +35,8 @@ Runtime (shell / docker / kubectl) is **not** configured in mcp.json — Agent c
26
35
  | `ACCESS_PRIVATE_KEY_PATH` | — | Explicit private key path |
27
36
  | `ACCESS_PASSWORD` | — | Password auth (dev only); also used to build Paradi compound password when that mode wins |
28
37
  | `ACCESS_PARADI_AUTH` | `auto` | Paradi only: `auto` \| `slash` \| `compound`. Default `auto` tries slash then compound on AUTH_FAILED and **pins** the winner for this MCP process |
29
- | `TARGET_HOST` | — | Default derive host (`ssh`) or Paradi landing host |
30
- | `TARGET_USER` | — | **Required if `TARGET_HOST` set** (no fallback to `ACCESS_USER`) |
38
+ | `TARGET_HOSTS` | — | One host or comma-separated list (IP or hostname). **One entry** = default landing (`ssh` hop-2 / Paradi landing). 0 or many = pass `host`. CIDR/glob rejected. Not a JSON array string |
39
+ | `TARGET_USER` | — | **Required if `TARGET_HOSTS` set** (no fallback to `ACCESS_USER`) |
31
40
  | `TARGET_PASSWORD` | — | Default derive password (sshpass); ignored for Paradi auth |
32
41
  | `DEFAULT_TIMEOUT_MS` | `60000` | Default command timeout |
33
42
  | `MAX_OUTPUT_CHARS` | `65536` | Max tool output size |
@@ -50,6 +59,8 @@ Runtime (shell / docker / kubectl) is **not** configured in mcp.json — Agent c
50
59
  Do **not** set: `BASTION_HOST`, `BASTION_USER`, `BASTION_PORT`, `BASTION_PASSWORD`, `BASTION_PRIVATE_KEY_PATH`, `REMOTE_SSH_USER`, `REMOTE_SSH_PASSWORD`.
51
60
  If present, `loadConfig` throws with rename hints (`BASTION_HOST` → `ACCESS_HOST`, etc.).
52
61
 
62
+ `TARGET_HOST` is also removed: use `TARGET_HOSTS`.
63
+
53
64
  ## SSH authentication (ACCESS)
54
65
 
55
66
  Configure **one or more** methods; the server passes all of them to the SSH client, which tries each until one succeeds:
@@ -96,7 +107,17 @@ The server uses **stdio transport**. See [clients/](clients/).
96
107
  "ACCESS_HOST": "10.121.120.7",
97
108
  "ACCESS_USER": "mccxadmin",
98
109
  "ACCESS_PASSWORD": "<secret>",
99
- "TARGET_HOST": "10.121.35.68",
110
+ "TARGET_HOSTS": "10.121.35.68",
111
+ "TARGET_USER": "mccuseradmin",
112
+ "TARGET_PASSWORD": "<secret>"
113
+ }
114
+ ```
115
+
116
+ Same credentials, several known hop-2 hosts (no single default — Agent passes `host` from user context):
117
+
118
+ ```json
119
+ {
120
+ "TARGET_HOSTS": "10.121.35.74,10.121.33.2",
100
121
  "TARGET_USER": "mccuseradmin",
101
122
  "TARGET_PASSWORD": "<secret>"
102
123
  }
@@ -110,7 +131,7 @@ The server uses **stdio transport**. See [clients/](clients/).
110
131
  "ACCESS_HOST": "10.121.61.3",
111
132
  "ACCESS_USER": "bastion-login",
112
133
  "ACCESS_PASSWORD": "<secret>",
113
- "TARGET_HOST": "10.121.35.68",
134
+ "TARGET_HOSTS": "10.121.35.68",
114
135
  "TARGET_USER": "mccuseradmin"
115
136
  }
116
137
  ```
@@ -119,8 +140,8 @@ Customers only set gateway + target. Do **not** put a three-part SSH username or
119
140
 
120
141
  Default `ACCESS_PARADI_AUTH=auto` (may omit):
121
142
 
122
- 1. Try **slash** username `ACCESS_USER/TARGET_HOST/TARGET_USER` + `ACCESS_PASSWORD`
123
- 2. On AUTH_FAILED only, try **compound** username `ACCESS_USER` + `ACCESS_PASSWORD@##@TARGET_HOST:SSH:22:TARGET_USER`
143
+ 1. Try **slash** username `ACCESS_USER/<landing-ip>/TARGET_USER` + `ACCESS_PASSWORD`
144
+ 2. On AUTH_FAILED only, try **compound** username `ACCESS_USER` + `ACCESS_PASSWORD@##@<landing-ip>:SSH:22:TARGET_USER`
124
145
  3. Pin the winner for this MCP process (restart MCP to clear / re-probe)
125
146
 
126
147
  Ops may force `ACCESS_PARADI_AUTH=auto|slash|compound` (customers usually keep **`auto`**). One table:
@@ -133,6 +154,6 @@ Ops may force `ACCESS_PARADI_AUTH=auto|slash|compound` (customers usually keep *
133
154
 
134
155
  Do not put slash usernames or `@##@` strings in mcp.json — the server encodes them.
135
156
 
136
- Landing Context is already TARGET: use `shell_exec` / `docker_*` (omit contextKey).
157
+ Landing is a TARGET OS. One `TARGET_HOSTS` entry: omit `host`. Many entries: pass `host` on `shell_exec` / `docker_*` / `remote_*`.
137
158
 
138
159
  See [PARADI_ACCESS_PLAN.md](PARADI_ACCESS_PLAN.md) for the full Access / Runtime model.
package/docs/GUIDE.md ADDED
@@ -0,0 +1,186 @@
1
+ # host-execution
2
+
3
+ **使用场景**:经 ACCESS(SSH 跳板或帕拉迪网关)在远端执行 shell / docker / `kubectl`、读文件 / 拷贝。
4
+
5
+ Agent 把本文当作**用户期望这个 MCP 提供的能力**。配好之后用户会按下面的说法下指令。
6
+
7
+ 如设计到 k8s 环境配置,建议配套 [k8s-multi-node-deploy](../../../skill/env/k8s-multi-node-deploy/) skill。
8
+
9
+ > 包名已由 `bastion-k8s-mcp` 升级为 `host-execution-mcp`。
10
+
11
+ ## 1. 安装 Node.js
12
+
13
+ 需要 **Node.js >= 18**([nodejs.org](https://nodejs.org) LTS):
14
+
15
+ ```bash
16
+ node -v
17
+ ```
18
+
19
+ ## 2. 配置:先选 ACCESS_KIND
20
+
21
+ 配置文件:`~/.cursor/mcp.json`(或 Cursor → Settings → MCP → Edit Config)。
22
+
23
+ 先问自己一句:**本机能不能用普通** `ssh user@ip` **直接登到要用的那台机器(或跳板)?** 答案决定 `ACCESS_KIND`。
24
+
25
+
26
+ | `ACCESS_KIND` | 你的实际情况 | 一句话 |
27
+ | ---------------- | ----------------------------------------------------------- | ------ |
28
+ | `ssh`(默认) | 本机(通常开 VPN)能**正常 SSH** 到入口机 / 目标机,连上就是 bash,没有「选资产 / 选账号」菜单 | 普通 SSH |
29
+ | `paradi-gateway` | **不能**对目标机直接 `ssh`;只能先连帕拉迪网关,再在网关里交互选资产、选登录账号 | 网关菜单穿透 |
30
+
31
+
32
+ 两种写法**同一套字段**(下面 §2.1 / §2.2),不要混用、不要合并。
33
+
34
+ **YAML 名册(可改)**:`~/.agents/host-execution.yaml`(Windows:`%USERPROFILE%\.agents\host-execution.yaml`)。mcp.json 极简,不必摊一整表 `ACCESS_*`。完整注释模板见 MCP Resource `host-execution://guides/yaml`,不要在本文或对话里发明字段。
35
+
36
+ - 一条链路 = 下面一份 JSON env;每条必须有唯一 `description`,写清场景(谁、干什么、哪台),不要只写「本机直连 + IP」
37
+ - 是否同一条看 **user+IP**,不是只看 IP(`root@10.0.0.5` 与 `mccxadmin@10.0.0.5` 是两条,不要写进同一条 `TARGET_HOSTS`)
38
+ - 对话里出现新的 user+IP → 默认写入名册;仅当同一 ACCESS 且同一 `TARGET_USER`、只是多了一个目标 IP → 往该条 `TARGET_HOSTS` 追加。用户说这次不要记 → 不写
39
+ - `description` 和真实用途不符 → 当场改名册里的标签,之后按新名精确选用;精确匹配不是「旧名不可改」
40
+ - 本轮对话一直指向某一条 → 一直用那条。多条时工具带**精确** `description`。省略 `host` = 在该条入口机上执行;要再 SSH 到另一台,传 `host`(从入口机可达的 IP)
41
+ - 名册至少一条真实链路 → 只认 YAML。仅有空名册(`links: []`)且 env 有 `ACCESS_*` → 仍用下面的 JSON
42
+
43
+ **JSON / env(启动时写死)**:把 §2.1 / §2.2 写进 `mcp.json` 的 `env`。改配置要重启 MCP。
44
+
45
+ `ssh` **长什么样:** 本机 `ssh user@入口IP`,输密码后直接进 shell → 配 §2.1。
46
+
47
+ `paradi-gateway` **长什么样:** 本机只能先 `ssh 网关账号@网关IP`,连上后出现资产/账号列表要手选数字 → MCP 替你省掉这份交互(§2.2)。示意:
48
+
49
+ ![帕拉迪网关:先连网关,再选资产与账号](./paradi-gateway-interactive.png)
50
+
51
+ ### 2.1 `ACCESS_KIND=ssh`:本机能正常 SSH
52
+
53
+ 先确认本机经 VPN 能 `ssh` 到入口机,再配:
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "host-execution": {
59
+ "command": "npx",
60
+ "args": ["-y", "host-execution-mcp@latest"],
61
+ "env": {
62
+ "ACCESS_KIND": "ssh", # 可省
63
+ "ACCESS_HOST": "<入口机 IP>",
64
+ "ACCESS_USER": "<入口机用户>",
65
+ "ACCESS_PASSWORD": "<入口机密码>",
66
+ "ACCESS_PORT": "22", # 可省
67
+ }
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ `ACCESS_HOST` + `ACCESS_USER` = 本机能 SSH 直连的入口机。也可用 `ACCESS_PRIVATE_KEY_PATH` 代替密码。
74
+
75
+ 可选:
76
+
77
+ - 如果目标机器是K8s 集群控制节点,希望限制操作范围:
78
+
79
+ ```json
80
+ # 以his-test 为例
81
+ "ALLOWED_NAMESPACES": "his-test"
82
+ ```
83
+
84
+ - 常从跳板再 SSH 到某台目标机时,加默认第二跳:
85
+
86
+ ```json
87
+ "TARGET_HOSTS": "<目标机 IP>",
88
+ "TARGET_USER": "<目标机用户>",
89
+ "TARGET_PASSWORD": "<目标机密码>"
90
+ ```
91
+
92
+ - 如果从跳板再 SSH 的机器不止一个,同时用户名,密码相同,可把已知 IP 写进同一项:
93
+
94
+ ```json
95
+ "TARGET_HOSTS": "<目标机 IP>,<目标机 IP>",
96
+ "TARGET_USER": "<目标机用户>",
97
+ "TARGET_PASSWORD": "<目标机密码>"
98
+ ```
99
+
100
+ `TARGET_HOSTS` 可省,只留账号,每次对话里说 IP:
101
+
102
+ ```json
103
+ "TARGET_USER": "<目标机用户>",
104
+ "TARGET_PASSWORD": "<目标机密码>"
105
+ ```
106
+
107
+ 旧键 `TARGET_HOST` 已去掉,请改用 `TARGET_HOSTS`。
108
+
109
+ ### 2.2 `ACCESS_KIND=paradi-gateway`:经帕拉迪网关
110
+
111
+ 本机无法对业务机普通 SSH。只配**网关账号** + **目标机 IP / 系统用户**;**不要**手写三段用户名或 `@##@` 密码串(MCP 内部编码)。默认 `ACCESS_PARADI_AUTH=auto`。
112
+
113
+ ```json
114
+ {
115
+ "mcpServers": {
116
+ "host-execution-paradi": {
117
+ "command": "npx",
118
+ "args": ["-y", "host-execution-mcp@latest"],
119
+ "env": {
120
+ "ACCESS_KIND": "paradi-gateway",
121
+ "ACCESS_HOST": "<网关 IP>",
122
+ "ACCESS_PORT": "22",
123
+ "ACCESS_USER": "<网关用户>",
124
+ "ACCESS_PASSWORD": "<网关密码>",
125
+ "ACCESS_PARADI_AUTH": "auto",
126
+ "TARGET_HOSTS": "<目标机 IP>",
127
+ "TARGET_USER": "<目标机系统用户>"
128
+ }
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+
135
+ | `ACCESS_PARADI_AUTH` | 行为 | 何时用 |
136
+ | -------------------- | ---------------------------------------- | ----------- |
137
+ | **auto**(默认) | 先 slash,AUTH_FAILED 再 compound;成功后进程内钉死 | 不确定网关能力时 |
138
+ | **slash** | 用户名 `USER/HOST/OSUSER`,密码=网关密码 | 网关按三段用户名选资产 |
139
+ | **compound** | 用户名 `USER`,密码 `密码@##@HOST:SSH:22:OSUSER` | 网关已开程序穿透 |
140
+
141
+
142
+ 保存后重启 MCP。验证:
143
+
144
+ > 用 host-execution 跑 `access_check`;若要做 K8s,再让 Agent 执行 `kubectl cluster-info --request-timeout=5s`
145
+
146
+ `ACCESS_UNAVAILABLE` → 先查 VPN / 这条链路的 `ACCESS_HOST`,不要反复锤**这一条**。名册里别的 `description` 仍可试。
147
+
148
+ 本地改源码时:
149
+
150
+ ```bash
151
+ cd packages/mcp/host-execution
152
+ npm install && npm run build
153
+ ```
154
+
155
+ ## 3. 怎么用
156
+
157
+ 对 Agent **用自然语言**说清:**命名空间、负载/Pod 名、文件路径**;破坏性操作加「只读,不要改」。
158
+
159
+
160
+ | 你想做的事 | 告诉 Agent |
161
+ | ----- | ------------------------------------------------------- |
162
+ | 找 Pod | 命名空间 + Deployment/负载名 |
163
+ | 看日志 | Pod 名 + 日志**文件路径**(训练日志多在挂载盘,不是 stdout) |
164
+ | 拷到本地 | 远程路径 + 本地目录 |
165
+ | 排查故障 | 日志 / dmesg / core 路径 + 「只读分析」 |
166
+ | 上目标机 | 目标 IP + 用户(已有 `TARGET_*` 时可省略 `user`/`password`);Agent 在 `shell_exec` 等工具上传 `host` |
167
+ | 帕拉迪落点 | 一条 TARGET 时省略 `host`;多条时传 `host` 选落地机 |
168
+
169
+
170
+ 输出被截断时,让 Agent 用 `grep` / `tail` 缩小范围。
171
+
172
+ 常用工具:`access_check`、`shell_exec`、`context_probe`、`k8s_*`、`docker_*`、`remote_*` / `remote_copy_*`。
173
+
174
+ ## 常见问题
175
+
176
+ - **MCP 起不来**:查 `node -v`、入口机地址账号、本机能否 `ssh user@ACCESS_HOST`;确认已改成 `ACCESS_`*(旧* `BASTION_` 会被拒绝)。仅有空 YAML 名册时进程仍应能起来,工具会提示按 `host-execution://guides/yaml` 追加链路
177
+ - **k8s_logs 为空**:日志在文件里,让 Agent 读挂载路径,不要只用 container stdout
178
+ - **帕拉迪连不上**:确认网关开了程序穿透(或 slash 可用);可强制 `ACCESS_PARADI_AUTH=compound` / `slash`;`access_check` 成功后会带 `paradiAuth`
179
+
180
+ ## 更多文档
181
+
182
+ - YAML 名册模板(MCP Resource):`host-execution://guides/yaml`
183
+ - 工程说明:[README.md](../README.md)
184
+ - Codex / 迁移 / 场景示例:[USER_GUIDE.zh-CN.md](./USER_GUIDE.zh-CN.md)
185
+ - Agent 操作说明:[AGENT_GUIDE.md](./AGENT_GUIDE.md)
186
+ - Skill 侧示例:[skill/env/k8s-multi-node-deploy/mcp/](../../../skill/env/k8s-multi-node-deploy/mcp/)
@@ -112,7 +112,7 @@ Client ──SSH──► Context0(ACCESS) ── Runtime
112
112
  "ACCESS_HOST": "10.121.120.7",
113
113
  "ACCESS_USER": "mccxadmin",
114
114
  "ACCESS_PASSWORD": "<secret>",
115
- "TARGET_HOST": "10.121.35.68",
115
+ "TARGET_HOSTS": "10.121.35.68",
116
116
  "TARGET_USER": "mccuseradmin",
117
117
  "TARGET_PASSWORD": "<secret>"
118
118
  }
@@ -135,7 +135,7 @@ Client ──SSH──► Context0(ACCESS) ── Runtime
135
135
  "ACCESS_HOST": "10.121.61.3",
136
136
  "ACCESS_USER": "zhangyimingzgc",
137
137
  "ACCESS_PASSWORD": "<secret>",
138
- "TARGET_HOST": "10.121.35.68",
138
+ "TARGET_HOSTS": "10.121.35.68",
139
139
  "TARGET_USER": "mccuseradmin"
140
140
  }
141
141
  ```
@@ -145,7 +145,7 @@ ParadiTransport.createContext() → Context0(endpoint=T, transport=paradi-gatewa
145
145
  Client ──SSH(身份编码目标)──► T ── Runtime (Runtime 无帕拉迪分支)
146
146
  ```
147
147
 
148
- 实现细节(用户不配):`sshUsername = ACCESS_USER/TARGET_HOST/TARGET_USER`。一般不配 `TARGET_PASSWORD`。
148
+ 实现细节(用户不配):`sshUsername = ACCESS_USER/<landing-ip>/TARGET_USER`。一般不配 `TARGET_PASSWORD`。
149
149
 
150
150
  ---
151
151
 
@@ -159,8 +159,8 @@ Access **不含** `ALLOWED_NAMESPACES`。另层例如 `ACCESS_POLICY`。Phase 1
159
159
 
160
160
  | KIND | 规则 |
161
161
  |------|------|
162
- | `ssh`(默认) | ACCESS 必填;TARGET 可选;**若存在 `TARGET_HOST` → `TARGET_USER` 必填**(禁止 fallback 到 `ACCESS_USER`) |
163
- | `paradi-gateway` | ACCESS + TARGET_HOST + TARGET_USER 必填;忽略 TARGET_PASSWORD 默认认证 |
162
+ | `ssh`(默认) | ACCESS 必填;TARGET 可选;**若存在 `TARGET_HOSTS` → `TARGET_USER` 必填**(禁止 fallback 到 `ACCESS_USER`) |
163
+ | `paradi-gateway` | ACCESS + 恰好一条具体 `TARGET_HOSTS` + TARGET_USER 必填;忽略 TARGET_PASSWORD 默认认证 |
164
164
 
165
165
  `ACCESS_KIND` 仅:`ssh` | `paradi-gateway`。
166
166
 
@@ -224,7 +224,7 @@ ssh_exec(host?, command) ≡
224
224
 
225
225
  - [x] `HostExecutionContext`(无 session)+ `SessionPool`(按 key)
226
226
  - [x] `SshTransport.createContext` → 仅 Context0(ACCESS);capabilities 初值 `exec` + docker/kubectl=`unknown`
227
- - [x] loadConfig + TARGET 作 default derive;有 TARGET_HOST 则 TARGET_USER 必填;字段名 `TARGET_PASSWORD`
227
+ - [x] loadConfig + TARGET 作 default derive;有 TARGET_HOSTS 则 TARGET_USER 必填;字段名 `TARGET_PASSWORD`
228
228
  - [x] 入口 shell;**ssh_exec = derive+shell**;k8s_* 仍经 ACCESS(bastion)执行
229
229
  - [x] CONFIGURATION / AGENT_GUIDE / USER_GUIDE / clients → ACCESS_*(legacy BASTION_* 薄别名)
230
230
  - [x] 版本 3.1.0
package/docs/TODO.md CHANGED
@@ -4,26 +4,19 @@ As of **5.0.0**. Items below are intentional or deferred; do not treat as regres
4
4
 
5
5
  ## Done in 5.0 cleanup (this branch)
6
6
 
7
- - [x] Paradi Zod fail-fast: remote schemas omit `target=context` / `contextKey` under `ACCESS_KIND=paradi-gateway`
8
- - [x] Copy assert rejects Paradi `host` **and** `context` before materialize
7
+ - [x] `target=context` / `contextKey` allowed on both ssh and Paradi (removed allowContext switch)
8
+ - [x] Copy assert rejects Paradi `host` (context = selected landing)
9
9
  - [x] Agent-facing tool descriptions: drop Hop1/Hop2 jargon; docs aligned to ACCESS/Context naming
10
10
 
11
11
  ## 5.1 backlog
12
12
 
13
13
  ### 1. Remote endpoint API — remove `target=context` pollution (ssh)
14
14
 
15
- ```ts
16
- // TODO(remote-endpoint-union): Split agent-facing copy/read endpoints:
17
- // { target: landing|pod|local, path, ... } vs { contextKey, path }
18
- // Keep materialize internal; stop overloading target=context on the same union.
19
- ```
15
+ - [x] Agent-facing: `description` + optional `host`; copy `target=local|remote|pod`; read/ps use path + optional namespace/pod. `contextKey` stays internal.
20
16
 
21
17
  ### 2. KubectlRunner → SessionPool, then optional `k8s_*(contextKey)`
22
18
 
23
- ```ts
24
- // TODO(kubectl-session-pool): Route kubectl through SessionPool (same as shell/docker).
25
- // Then optionally expose k8s_*(contextKey?) for derived-host kubeconfig — doc honesty first in 5.0.
26
- ```
19
+ - [x] Route kubectl through AccessRuntime / SessionPool; `k8s_*(contextKey?)` same selection as `shell_exec`.
27
20
 
28
21
  ### 3. SessionPool TTL / LRU
29
22