host-execution-mcp 1.0.0 → 1.0.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 +7 -0
- package/README.md +1 -1
- package/dist/instructions.js +56 -56
- package/docs/AGENT_GUIDE.md +1 -1
- package/docs/CONFIGURATION.md +9 -1
- package/docs/USER_GUIDE.zh-CN.md +144 -28
- package/docs/paradi-gateway-interactive.png +0 -0
- package/package.json +65 -65
- package/dist/ssh/bastion-client.d.ts +0 -60
- package/dist/ssh/bastion-client.js +0 -423
- package/dist/ssh/bastion-client.js.map +0 -1
- package/dist/ssh/bastion-errors.d.ts +0 -62
- package/dist/ssh/bastion-errors.js +0 -190
- package/dist/ssh/bastion-errors.js.map +0 -1
- package/dist/ssh/hop1-sftp.d.ts +0 -14
- package/dist/ssh/hop1-sftp.js +0 -437
- package/dist/ssh/hop1-sftp.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.1] - 2026-09-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Soften absolute agent wording: this MCP's tool path is ACCESS→host (`do not retry these tools`), not a ban on laptop SSH.
|
|
15
|
+
- Example MCP configs (`GUIDE.md`, `mcp.example.json`, USER_GUIDE) use `host-execution-mcp@latest` so copy-paste snippets do not need a version bump.
|
|
16
|
+
|
|
10
17
|
## [1.0.0] - 2026-07-27
|
|
11
18
|
|
|
12
19
|
First public release of **`host-execution-mcp`** (new npm package name; continues the Access → HostExecutionContext → Runtime line formerly developed as `bastion-k8s-mcp`).
|
package/README.md
CHANGED
package/dist/instructions.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
1
|
function buildSshBaseInstructions() {
|
|
2
|
-
return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP.
|
|
3
|
-
|
|
4
|
-
Execution model:
|
|
5
|
-
Access: MCP client → AccessTransport → HostExecutionContext (landing)
|
|
6
|
-
Runtime: selected Context → shell / docker / k8s / copy (SessionPool; Runtime never creates SSH)
|
|
7
|
-
Derive: context_derive → contextKey (ACCESS_KIND=ssh only).
|
|
8
|
-
|
|
9
|
-
Context vs shell:
|
|
10
|
-
- context_derive — create a derived HostExecutionContext; returns contextKey (does not probe reachability)
|
|
11
|
-
- shell_exec — shell on a Context; never creates Context (omit contextKey = AccessTransport landing)
|
|
12
|
-
- ssh_exec — shortcut for context_derive + shell_exec; returns reusable contextKey. Prefer for derive+shell in one call; reuse the key for follow-up docker_*/remote_*/shell_exec
|
|
13
|
-
|
|
14
|
-
docker_* / context_probe: Runtime on selected Context.
|
|
15
|
-
Omit contextKey = AccessTransport landing (ACCESS under ssh; TARGET under paradi-gateway).
|
|
16
|
-
|
|
17
|
-
remote_* target=context = HostExecutionContext by contextKey (from context_derive / ssh_exec).
|
|
18
|
-
|
|
19
|
-
Tool selection:
|
|
20
|
-
- access_check — Local→ACCESS connectivity (≤10s; NOT kubectl). First session / after ACCESS_UNAVAILABLE
|
|
21
|
-
- shell_exec — landing or derived shell (contextKey)
|
|
22
|
-
- context_derive — need a contextKey without running a command yet
|
|
23
|
-
- ssh_exec — one-shot derive+shell (returns contextKey)
|
|
24
|
-
- docker_* — Docker on landing or contextKey
|
|
25
|
-
- k8s_* — kubectl on landing only (by design). kubectl on a derived host: shell_exec(contextKey, "kubectl …")
|
|
26
|
-
- remote_* target=landing|pod|context — files/ps/copy
|
|
27
|
-
- remote_copy_file vs remote_copy_start — sync vs async; never auto-promote; prefer start when size>256MB or ETA>2min
|
|
28
|
-
|
|
29
|
-
Hard rules:
|
|
30
|
-
- access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST); do not retry
|
|
31
|
-
- SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across Contexts
|
|
32
|
-
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
33
|
-
- Never assume namespace/paths; never reuse ACCESS_USER as TARGET_USER / derive user
|
|
34
|
-
- success=false: read stdout (stderr merged). truncated → more lines / remote_copy_*
|
|
35
|
-
- Multi-container pods: pass container name
|
|
2
|
+
return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP.
|
|
3
|
+
|
|
4
|
+
Execution model:
|
|
5
|
+
Access: MCP client → AccessTransport → HostExecutionContext (landing)
|
|
6
|
+
Runtime: selected Context → shell / docker / k8s / copy (SessionPool; Runtime never creates SSH)
|
|
7
|
+
Derive: context_derive → contextKey (ACCESS_KIND=ssh only). This tool path is ACCESS→host, not laptop SSH.
|
|
8
|
+
|
|
9
|
+
Context vs shell:
|
|
10
|
+
- context_derive — create a derived HostExecutionContext; returns contextKey (does not probe reachability)
|
|
11
|
+
- shell_exec — shell on a Context; never creates Context (omit contextKey = AccessTransport landing)
|
|
12
|
+
- ssh_exec — shortcut for context_derive + shell_exec; returns reusable contextKey. Prefer for derive+shell in one call; reuse the key for follow-up docker_*/remote_*/shell_exec
|
|
13
|
+
|
|
14
|
+
docker_* / context_probe: Runtime on selected Context.
|
|
15
|
+
Omit contextKey = AccessTransport landing (ACCESS under ssh; TARGET under paradi-gateway).
|
|
16
|
+
|
|
17
|
+
remote_* target=context = HostExecutionContext by contextKey (from context_derive / ssh_exec).
|
|
18
|
+
|
|
19
|
+
Tool selection:
|
|
20
|
+
- access_check — Local→ACCESS connectivity (≤10s; NOT kubectl). First session / after ACCESS_UNAVAILABLE
|
|
21
|
+
- shell_exec — landing or derived shell (contextKey)
|
|
22
|
+
- context_derive — need a contextKey without running a command yet
|
|
23
|
+
- ssh_exec — one-shot derive+shell (returns contextKey)
|
|
24
|
+
- docker_* — Docker on landing or contextKey
|
|
25
|
+
- k8s_* — kubectl on landing only (by design). kubectl on a derived host: shell_exec(contextKey, "kubectl …")
|
|
26
|
+
- remote_* target=landing|pod|context — files/ps/copy
|
|
27
|
+
- remote_copy_file vs remote_copy_start — sync vs async; never auto-promote; prefer start when size>256MB or ETA>2min
|
|
28
|
+
|
|
29
|
+
Hard rules:
|
|
30
|
+
- access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST); do not retry these tools
|
|
31
|
+
- SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across Contexts
|
|
32
|
+
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
33
|
+
- Never assume namespace/paths; never reuse ACCESS_USER as TARGET_USER / derive user
|
|
34
|
+
- success=false: read stdout (stderr merged). truncated → more lines / remote_copy_*
|
|
35
|
+
- Multi-container pods: pass container name
|
|
36
36
|
- Operational cookbook (shell quoting, CRLF, docker login quirks, registry probes): see docs/AGENT_GUIDE.md`;
|
|
37
37
|
}
|
|
38
38
|
function buildParadiBaseInstructions(config) {
|
|
39
39
|
const target = config.targetHost?.trim() || "<TARGET_HOST>";
|
|
40
|
-
return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP (ACCESS_KIND=paradi-gateway).
|
|
41
|
-
|
|
42
|
-
Landing endpoint is TARGET (${target}) — not the gateway OS. Runtime does not know gateway details; never creates SSH.
|
|
43
|
-
|
|
44
|
-
Derive / context_derive / ssh_exec / remote_* target=context / contextKey: unsupported by current Paradi AccessTransport (landing is already TARGET). Handlers throw if called — omit contextKey; use target=landing|pod|local.
|
|
45
|
-
|
|
46
|
-
Default workflow:
|
|
47
|
-
- Shell: shell_exec or remote_* target=landing
|
|
48
|
-
- Docker / context_probe: omit contextKey (landing = TARGET)
|
|
49
|
-
- Pods: k8s_* / remote_* target=pod (kubectl on landing)
|
|
50
|
-
- Copy: local↔landing or pod/local; SFTP degraded — prefer remote_copy_start for large files
|
|
51
|
-
|
|
52
|
-
Hard rules:
|
|
53
|
-
- access_check.reachable=false or ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST)
|
|
54
|
-
- unknown ≠ true; SSH success ≠ docker/kubectl; never reuse capabilities across Contexts
|
|
55
|
-
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
56
|
-
- Never assume namespace/paths
|
|
40
|
+
return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP (ACCESS_KIND=paradi-gateway).
|
|
41
|
+
|
|
42
|
+
Landing endpoint is TARGET (${target}) — not the gateway OS. Runtime does not know gateway details; never creates SSH.
|
|
43
|
+
|
|
44
|
+
Derive / context_derive / ssh_exec / remote_* target=context / contextKey: unsupported by current Paradi AccessTransport (landing is already TARGET). Handlers throw if called — omit contextKey; use target=landing|pod|local.
|
|
45
|
+
|
|
46
|
+
Default workflow:
|
|
47
|
+
- Shell: shell_exec or remote_* target=landing
|
|
48
|
+
- Docker / context_probe: omit contextKey (landing = TARGET)
|
|
49
|
+
- Pods: k8s_* / remote_* target=pod (kubectl on landing)
|
|
50
|
+
- Copy: local↔landing or pod/local; SFTP degraded — prefer remote_copy_start for large files
|
|
51
|
+
|
|
52
|
+
Hard rules:
|
|
53
|
+
- access_check.reachable=false or ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST)
|
|
54
|
+
- unknown ≠ true; SSH success ≠ docker/kubectl; never reuse capabilities across Contexts
|
|
55
|
+
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
56
|
+
- Never assume namespace/paths
|
|
57
57
|
- Operational cookbook: docs/AGENT_GUIDE.md`;
|
|
58
58
|
}
|
|
59
59
|
/** TARGET_* default derive auth so agents omit configured defaults instead of asking the human. */
|
|
60
60
|
export function buildDerivedHostAuthGuidance(config) {
|
|
61
61
|
if (config.accessKind === "paradi-gateway") {
|
|
62
62
|
const host = config.targetHost?.trim();
|
|
63
|
-
return `
|
|
63
|
+
return `
|
|
64
64
|
Paradi landing: Context endpoint is TARGET${host ? ` (${host})` : ""}. Derive unsupported by current Paradi AccessTransport — omit contextKey; context_derive / ssh_exec / target=context throw if called. Use shell_exec, docker_*, k8s_*, target=landing|pod|local.`;
|
|
65
65
|
}
|
|
66
66
|
const user = config.targetUser?.trim();
|
|
@@ -70,18 +70,18 @@ Paradi landing: Context endpoint is TARGET${host ? ` (${host})` : ""}. Derive un
|
|
|
70
70
|
const noAccessUserFallback = " Never reuse ACCESS_USER as TARGET_USER / derive user — pass TARGET_USER (or tool user) explicitly.";
|
|
71
71
|
const shortcutHint = " ssh_exec = context_derive + shell_exec shortcut (returns reusable contextKey).";
|
|
72
72
|
if (!user && !passwordSet) {
|
|
73
|
-
return `
|
|
73
|
+
return `
|
|
74
74
|
Derive host auth: TARGET_* unset — pass user (password if no key).${hostHint}${noAccessUserFallback}${shortcutHint} Do not invent defaults.`;
|
|
75
75
|
}
|
|
76
76
|
if (user && passwordSet) {
|
|
77
|
-
return `
|
|
77
|
+
return `
|
|
78
78
|
Derive host auth: TARGET_* active (user=${user}, password=set)${hostHint} — omit user/password on context_derive / ssh_exec; do not ask the human. Override only for a different account.${noAccessUserFallback}${shortcutHint}`;
|
|
79
79
|
}
|
|
80
80
|
if (user) {
|
|
81
|
-
return `
|
|
81
|
+
return `
|
|
82
82
|
Derive host auth: TARGET_USER=${user}${hostHint} — omit user on context_derive / ssh_exec; pass password only if no key.${noAccessUserFallback}${shortcutHint}`;
|
|
83
83
|
}
|
|
84
|
-
return `
|
|
84
|
+
return `
|
|
85
85
|
Derive host auth: TARGET_PASSWORD set${hostHint} — omit password on context_derive / ssh_exec; still pass user (TARGET_USER unset). Do not invent a username.${noAccessUserFallback}${shortcutHint}`;
|
|
86
86
|
}
|
|
87
87
|
export function buildServerInstructions(config) {
|
package/docs/AGENT_GUIDE.md
CHANGED
|
@@ -15,7 +15,7 @@ User config is `ACCESS_*` / `TARGET_*` only. Async copy root: `ACCESS_COPY_JOB_R
|
|
|
15
15
|
|
|
16
16
|
## Architecture (read this first)
|
|
17
17
|
|
|
18
|
-
**
|
|
18
|
+
**On this MCP path**, there is no laptop SSH to pods or cluster nodes.
|
|
19
19
|
|
|
20
20
|
### Shape A — ACCESS_KIND=ssh
|
|
21
21
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -123,7 +123,15 @@ Default `ACCESS_PARADI_AUTH=auto` (may omit):
|
|
|
123
123
|
2. On AUTH_FAILED only, try **compound** username `ACCESS_USER` + `ACCESS_PASSWORD@##@TARGET_HOST:SSH:22:TARGET_USER`
|
|
124
124
|
3. Pin the winner for this MCP process (restart MCP to clear / re-probe)
|
|
125
125
|
|
|
126
|
-
Ops
|
|
126
|
+
Ops may force `ACCESS_PARADI_AUTH=auto|slash|compound` (customers usually keep **`auto`**). One table:
|
|
127
|
+
|
|
128
|
+
| Mode | Username | Password | Fit | Example (manual SSH equivalent) |
|
|
129
|
+
| --- | --- | --- | --- | --- |
|
|
130
|
+
| **auto** (default) | Try slash first; on AUTH_FAILED try compound; pin winner for this process | same as winners | Unknown which gateway capability is enabled | No manual pick; `access_check` may show `paradiAuth` |
|
|
131
|
+
| **slash** | `USER/HOST/OSUSER` | gateway password | Gateway selects asset via slash username | `ssh zhangyimingzgc/10.121.35.68/mccuseradmin@10.121.61.3` (password = gateway password; gateway `10.121.61.3` → `10.121.35.68` / `mccuseradmin`) |
|
|
132
|
+
| **compound** | `USER` | `password@##@HOST:SSH:22:OSUSER` | Gateway has program penetration | `ssh ellazj@10.121.61.10` (password = `gatewayPassword@##@10.121.35.74:SSH:22:mccuseradmin`; gateway `10.121.61.10` → `10.121.35.74` / `mccuseradmin`) |
|
|
133
|
+
|
|
134
|
+
Do not put slash usernames or `@##@` strings in mcp.json — the server encodes them.
|
|
127
135
|
|
|
128
136
|
Landing Context is already TARGET: use `shell_exec` / `docker_*` (omit contextKey).
|
|
129
137
|
|
package/docs/USER_GUIDE.zh-CN.md
CHANGED
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
# host-execution-mcp 使用教程
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**使用场景:本地可以直连入口机(跳板 / 帕拉迪网关),再进入 K8s 集群或目标主机,AI 辅助分析代码、文件传输等等。**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**本机 Cursor → SSH(ACCESS)→ 落点 HostExecutionContext → kubectl / docker / shell / 再跳目标机**(这条路径上笔记本不直连 Pod)。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> 包名已由 `bastion-k8s-mcp` 升级为 **`host-execution-mcp`**。环境变量统一为 `ACCESS_*` / `TARGET_*`(不再使用 `BASTION_*` / `REMOTE_SSH_*`)。
|
|
8
|
+
|
|
9
|
+
:::
|
|
10
|
+
建议配套 [**k8s-multi-node-deploy**](https://sh-code.mthreads.com/andy.wang/agent-compose/-/tree/master/skill/env/k8s-multi-node-deploy?ref_type=heads) skill 效果更佳~~~,无法访问联系我 $\color{#0089FF}{@Andy Wang}$
|
|
11
|
+
:::
|
|
8
12
|
|
|
9
13
|
## 1. 安装 Node.js
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
MCP 需要运行在 Node.js 环境上,**Node.js >= 18**。官网 [nodejs.org](https://nodejs.org) 下载 LTS,安装后验证:
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
18
|
node -v
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
## 2. MCP 配置(Cursor)
|
|
21
|
+
## 2. MCP 配置(Cursor 为例)
|
|
20
22
|
|
|
21
23
|
配置文件:`.cursor/mcp.json`,或 Cursor → Settings → MCP → Edit Config。
|
|
22
24
|
|
|
25
|
+
先问自己一句:**本机能不能用普通 `ssh user@ip` 直接登到要用的那台机器(或跳板)?** 答案决定 `ACCESS_KIND`。
|
|
26
|
+
|
|
27
|
+
| `ACCESS_KIND` | 你的实际情况 | 一句话 |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| **`ssh`**(默认) | 本机(通常开 VPN)能**正常 SSH** 到入口机 / 目标机,连上就是 bash,没有「选资产 / 选账号」菜单 | 普通 SSH 场景 |
|
|
30
|
+
| **`paradi-gateway`** | **不能**对目标机直接 `ssh`;只能先连帕拉迪网关,再在网关里交互选资产、选登录账号,才能落到业务机 | 网关菜单穿透场景(见下图) |
|
|
31
|
+
|
|
32
|
+
**`ssh` 长什么样:** 本机执行例如 `ssh mccxadmin@10.121.120.7`,输密码后直接进系统 shell —— 配 `ACCESS_KIND=ssh`(§2.1)。
|
|
33
|
+
|
|
34
|
+
**`paradi-gateway` 长什么样:** 本机只能先 `ssh 网关账号@网关IP`,连上后出现「目标资产列表 / 登录帐号列表」,要手选数字才能进机器 —— **MCP 替你省掉这份交互**,用编码账号/密码直接落到目标机(§2.2)。真实终端示意:
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
选好模式后,抄下面对应小节的 `env`。
|
|
39
|
+
|
|
40
|
+
### 2.1 `ACCESS_KIND=ssh`:本机能正常 SSH(跳板 / K8s)
|
|
41
|
+
|
|
42
|
+
:::
|
|
43
|
+
**需要先验证本地机器通过 VPN 能登录到 `10.121.120.7` 才行(找四季青运维)**
|
|
44
|
+
:::
|
|
45
|
+
|
|
23
46
|
```json
|
|
24
47
|
{
|
|
25
48
|
"mcpServers": {
|
|
@@ -27,67 +50,160 @@ node -v
|
|
|
27
50
|
"command": "npx",
|
|
28
51
|
"args": ["-y", "host-execution-mcp@latest"],
|
|
29
52
|
"env": {
|
|
53
|
+
"ACCESS_KIND": "ssh",
|
|
30
54
|
"ACCESS_HOST": "10.121.120.7",
|
|
31
|
-
"ACCESS_USER": "
|
|
55
|
+
"ACCESS_USER": "mccxadmin",
|
|
56
|
+
"ACCESS_PASSWORD": "mccxadminjd",
|
|
57
|
+
"ACCESS_PORT": "22",
|
|
58
|
+
"ALLOWED_NAMESPACES": "his-test"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`ACCESS_HOST` + `ACCESS_USER` 填你**本机能 SSH 直连的入口机**地址和账号即可(MCP 会用同样的方式登录)。
|
|
66
|
+
|
|
67
|
+
可选:若常从跳板再 SSH 到某台目标机,可加默认第二跳:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
"TARGET_HOST": "10.121.32.69",
|
|
71
|
+
"TARGET_USER": "mccxadmin",
|
|
72
|
+
"TARGET_PASSWORD": "mccxadmin"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2.2 `ACCESS_KIND=paradi-gateway`:不能直连目标机,经帕拉迪网关
|
|
76
|
+
|
|
77
|
+
本机**无法**对业务机普通 SSH;只能连网关。客户只需配**网关账号** + **目标机 IP/系统用户**;**不要**手写三段用户名或 `@##@` 密码串(MCP 内部编码,效果等价于你在菜单里选好资产与账号)。默认 `ACCESS_PARADI_AUTH=auto`:先试 slash,失败再试 compound,成功后进程内钉死。
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"host-execution-paradi": {
|
|
83
|
+
"command": "npx",
|
|
84
|
+
"args": ["-y", "host-execution-mcp@latest"],
|
|
85
|
+
"env": {
|
|
86
|
+
"ACCESS_KIND": "paradi-gateway",
|
|
87
|
+
"ACCESS_HOST": "10.121.61.10",
|
|
88
|
+
"ACCESS_PORT": "22",
|
|
89
|
+
"ACCESS_USER": "ellazj",
|
|
90
|
+
"ACCESS_PASSWORD": "<网关密码>",
|
|
91
|
+
"ACCESS_PARADI_AUTH": "auto",
|
|
92
|
+
"TARGET_HOST": "10.121.35.74",
|
|
93
|
+
"TARGET_USER": "mccuseradmin"
|
|
32
94
|
}
|
|
33
95
|
}
|
|
34
96
|
}
|
|
35
97
|
}
|
|
36
98
|
```
|
|
37
99
|
|
|
38
|
-
`
|
|
100
|
+
运维可强制:`ACCESS_PARADI_AUTH` = `auto` | `slash` | `compound`(一般客户保持 **`auto`** 即可)。对照表:
|
|
101
|
+
|
|
102
|
+
| 模式 | 用户名 | 密码 | 适合 | 实际场景(手动 SSH 等价) |
|
|
103
|
+
| --- | --- | --- | --- | --- |
|
|
104
|
+
| **auto**(默认) | 先按 slash,AUTH_FAILED 再按 compound;成功后进程内钉死赢家 | 同上 | 不确定网关开了哪种能力时 | 无需手选;`access_check` 可看 `paradiAuth` |
|
|
105
|
+
| **slash** | `USER/HOST/OSUSER` | 网关密码 | 网关按三段用户名选资产 | `ssh zhangyimingzgc/10.121.35.68/mccuseradmin@10.121.61.3`,密码填网关密码(网关 `10.121.61.3` → `10.121.35.68` / `mccuseradmin`) |
|
|
106
|
+
| **compound** | `USER` | `密码@##@HOST:SSH:22:OSUSER` | 网关已开程序穿透 | `ssh ellazj@10.121.61.10`,密码填 `网关密码@##@10.121.35.74:SSH:22:mccuseradmin`(网关 `10.121.61.10` → `10.121.35.74` / `mccuseradmin`) |
|
|
107
|
+
|
|
108
|
+
mcp.json **不要**手写三段用户名或 `@##@` 串,由 MCP 按上表编码。
|
|
39
109
|
|
|
40
110
|
保存后重启 MCP 服务。验证连通:
|
|
41
111
|
|
|
42
|
-
>
|
|
112
|
+
> 用 host-execution 跑 `access_check`;若要做 K8s,再让 Agent 执行 `kubectl cluster-info --request-timeout=5s`
|
|
43
113
|
|
|
44
|
-
若提示 `ACCESS_UNAVAILABLE
|
|
114
|
+
若提示 `ACCESS_UNAVAILABLE`:先查 VPN / `ACCESS_HOST`,不要反复重试本 MCP 的其他工具。
|
|
45
115
|
|
|
46
116
|
---
|
|
47
117
|
|
|
48
118
|
## 3. 怎么用
|
|
49
119
|
|
|
50
|
-
对 Agent **用自然语言**说清:**命名空间、负载/Pod
|
|
120
|
+
对 Agent **用自然语言**说清:**命名空间、负载/Pod 名、文件路径**;**需要时加「只读,不要改」**,可减少 AI 操作带来的不确定性风险(尤其破坏性操作)。
|
|
51
121
|
|
|
52
122
|
| 你想做的事 | 告诉 Agent |
|
|
53
|
-
|
|
123
|
+
| --- | --- |
|
|
54
124
|
| 找 Pod | 命名空间 + Deployment/负载名 |
|
|
55
125
|
| 看日志 | Pod 名 + 日志**文件路径**(训练日志多在挂载盘,不是 stdout) |
|
|
56
126
|
| 拷到本地 | 远程路径 + 本地目录(Agent 读取后写入本机) |
|
|
57
127
|
| 排查故障 | 日志 / dmesg / core 路径 + 「只读分析」 |
|
|
128
|
+
| 上目标机 | 目标 IP + 用户(有 `TARGET_*` 时可省略,让 Agent `context_derive` / 跳板执行) |
|
|
129
|
+
| 帕拉迪落点 | 已在目标机:直接 `shell_exec` / `docker_*`,不要再 derive |
|
|
58
130
|
|
|
59
131
|
输出太大被截断时,让 Agent 用 `grep`、`tail` 缩小范围。
|
|
60
132
|
|
|
61
|
-
|
|
133
|
+
常用工具(Agent 侧):`access_check`、`shell_exec`、`context_derive`、`k8s_*`、`docker_*`、`remote_*` / `remote_copy_*`。
|
|
62
134
|
|
|
63
|
-
|
|
135
|
+
---
|
|
64
136
|
|
|
65
|
-
|
|
137
|
+
## 4. 示例
|
|
66
138
|
|
|
67
|
-
|
|
139
|
+
1. MCP + SKILL → 让从零重新创建一个负载,然后拉 128 个节点
|
|
68
140
|
|
|
69
|
-
|
|
141
|
+

|
|
70
142
|
|
|
71
|
-
|
|
143
|
+
2. 帮进行多机 mccl-test 测试(替换新 mccl 测试)
|
|
72
144
|
|
|
73
|
-
|
|
145
|
+
(上下文信息已经有了对应 16 机信息)
|
|
74
146
|
|
|
75
|
-
|
|
147
|
+

|
|
76
148
|
|
|
77
|
-
|
|
149
|
+
3. 批量配置 128 机环境,并帮拉起训练做对比验证
|
|
78
150
|
|
|
79
|
-
|
|
151
|
+

|
|
80
152
|
|
|
81
|
-
|
|
153
|
+
4. 负载任务
|
|
82
154
|
|
|
83
|
-
|
|
155
|
+

|
|
84
156
|
|
|
85
157
|
---
|
|
86
158
|
|
|
87
159
|
## 常见问题
|
|
88
160
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
161
|
+
* **MCP 起不来**:检查 `node -v`、入口机地址账号、本机能否 `ssh user@10.121.120.7`;确认 env 已改成 `ACCESS_*`(旧 `BASTION_*` 会被拒绝)
|
|
162
|
+
* **仍配置 BASTION_***:会报错并提示改名;按上文 JSON 换成 `ACCESS_HOST` / `ACCESS_USER` / `ACCESS_PASSWORD`
|
|
163
|
+
* **k8s_logs 为空**:日志在文件里,让 Agent 读挂载路径,不要只用 container stdout
|
|
164
|
+
* **多个节点都 Killed**:先找第一个报 MUSA/SIGABRT 的 rank,其余可能是连锁退出
|
|
165
|
+
* **帕拉迪连不上**:确认网关开了程序穿透(或 slash 可用);可设 `ACCESS_PARADI_AUTH=compound` / `slash` 强制一种;`access_check` 成功后会带 `paradiAuth`
|
|
92
166
|
|
|
93
167
|
更多配置见 [CONFIGURATION.md](./CONFIGURATION.md)。
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
# 补充:
|
|
172
|
+
|
|
173
|
+
## Codex 使用
|
|
174
|
+
|
|
175
|
+
本地 vscode + codex 也可用。
|
|
176
|
+
|
|
177
|
+
将上述《host-execution-mcp 使用教程》的配置拷贝给 codex 插件,直接让其根据该配置,自动本地配好 MCP server。
|
|
178
|
+
|
|
179
|
+
配置好后大概如下:
|
|
180
|
+
|
|
181
|
+

|
|
182
|
+
|
|
183
|
+
也可以打开 `~/.codex/config.toml`(或本机 Codex 配置)增加配置如下:
|
|
184
|
+
|
|
185
|
+
```toml
|
|
186
|
+
[mcp_servers.host-execution]
|
|
187
|
+
command = "npx"
|
|
188
|
+
args = ["-y", "host-execution-mcp@latest"]
|
|
189
|
+
|
|
190
|
+
[mcp_servers.host-execution.env]
|
|
191
|
+
ALLOWED_NAMESPACES = "his-test"
|
|
192
|
+
ACCESS_KIND = "ssh"
|
|
193
|
+
ACCESS_HOST = "10.121.120.7"
|
|
194
|
+
ACCESS_PASSWORD = "mccxadminjd"
|
|
195
|
+
ACCESS_PORT = "22"
|
|
196
|
+
ACCESS_USER = "mccxadmin"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
> 使用时整个 vscode 窗口只能当作一个类似 Codex 桌面版 app,建议配合 terminal 使用。
|
|
200
|
+
|
|
201
|
+
## 与旧包对照(迁移)
|
|
202
|
+
|
|
203
|
+
| 旧(bastion-k8s-mcp) | 新(host-execution-mcp) |
|
|
204
|
+
| --- | --- |
|
|
205
|
+
| `bastion-k8s-mcp@3.x` | `host-execution-mcp@1.0.0` |
|
|
206
|
+
| `BASTION_HOST` / `USER` / `PASSWORD` / `PORT` | `ACCESS_HOST` / `USER` / `PASSWORD` / `PORT` |
|
|
207
|
+
| `REMOTE_SSH_USER` / `PASSWORD` | `TARGET_USER` / `TARGET_PASSWORD` |
|
|
208
|
+
| `bastion_check` / `bastion_exec` | `access_check` / `shell_exec` |
|
|
209
|
+
| — | `ACCESS_KIND=paradi-gateway` + `TARGET_*`(帕拉迪) |
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "host-execution-mcp",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Access -> HostExecutionContext -> Runtime MCP for remote shell/docker/kubectl (SSH jump or Paradi gateway)",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"host-execution-mcp": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"README.md",
|
|
13
|
-
"LICENSE",
|
|
14
|
-
"CHANGELOG.md",
|
|
15
|
-
"SECURITY.md",
|
|
16
|
-
"docs"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsc",
|
|
20
|
-
"start": "node dist/index.js",
|
|
21
|
-
"dev": "tsc && node dist/index.js",
|
|
22
|
-
"test": "node --import tsx --test tests/*.test.ts",
|
|
23
|
-
"lint": "eslint src tests",
|
|
24
|
-
"format": "prettier --write .",
|
|
25
|
-
"format:check": "prettier --check .",
|
|
26
|
-
"prepublishOnly": "npm run build && npm test"
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": ">=18"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"mcp",
|
|
33
|
-
"host-execution",
|
|
34
|
-
"kubernetes",
|
|
35
|
-
"kubectl",
|
|
36
|
-
"ssh",
|
|
37
|
-
"paradi"
|
|
38
|
-
],
|
|
39
|
-
"license": "MIT",
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/your-org/host-execution-mcp.git"
|
|
43
|
-
},
|
|
44
|
-
"bugs": {
|
|
45
|
-
"url": "https://github.com/your-org/host-execution-mcp/issues"
|
|
46
|
-
},
|
|
47
|
-
"homepage": "https://github.com/your-org/host-execution-mcp#readme",
|
|
48
|
-
"dependencies": {
|
|
49
|
-
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
50
|
-
"ssh2": "^1.16.0",
|
|
51
|
-
"ssh2-sftp-client": "^12.1.1",
|
|
52
|
-
"zod": "^3.24.2"
|
|
53
|
-
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@eslint/js": "^9.23.0",
|
|
56
|
-
"@types/node": "^22.13.10",
|
|
57
|
-
"@types/ssh2": "^1.15.4",
|
|
58
|
-
"@types/ssh2-sftp-client": "^9.0.6",
|
|
59
|
-
"eslint": "^9.23.0",
|
|
60
|
-
"prettier": "^3.5.3",
|
|
61
|
-
"tsx": "^4.19.3",
|
|
62
|
-
"typescript": "^5.8.2",
|
|
63
|
-
"typescript-eslint": "^8.28.0"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "host-execution-mcp",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Access -> HostExecutionContext -> Runtime MCP for remote shell/docker/kubectl (SSH jump or Paradi gateway)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"host-execution-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"CHANGELOG.md",
|
|
15
|
+
"SECURITY.md",
|
|
16
|
+
"docs"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "tsc && node dist/index.js",
|
|
22
|
+
"test": "node --import tsx --test tests/*.test.ts",
|
|
23
|
+
"lint": "eslint src tests",
|
|
24
|
+
"format": "prettier --write .",
|
|
25
|
+
"format:check": "prettier --check .",
|
|
26
|
+
"prepublishOnly": "npm run build && npm test"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mcp",
|
|
33
|
+
"host-execution",
|
|
34
|
+
"kubernetes",
|
|
35
|
+
"kubectl",
|
|
36
|
+
"ssh",
|
|
37
|
+
"paradi"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/your-org/host-execution-mcp.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/your-org/host-execution-mcp/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/your-org/host-execution-mcp#readme",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
50
|
+
"ssh2": "^1.16.0",
|
|
51
|
+
"ssh2-sftp-client": "^12.1.1",
|
|
52
|
+
"zod": "^3.24.2"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@eslint/js": "^9.23.0",
|
|
56
|
+
"@types/node": "^22.13.10",
|
|
57
|
+
"@types/ssh2": "^1.15.4",
|
|
58
|
+
"@types/ssh2-sftp-client": "^9.0.6",
|
|
59
|
+
"eslint": "^9.23.0",
|
|
60
|
+
"prettier": "^3.5.3",
|
|
61
|
+
"tsx": "^4.19.3",
|
|
62
|
+
"typescript": "^5.8.2",
|
|
63
|
+
"typescript-eslint": "^8.28.0"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { AppConfig } from "../config.js";
|
|
2
|
-
import { type SftpCopyOptions, type SftpTransferResult } from "../utils/copy-transfer.js";
|
|
3
|
-
import { type AccessCheckResult } from "./bastion-errors.js";
|
|
4
|
-
export interface ExecOutput {
|
|
5
|
-
stdout: string;
|
|
6
|
-
stderr: string;
|
|
7
|
-
exitCode: number;
|
|
8
|
-
durationMs: number;
|
|
9
|
-
}
|
|
10
|
-
export declare class BastionClient {
|
|
11
|
-
private client;
|
|
12
|
-
private connecting;
|
|
13
|
-
/** Serializes ensureBastionReady / check cache updates. */
|
|
14
|
-
private gate;
|
|
15
|
-
private readonly config;
|
|
16
|
-
private readyUntil;
|
|
17
|
-
private unavailableUntil;
|
|
18
|
-
private lastUnavailable;
|
|
19
|
-
constructor(config: AppConfig);
|
|
20
|
-
/**
|
|
21
|
-
* Ensure bastion is reachable (TTL-cached). Uses an ephemeral SSH probe ?
|
|
22
|
-
* never disconnects an in-flight shared exec session on success.
|
|
23
|
-
*/
|
|
24
|
-
ensureBastionReady(): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Short-timeout Local to ACCESS probe (ephemeral client; <=10s worst case).
|
|
27
|
-
* Respects negative TTL (returns cached failure). Does not sever shared exec SSH.
|
|
28
|
-
*/
|
|
29
|
-
check(): Promise<AccessCheckResult>;
|
|
30
|
-
exec(command: string, timeoutMs?: number, cwd?: string, signal?: AbortSignal): Promise<ExecOutput>;
|
|
31
|
-
disconnect(): void;
|
|
32
|
-
/**
|
|
33
|
-
* Upload local path (file or directory) ? bastion via independent Hop1 SFTP.
|
|
34
|
-
* Transfer-phase errors are not reclassified into ACCESS_UNAVAILABLE.
|
|
35
|
-
*/
|
|
36
|
-
uploadPath(localPath: string, remotePath: string, options?: SftpCopyOptions): Promise<SftpTransferResult>;
|
|
37
|
-
/**
|
|
38
|
-
* Download bastion path (file or directory) ? local via independent Hop1 SFTP.
|
|
39
|
-
*/
|
|
40
|
-
downloadPath(remotePath: string, localPath: string, options?: SftpCopyOptions): Promise<SftpTransferResult>;
|
|
41
|
-
private withGate;
|
|
42
|
-
private markReady;
|
|
43
|
-
/**
|
|
44
|
-
* Record a connect-phase failure. Negative TTL only for classified causes
|
|
45
|
-
* (not UNKNOWN), so transient unknowns are not blackholed for 15s.
|
|
46
|
-
*/
|
|
47
|
-
private markConnectUnavailable;
|
|
48
|
-
/** Ephemeral SSH + shell probe; never assigns or disconnects `this.client`. */
|
|
49
|
-
private probeEphemeral;
|
|
50
|
-
private remoteSha256;
|
|
51
|
-
private ensureConnected;
|
|
52
|
-
private ensureConnectedUnlocked;
|
|
53
|
-
private requireClient;
|
|
54
|
-
/**
|
|
55
|
-
* Open a dedicated ssh2 Client with readyTimeout + hard deadline
|
|
56
|
-
* (covers TCP blackhole where ssh2 readyTimeout alone is insufficient).
|
|
57
|
-
*/
|
|
58
|
-
private openSshClient;
|
|
59
|
-
private execOnClient;
|
|
60
|
-
}
|