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.
- package/CHANGELOG.md +37 -0
- package/README.md +13 -11
- package/SECURITY.md +3 -3
- package/dist/access/index.d.ts +21 -10
- package/dist/access/index.js +55 -27
- package/dist/access/index.js.map +1 -1
- package/dist/access/paradi-auth.d.ts +3 -3
- package/dist/access/paradi-auth.js +4 -4
- package/dist/access/paradi-auth.js.map +1 -1
- package/dist/access/paradi-transport.d.ts +1 -1
- package/dist/access/paradi-transport.js +3 -3
- package/dist/access/paradi-transport.js.map +1 -1
- package/dist/access/paradi-username.d.ts +1 -1
- package/dist/access/paradi-username.js +2 -2
- package/dist/access/paradi-username.js.map +1 -1
- package/dist/access/session-pool.d.ts +5 -0
- package/dist/access/session-pool.js +7 -0
- package/dist/access/session-pool.js.map +1 -1
- package/dist/access/ssh-transport.d.ts +1 -1
- package/dist/access/ssh-transport.js +3 -2
- package/dist/access/ssh-transport.js.map +1 -1
- package/dist/config-yaml.d.ts +54 -0
- package/dist/config-yaml.js +172 -0
- package/dist/config-yaml.js.map +1 -0
- package/dist/config.d.ts +45 -1
- package/dist/config.js +126 -22
- package/dist/config.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +4 -1
- package/dist/instructions.js +73 -51
- package/dist/instructions.js.map +1 -1
- package/dist/kubectl/runner.d.ts +7 -8
- package/dist/kubectl/runner.js +18 -21
- package/dist/kubectl/runner.js.map +1 -1
- package/dist/link-runtime.d.ts +39 -0
- package/dist/link-runtime.js +134 -0
- package/dist/link-runtime.js.map +1 -0
- package/dist/server.d.ts +2 -1
- package/dist/server.js +10 -12
- package/dist/server.js.map +1 -1
- package/dist/sources/guides.d.ts +34 -0
- package/dist/sources/guides.js +50 -0
- package/dist/sources/guides.js.map +1 -0
- package/dist/sources/index.d.ts +5 -0
- package/dist/sources/index.js +22 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/yaml-template.d.ts +31 -0
- package/dist/sources/yaml-template.js +35 -0
- package/dist/sources/yaml-template.js.map +1 -0
- package/dist/ssh/access-client.d.ts +6 -2
- package/dist/ssh/access-client.js +58 -27
- package/dist/ssh/access-client.js.map +1 -1
- package/dist/ssh/access-errors.js +1 -1
- package/dist/ssh/access-errors.js.map +1 -1
- package/dist/ssh/access-sftp.js +3 -3
- package/dist/ssh/access-sftp.js.map +1 -1
- package/dist/tools/copy-job-schemas.d.ts +96 -581
- package/dist/tools/copy-job-schemas.js +9 -9
- package/dist/tools/copy-job-schemas.js.map +1 -1
- package/dist/tools/register.d.ts +2 -10
- package/dist/tools/register.js +174 -331
- package/dist/tools/register.js.map +1 -1
- package/dist/tools/remote-schemas.d.ts +156 -708
- package/dist/tools/remote-schemas.js +99 -103
- package/dist/tools/remote-schemas.js.map +1 -1
- package/dist/utils/copy-executor.d.ts +3 -1
- package/dist/utils/copy-executor.js +39 -25
- package/dist/utils/copy-executor.js.map +1 -1
- package/dist/utils/copy-transfer.d.ts +2 -0
- package/dist/utils/copy-transfer.js.map +1 -1
- package/dist/utils/remote-executor.d.ts +3 -4
- package/dist/utils/remote-executor.js +8 -18
- package/dist/utils/remote-executor.js.map +1 -1
- package/dist/utils/remote-target.js +1 -1
- package/dist/utils/remote-target.js.map +1 -1
- package/docs/AGENT_GUIDE.md +31 -103
- package/docs/CONFIGURATION.md +30 -9
- package/docs/GUIDE.md +186 -0
- package/docs/PARADI_ACCESS_PLAN.md +6 -6
- package/docs/TODO.md +4 -11
- package/docs/USER_GUIDE.zh-CN.md +26 -173
- package/docs/host-execution.yaml +92 -0
- package/package.json +3 -1
package/dist/instructions.js
CHANGED
|
@@ -1,88 +1,90 @@
|
|
|
1
|
+
import { loadSourceLinks } from "./config-yaml.js";
|
|
1
2
|
function buildSshBaseInstructions() {
|
|
2
|
-
return `You are connected to host-execution-mcp
|
|
3
|
+
return `You are connected to host-execution-mcp.
|
|
3
4
|
|
|
4
5
|
Execution model:
|
|
5
|
-
Access:
|
|
6
|
-
Runtime:
|
|
7
|
-
|
|
6
|
+
Access: MCP client → SSH → this YAML link's landing (ACCESS_HOST)
|
|
7
|
+
Runtime: shell / docker / kubectl / copy on that landing
|
|
8
|
+
Second hop: pass host (IP reachable FROM ACCESS). Omit host = stay on the landing.
|
|
9
|
+
This tool path is ACCESS→host, not laptop SSH.
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
- shell_exec —
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
11
|
+
Tools:
|
|
12
|
+
- access_check — Local→ACCESS probe (≤10s; NOT kubectl). First session / after ACCESS_UNAVAILABLE
|
|
13
|
+
- shell_exec — command on the selected machine (omit host = landing; pass host = hop-2)
|
|
14
|
+
- context_probe / docker_* / k8s_* / remote_* — same pick: description + optional host
|
|
15
|
+
- remote_read_file / remote_ps — path on that machine; add namespace+pod to go into a container via kubectl there
|
|
16
|
+
- remote_copy_* — endpoints target=local|remote|pod; remote/pod use the same selected machine
|
|
28
17
|
|
|
29
18
|
Hard rules:
|
|
30
|
-
- access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST)
|
|
31
|
-
- SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across
|
|
19
|
+
- access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop THIS link (VPN / ACCESS_HOST). Other YAML descriptions may still work.
|
|
20
|
+
- SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across machines
|
|
32
21
|
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
33
|
-
- Never assume namespace/paths; never reuse ACCESS_USER as
|
|
22
|
+
- Never assume namespace/paths; never reuse ACCESS_USER as hop-2 user
|
|
34
23
|
- success=false: read stdout (stderr merged). truncated → more lines / remote_copy_*
|
|
35
24
|
- Multi-container pods: pass container name
|
|
36
|
-
-
|
|
25
|
+
- Once per conversation: listResources and read host-execution://guides/user, host-execution://guides/agent, and host-execution://guides/yaml. GUIDE is the capability the user wants; if a tool cannot meet it, tell the user. Reuse for the session — do not look for repo file paths.`;
|
|
37
26
|
}
|
|
38
27
|
function buildParadiBaseInstructions(config) {
|
|
39
|
-
const target = config.targetHost?.trim()
|
|
40
|
-
|
|
28
|
+
const target = config.targetHost?.trim();
|
|
29
|
+
const landingHint = target
|
|
30
|
+
? `TARGET_HOSTS has one landing (${target}) — omit host on that machine.`
|
|
31
|
+
: `TARGET_HOSTS has no single default — pass host to select a TARGET landing.`;
|
|
32
|
+
return `You are connected to host-execution-mcp (ACCESS_KIND=paradi-gateway).
|
|
41
33
|
|
|
42
|
-
Landing
|
|
34
|
+
${landingHint} Landing is a TARGET OS (encoded at the gateway), not the gateway OS.
|
|
35
|
+
Pass host to select a TARGET landing (gateway re-encodes identity) — not hop-2 SSH from the current machine.
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
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
|
|
37
|
+
Workflow:
|
|
38
|
+
- One TARGET_HOSTS: omit host
|
|
39
|
+
- Many or omitted: pass host on shell_exec / docker_* / remote_*
|
|
40
|
+
- Pods / copy: same machine as shell_exec. Copy target=remote = that landing; no hop-2. SFTP degraded — prefer remote_copy_start for large files.
|
|
51
41
|
|
|
52
42
|
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
|
|
43
|
+
- access_check.reachable=false or ACCESS_UNAVAILABLE → stop THIS link (VPN / ACCESS_HOST)
|
|
44
|
+
- unknown ≠ true; SSH success ≠ docker/kubectl; never reuse capabilities across machines
|
|
55
45
|
- Before pkill/kill/rm: remote_ps or user confirmation
|
|
56
46
|
- Never assume namespace/paths
|
|
57
|
-
-
|
|
47
|
+
- Once per conversation: listResources and read host-execution://guides/user, host-execution://guides/agent, and host-execution://guides/yaml. GUIDE is the capability the user wants; if a tool cannot meet it, tell the user. Reuse for the session — do not look for repo file paths.`;
|
|
58
48
|
}
|
|
59
|
-
/** TARGET_* default
|
|
49
|
+
/** TARGET_* default hop-2 / Paradi auth so agents omit configured defaults instead of asking the human. */
|
|
60
50
|
export function buildDerivedHostAuthGuidance(config) {
|
|
61
51
|
if (config.accessKind === "paradi-gateway") {
|
|
62
|
-
const host = config.targetHost?.trim();
|
|
63
52
|
return `
|
|
64
|
-
Paradi landing
|
|
53
|
+
Paradi landing select.${formatTargetHostHint(config)} Pass host on tools to pick a TARGET landing (gateway re-encodes identity). Omit user/password when TARGET_USER is set. Do not hop-2 from a Paradi landing.`;
|
|
65
54
|
}
|
|
66
55
|
const user = config.targetUser?.trim();
|
|
67
56
|
const passwordSet = Boolean(config.targetPassword);
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const noAccessUserFallback = " Never reuse ACCESS_USER as TARGET_USER / derive user — pass TARGET_USER (or tool user) explicitly.";
|
|
71
|
-
const shortcutHint = " ssh_exec = context_derive + shell_exec shortcut (returns reusable contextKey).";
|
|
57
|
+
const hostHint = formatTargetHostHint(config);
|
|
58
|
+
const noAccessUserFallback = " Never reuse ACCESS_USER as hop-2 user — pass TARGET_USER (or tool user) explicitly.";
|
|
72
59
|
if (!user && !passwordSet) {
|
|
73
60
|
return `
|
|
74
|
-
|
|
61
|
+
Hop-2 auth: TARGET_* unset — pass user (password if no key) with host.${hostHint}${noAccessUserFallback} Do not invent defaults.`;
|
|
75
62
|
}
|
|
76
63
|
if (user && passwordSet) {
|
|
77
64
|
return `
|
|
78
|
-
|
|
65
|
+
Hop-2 auth: TARGET_* active (user=${user}, password=set)${hostHint} — omit user/password when passing host; do not ask the human. Override only for a different account.${noAccessUserFallback}`;
|
|
79
66
|
}
|
|
80
67
|
if (user) {
|
|
81
68
|
return `
|
|
82
|
-
|
|
69
|
+
Hop-2 auth: TARGET_USER=${user}${hostHint} — omit user when passing host; pass password only if no key.${noAccessUserFallback}`;
|
|
83
70
|
}
|
|
84
71
|
return `
|
|
85
|
-
|
|
72
|
+
Hop-2 auth: TARGET_PASSWORD set${hostHint} — omit password when passing host; still pass user (TARGET_USER unset). Do not invent a username.${noAccessUserFallback}`;
|
|
73
|
+
}
|
|
74
|
+
function formatTargetHostHint(config) {
|
|
75
|
+
const hosts = config.targetHosts?.length
|
|
76
|
+
? config.targetHosts
|
|
77
|
+
: config.targetHost?.trim()
|
|
78
|
+
? [config.targetHost.trim()]
|
|
79
|
+
: [];
|
|
80
|
+
if (hosts.length === 0) {
|
|
81
|
+
return "";
|
|
82
|
+
}
|
|
83
|
+
const joined = hosts.join(",");
|
|
84
|
+
if (config.targetHost && hosts.length === 1) {
|
|
85
|
+
return ` TARGET_HOSTS=${joined} — pass that host to run on the hop-2 machine (omit host = ACCESS landing).`;
|
|
86
|
+
}
|
|
87
|
+
return ` TARGET_HOSTS=${joined} — pass host from user context; no single default.`;
|
|
86
88
|
}
|
|
87
89
|
export function buildServerInstructions(config) {
|
|
88
90
|
const base = config.accessKind === "paradi-gateway"
|
|
@@ -90,4 +92,24 @@ export function buildServerInstructions(config) {
|
|
|
90
92
|
: buildSshBaseInstructions();
|
|
91
93
|
return `${base}${buildDerivedHostAuthGuidance(config)}`;
|
|
92
94
|
}
|
|
95
|
+
export function buildYamlRosterGuidance(linkCount) {
|
|
96
|
+
const pick = linkCount === 0
|
|
97
|
+
? " Roster is empty — tell the user to append a link from host-execution://guides/yaml."
|
|
98
|
+
: linkCount === 1
|
|
99
|
+
? " One YAML link — description may be omitted."
|
|
100
|
+
: " Many YAML links — pass exact description; do not fuzzy-match.";
|
|
101
|
+
return `
|
|
102
|
+
YAML roster: ~/.agents/host-execution.yaml (Windows %USERPROFILE%\\.agents\\host-execution.yaml). Same link = user+IP. New user+IP in conversation → append unless the user says not to. Same conversation keeps the current link.${pick} description is a scenario label, not a frozen key — if it is misleading, rewrite it in the YAML now and then pass the new exact string. Do not invent fields — copy from host-execution://guides/yaml.`;
|
|
103
|
+
}
|
|
104
|
+
export function buildSourceInstructions(source) {
|
|
105
|
+
if (source.mode === "json") {
|
|
106
|
+
return `${buildServerInstructions(source.config)}
|
|
107
|
+
YAML roster file has no real links — JSON env is active. Writing a real link to ~/.agents/host-execution.yaml makes YAML win on the next tool call. Read host-execution://guides/yaml before appending.`;
|
|
108
|
+
}
|
|
109
|
+
const links = loadSourceLinks(source);
|
|
110
|
+
if (links.length === 1) {
|
|
111
|
+
return `${buildServerInstructions(links[0].config)}${buildYamlRosterGuidance(1)}`;
|
|
112
|
+
}
|
|
113
|
+
return `${buildSshBaseInstructions()}${buildYamlRosterGuidance(links.length)}`;
|
|
114
|
+
}
|
|
93
115
|
//# sourceMappingURL=instructions.js.map
|
package/dist/instructions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"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"}
|
package/dist/kubectl/runner.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { AccessRuntime } from "../access/index.js";
|
|
1
2
|
import type { AppConfig } from "../config.js";
|
|
2
|
-
import type { AccessClient } from "../ssh/access-client.js";
|
|
3
3
|
export type PodOutputFormat = "wide" | "json" | "name";
|
|
4
4
|
export declare function buildListPodsCommand(namespace: string, options: {
|
|
5
5
|
labelSelector?: string;
|
|
@@ -12,21 +12,20 @@ export declare function buildKubectlLogsCommand(namespace: string, pod: string,
|
|
|
12
12
|
tail?: number;
|
|
13
13
|
since?: string;
|
|
14
14
|
}): string;
|
|
15
|
-
export declare function runOnAccess(client: AccessClient, config: AppConfig, command: string, timeoutMs?: number, cwd?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
16
|
-
export declare function validateNamespace(config: AppConfig, namespace: string): void;
|
|
17
15
|
export declare class KubectlRunner {
|
|
18
|
-
private readonly
|
|
16
|
+
private readonly access;
|
|
19
17
|
private readonly config;
|
|
20
|
-
constructor(
|
|
18
|
+
constructor(access: AccessRuntime, config: AppConfig);
|
|
19
|
+
private run;
|
|
21
20
|
listPods(namespace: string, options: {
|
|
22
21
|
labelSelector?: string;
|
|
23
22
|
fieldSelector?: string;
|
|
24
23
|
output?: PodOutputFormat;
|
|
25
|
-
}, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
26
|
-
exec(namespace: string, pod: string, command: string, container?: string, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
24
|
+
}, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
25
|
+
exec(namespace: string, pod: string, command: string, container?: string, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
27
26
|
logs(namespace: string, pod: string, options: {
|
|
28
27
|
container?: string;
|
|
29
28
|
tail?: number;
|
|
30
29
|
since?: string;
|
|
31
|
-
}, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
30
|
+
}, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
|
|
32
31
|
}
|
package/dist/kubectl/runner.js
CHANGED
|
@@ -47,33 +47,30 @@ export function buildKubectlLogsCommand(namespace, pod, options) {
|
|
|
47
47
|
parts.push(`--tail=${options.tail ?? 200}`);
|
|
48
48
|
return parts.join(" ");
|
|
49
49
|
}
|
|
50
|
-
export async function runOnAccess(client, config, command, timeoutMs, cwd) {
|
|
51
|
-
return client.exec(command, timeoutMs ?? config.defaultTimeoutMs, cwd);
|
|
52
|
-
}
|
|
53
|
-
export function validateNamespace(config, namespace) {
|
|
54
|
-
assertNamespaceAllowed(config, namespace);
|
|
55
|
-
}
|
|
56
50
|
export class KubectlRunner {
|
|
57
|
-
|
|
51
|
+
access;
|
|
58
52
|
config;
|
|
59
|
-
constructor(
|
|
60
|
-
this.
|
|
53
|
+
constructor(access, config) {
|
|
54
|
+
this.access = access;
|
|
61
55
|
this.config = config;
|
|
62
56
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
run(command, timeoutMs, contextKey) {
|
|
58
|
+
return this.access.shellExec(command, {
|
|
59
|
+
contextKey,
|
|
60
|
+
timeoutMs: timeoutMs ?? this.config.defaultTimeoutMs,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
listPods(namespace, options, timeoutMs, contextKey) {
|
|
64
|
+
assertNamespaceAllowed(this.config, namespace);
|
|
65
|
+
return this.run(buildListPodsCommand(namespace, options), timeoutMs, contextKey);
|
|
67
66
|
}
|
|
68
|
-
exec(namespace, pod, command, container, timeoutMs) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return runOnAccess(this.client, this.config, kubectlCommand, timeoutMs);
|
|
67
|
+
exec(namespace, pod, command, container, timeoutMs, contextKey) {
|
|
68
|
+
assertNamespaceAllowed(this.config, namespace);
|
|
69
|
+
return this.run(buildKubectlExecCommand(namespace, pod, command, container), timeoutMs, contextKey);
|
|
72
70
|
}
|
|
73
|
-
logs(namespace, pod, options, timeoutMs) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return runOnAccess(this.client, this.config, kubectlCommand, timeoutMs);
|
|
71
|
+
logs(namespace, pod, options, timeoutMs, contextKey) {
|
|
72
|
+
assertNamespaceAllowed(this.config, namespace);
|
|
73
|
+
return this.run(buildKubectlLogsCommand(namespace, pod, options), timeoutMs, contextKey);
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
76
|
//# sourceMappingURL=runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/kubectl/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/kubectl/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AppConfig } from "./config.js";
|
|
2
|
+
import { type ConfigSource, type YamlRosterDeps } from "./config-yaml.js";
|
|
3
|
+
import { AccessRuntime } from "./access/index.js";
|
|
4
|
+
import { KubectlRunner } from "./kubectl/runner.js";
|
|
5
|
+
import { AccessClient } from "./ssh/access-client.js";
|
|
6
|
+
import { CopyJobManager } from "./utils/copy-job-manager.js";
|
|
7
|
+
import { RemoteExecutor } from "./utils/remote-executor.js";
|
|
8
|
+
import type { RemoteCopyStartRequest } from "./utils/copy-job-types.js";
|
|
9
|
+
export type ToolSession = {
|
|
10
|
+
description?: string;
|
|
11
|
+
config: AppConfig;
|
|
12
|
+
accessClient: AccessClient;
|
|
13
|
+
access: AccessRuntime;
|
|
14
|
+
kubectl: KubectlRunner;
|
|
15
|
+
remote: RemoteExecutor;
|
|
16
|
+
copyJobs: CopyJobManager;
|
|
17
|
+
};
|
|
18
|
+
export type LinkPick = {
|
|
19
|
+
description?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare class LinkRuntimeHub {
|
|
22
|
+
private readonly source;
|
|
23
|
+
private readonly rosterDeps;
|
|
24
|
+
private readonly cached;
|
|
25
|
+
private readonly copyOwners;
|
|
26
|
+
private jsonSession?;
|
|
27
|
+
private reconciledCopyJobs;
|
|
28
|
+
constructor(source: ConfigSource, rosterDeps?: YamlRosterDeps);
|
|
29
|
+
hintConfig(): AppConfig | undefined;
|
|
30
|
+
resolve(pick?: LinkPick): ToolSession;
|
|
31
|
+
copyStart(session: ToolSession, request: RemoteCopyStartRequest): Promise<import("./utils/copy-job-types.js").RemoteCopyStartResult>;
|
|
32
|
+
copyStatus(transferId: string): Promise<import("./utils/copy-job-types.js").RemoteCopyStatusResult>;
|
|
33
|
+
copyCancel(transferId: string): Promise<import("./utils/copy-job-types.js").RemoteCopyCancelResult>;
|
|
34
|
+
private copyManagerFor;
|
|
35
|
+
private reloadLinks;
|
|
36
|
+
private getOrCreate;
|
|
37
|
+
private build;
|
|
38
|
+
}
|
|
39
|
+
export declare function createLinkRuntimeHub(source: ConfigSource, rosterDeps?: YamlRosterDeps): LinkRuntimeHub;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { loadSourceLinks, pickYamlLink, } from "./config-yaml.js";
|
|
2
|
+
import { AccessRuntime } from "./access/index.js";
|
|
3
|
+
import { KubectlRunner } from "./kubectl/runner.js";
|
|
4
|
+
import { AccessClient } from "./ssh/access-client.js";
|
|
5
|
+
import { CopyJobManager } from "./utils/copy-job-manager.js";
|
|
6
|
+
import { RemoteExecutor } from "./utils/remote-executor.js";
|
|
7
|
+
function fingerprint(config) {
|
|
8
|
+
return JSON.stringify({
|
|
9
|
+
accessKind: config.accessKind,
|
|
10
|
+
accessHost: config.accessHost,
|
|
11
|
+
accessUser: config.accessUser,
|
|
12
|
+
accessPort: config.accessPort,
|
|
13
|
+
accessPrivateKeyPath: config.accessPrivateKeyPath,
|
|
14
|
+
accessPassword: config.accessPassword,
|
|
15
|
+
accessParadiAuth: config.accessParadiAuth,
|
|
16
|
+
targetHosts: config.targetHosts,
|
|
17
|
+
targetUser: config.targetUser,
|
|
18
|
+
targetPassword: config.targetPassword,
|
|
19
|
+
allowedNamespaces: config.allowedNamespaces,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function buildSession(link, reconcileOnStart) {
|
|
23
|
+
const accessClient = new AccessClient(link.config);
|
|
24
|
+
const access = new AccessRuntime(link.config, accessClient);
|
|
25
|
+
const kubectl = new KubectlRunner(access, link.config);
|
|
26
|
+
const remote = new RemoteExecutor(access, kubectl, link.config);
|
|
27
|
+
const copyJobs = new CopyJobManager({ accessClient, config: link.config }, undefined, undefined, { reconcileOnStart });
|
|
28
|
+
return {
|
|
29
|
+
description: link.description || undefined,
|
|
30
|
+
config: link.config,
|
|
31
|
+
accessClient,
|
|
32
|
+
access,
|
|
33
|
+
kubectl,
|
|
34
|
+
remote,
|
|
35
|
+
copyJobs,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export class LinkRuntimeHub {
|
|
39
|
+
source;
|
|
40
|
+
rosterDeps;
|
|
41
|
+
cached = [];
|
|
42
|
+
copyOwners = new Map();
|
|
43
|
+
jsonSession;
|
|
44
|
+
reconciledCopyJobs = false;
|
|
45
|
+
constructor(source, rosterDeps = {}) {
|
|
46
|
+
this.source = source;
|
|
47
|
+
this.rosterDeps = rosterDeps;
|
|
48
|
+
if (source.mode === "json") {
|
|
49
|
+
this.jsonSession = this.build({ description: "", config: source.config });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
hintConfig() {
|
|
53
|
+
if (this.source.mode === "json") {
|
|
54
|
+
return this.source.config;
|
|
55
|
+
}
|
|
56
|
+
const links = this.reloadLinks();
|
|
57
|
+
return links.length === 1 ? links[0]?.config : undefined;
|
|
58
|
+
}
|
|
59
|
+
resolve(pick = {}) {
|
|
60
|
+
if (this.source.mode === "json") {
|
|
61
|
+
return this.jsonSession;
|
|
62
|
+
}
|
|
63
|
+
const selected = pickYamlLink(this.reloadLinks(), pick.description);
|
|
64
|
+
return this.getOrCreate(selected);
|
|
65
|
+
}
|
|
66
|
+
async copyStart(session, request) {
|
|
67
|
+
const result = await session.copyJobs.start(request);
|
|
68
|
+
this.copyOwners.set(result.transferId, session.copyJobs);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
async copyStatus(transferId) {
|
|
72
|
+
return (await this.copyManagerFor(transferId)).status(transferId);
|
|
73
|
+
}
|
|
74
|
+
async copyCancel(transferId) {
|
|
75
|
+
return (await this.copyManagerFor(transferId)).cancel(transferId);
|
|
76
|
+
}
|
|
77
|
+
async copyManagerFor(transferId) {
|
|
78
|
+
const owned = this.copyOwners.get(transferId);
|
|
79
|
+
if (owned) {
|
|
80
|
+
return owned;
|
|
81
|
+
}
|
|
82
|
+
if (this.jsonSession) {
|
|
83
|
+
return this.jsonSession.copyJobs;
|
|
84
|
+
}
|
|
85
|
+
for (const entry of this.cached) {
|
|
86
|
+
try {
|
|
87
|
+
await entry.session.copyJobs.status(transferId);
|
|
88
|
+
return entry.session.copyJobs;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// try next
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (this.cached[0]) {
|
|
95
|
+
return this.cached[0].session.copyJobs;
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`Unknown transferId: ${transferId}`);
|
|
98
|
+
}
|
|
99
|
+
reloadLinks() {
|
|
100
|
+
return loadSourceLinks(this.source, this.rosterDeps);
|
|
101
|
+
}
|
|
102
|
+
getOrCreate(link) {
|
|
103
|
+
const fp = fingerprint(link.config);
|
|
104
|
+
const reuse = this.cached.find((entry) => entry.description === link.description && entry.fingerprint === fp);
|
|
105
|
+
if (reuse) {
|
|
106
|
+
return reuse.session;
|
|
107
|
+
}
|
|
108
|
+
// Drop stale sessions for the same description (config edited in-place).
|
|
109
|
+
for (let i = this.cached.length - 1; i >= 0; i--) {
|
|
110
|
+
const entry = this.cached[i];
|
|
111
|
+
if (entry && entry.description === link.description && entry.fingerprint !== fp) {
|
|
112
|
+
try {
|
|
113
|
+
entry.session.accessClient.disconnect();
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// best-effort
|
|
117
|
+
}
|
|
118
|
+
this.cached.splice(i, 1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const session = this.build(link);
|
|
122
|
+
this.cached.push({ fingerprint: fp, description: link.description, session });
|
|
123
|
+
return session;
|
|
124
|
+
}
|
|
125
|
+
build(link) {
|
|
126
|
+
const session = buildSession(link, !this.reconciledCopyJobs);
|
|
127
|
+
this.reconciledCopyJobs = true;
|
|
128
|
+
return session;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export function createLinkRuntimeHub(source, rosterDeps) {
|
|
132
|
+
return new LinkRuntimeHub(source, rosterDeps);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=link-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-runtime.js","sourceRoot":"","sources":["../src/link-runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import type { AppConfig } from "./config.js";
|
|
3
|
-
|
|
3
|
+
import { type ConfigSource } from "./config-yaml.js";
|
|
4
|
+
export declare function createServer(configOrSource: AppConfig | ConfigSource): McpServer;
|
package/dist/server.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { VERSION } from "./version.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { asConfigSource } from "./config-yaml.js";
|
|
4
|
+
import { buildSourceInstructions } from "./instructions.js";
|
|
5
|
+
import { createLinkRuntimeHub } from "./link-runtime.js";
|
|
6
|
+
import { registerSources } from "./sources/index.js";
|
|
7
7
|
import { registerPrompts, registerTools } from "./tools/register.js";
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export function createServer(configOrSource) {
|
|
9
|
+
const source = asConfigSource(configOrSource);
|
|
10
|
+
const hub = createLinkRuntimeHub(source);
|
|
10
11
|
const server = new McpServer({
|
|
11
12
|
name: "host-execution-mcp",
|
|
12
13
|
version: VERSION,
|
|
13
14
|
}, {
|
|
14
|
-
instructions:
|
|
15
|
+
instructions: buildSourceInstructions(source),
|
|
15
16
|
});
|
|
16
|
-
|
|
17
|
-
const access = new AccessRuntime(config, accessClient);
|
|
18
|
-
const kubectl = new KubectlRunner(accessClient, config);
|
|
19
|
-
const remote = new RemoteExecutor(access, kubectl, config);
|
|
20
|
-
registerTools(server, { config, accessClient, access, kubectl, remote });
|
|
17
|
+
registerTools(server, { hub });
|
|
21
18
|
registerPrompts(server);
|
|
19
|
+
registerSources(server);
|
|
22
20
|
return server;
|
|
23
21
|
}
|
|
24
22
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,UAAU,YAAY,CAAC,cAAwC;IACnE,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,uBAAuB,CAAC,MAAM,CAAC;KAC9C,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** `src/sources` or `dist/sources` → package `docs/`. */
|
|
2
|
+
export declare function docsDir(): string;
|
|
3
|
+
export type GuideSlug = "user" | "agent";
|
|
4
|
+
export type GuideMeta = {
|
|
5
|
+
slug: GuideSlug;
|
|
6
|
+
uri: string;
|
|
7
|
+
name: string;
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
file: string;
|
|
11
|
+
annotations: {
|
|
12
|
+
audience: Array<"user" | "assistant">;
|
|
13
|
+
priority: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const GUIDES: readonly GuideMeta[];
|
|
17
|
+
export declare function listGuideSources(): Array<{
|
|
18
|
+
uri: string;
|
|
19
|
+
name: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
mimeType: string;
|
|
23
|
+
annotations: {
|
|
24
|
+
audience: Array<"user" | "assistant">;
|
|
25
|
+
priority: number;
|
|
26
|
+
};
|
|
27
|
+
}>;
|
|
28
|
+
export declare function readGuideSource(uri: string): {
|
|
29
|
+
contents: Array<{
|
|
30
|
+
uri: string;
|
|
31
|
+
mimeType: string;
|
|
32
|
+
text: string;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/** `src/sources` or `dist/sources` → package `docs/`. */
|
|
5
|
+
export function docsDir() {
|
|
6
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "docs");
|
|
7
|
+
}
|
|
8
|
+
export const GUIDES = [
|
|
9
|
+
{
|
|
10
|
+
slug: "user",
|
|
11
|
+
uri: "host-execution://guides/user",
|
|
12
|
+
name: "user-guide",
|
|
13
|
+
title: "User GUIDE",
|
|
14
|
+
description: "What the user configured this MCP to do: ACCESS_KIND, mcp.json, TARGET_HOSTS, how they will ask the Agent.",
|
|
15
|
+
file: "GUIDE.md",
|
|
16
|
+
annotations: { audience: ["user", "assistant"], priority: 0.8 },
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
slug: "agent",
|
|
20
|
+
uri: "host-execution://guides/agent",
|
|
21
|
+
name: "agent-guide",
|
|
22
|
+
title: "Agent cookbook",
|
|
23
|
+
description: "Operational pitfalls: tool returns, quoting, CRLF, docker non-TTY, truncation, large copy. If GUIDE capability is unmet, tell the user.",
|
|
24
|
+
file: "AGENT_GUIDE.md",
|
|
25
|
+
annotations: { audience: ["assistant"], priority: 0.7 },
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
export function listGuideSources() {
|
|
29
|
+
return GUIDES.map((g) => ({
|
|
30
|
+
uri: g.uri,
|
|
31
|
+
name: g.name,
|
|
32
|
+
title: g.title,
|
|
33
|
+
description: g.description,
|
|
34
|
+
mimeType: "text/markdown",
|
|
35
|
+
annotations: g.annotations,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
export function readGuideSource(uri) {
|
|
39
|
+
const guide = GUIDES.find((g) => g.uri === uri);
|
|
40
|
+
if (!guide) {
|
|
41
|
+
const err = new Error(`Resource not found: ${uri}`);
|
|
42
|
+
err.code = -32002;
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
const text = readFileSync(join(docsDir(), guide.file), "utf8");
|
|
46
|
+
return {
|
|
47
|
+
contents: [{ uri, mimeType: "text/markdown", text }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=guides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides.js","sourceRoot":"","sources":["../../src/sources/guides.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,yDAAyD;AACzD,MAAM,UAAU,OAAO;IACrB,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC;AAcD,MAAM,CAAC,MAAM,MAAM,GAAyB;IAC1C;QACE,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,8BAA8B;QACnC,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,4GAA4G;QAC9G,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;KAChE;IACD;QACE,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,+BAA+B;QACpC,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,gBAAgB;QACvB,WAAW,EACT,yIAAyI;QAC3I,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;KACxD;CACF,CAAC;AAEF,MAAM,UAAU,gBAAgB;IAQ9B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,QAAQ,EAAE,eAAe;QACzB,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IAGzC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAA8B,CAAC;QACjF,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC;QAClB,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO;QACL,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC"}
|