@akms/mcp-ssh 0.0.3 → 0.1.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/README.md +70 -4
- package/lib/cli.cjs +2173 -248
- package/lib/cli.cjs.map +1 -1
- package/lib/cli.js +2170 -245
- package/lib/cli.js.map +1 -1
- package/lib/index.cjs +340 -89
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +58 -5
- package/lib/index.d.ts +58 -5
- package/lib/index.js +339 -88
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.cts
CHANGED
|
@@ -28,6 +28,18 @@ interface SshPolicy {
|
|
|
28
28
|
/** Remote path prefixes the file tools may touch. Empty means unrestricted. */
|
|
29
29
|
allowedPaths: string[];
|
|
30
30
|
}
|
|
31
|
+
/** Intermediate host the target is reached through, as OpenSSH's `ProxyJump` / `-J`. */
|
|
32
|
+
interface SshJumpProfile {
|
|
33
|
+
host: string;
|
|
34
|
+
port: number;
|
|
35
|
+
username: string;
|
|
36
|
+
/** Expanded absolute path to a private key file. */
|
|
37
|
+
privateKeyPath?: string;
|
|
38
|
+
passphrase?: string;
|
|
39
|
+
password?: string;
|
|
40
|
+
/** Expected jump host key, `SHA256:…`; a mismatch aborts the connection. */
|
|
41
|
+
hostKeyFingerprint?: string;
|
|
42
|
+
}
|
|
31
43
|
/** The registered host: where to connect, how to authenticate, what is permitted. */
|
|
32
44
|
interface SshHostProfile {
|
|
33
45
|
/** Alias shown to the model, from `SSH_NAME`; defaults to the hostname. */
|
|
@@ -47,6 +59,14 @@ interface SshHostProfile {
|
|
|
47
59
|
hostKeyFingerprint?: string;
|
|
48
60
|
/** Directory every session starts in; falls back to the login shell's default. */
|
|
49
61
|
defaultCwd?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Command whose stdin/stdout carry the SSH stream instead of a TCP socket — OpenSSH's
|
|
64
|
+
* `ProxyCommand`. It carries the first hop: the jump host when one is set, else the
|
|
65
|
+
* target. `%h` / `%p` / `%r` expand to that hop's host, port and user.
|
|
66
|
+
*/
|
|
67
|
+
proxyCommand?: string;
|
|
68
|
+
/** Jump host the target is reached through via a forwarded TCP channel. */
|
|
69
|
+
jump?: SshJumpProfile;
|
|
50
70
|
policy: SshPolicy;
|
|
51
71
|
}
|
|
52
72
|
/** Credential-free view of the profile, safe to hand back to the model. */
|
|
@@ -57,6 +77,13 @@ interface SshHostSummary {
|
|
|
57
77
|
username: string;
|
|
58
78
|
description?: string;
|
|
59
79
|
authMethod: "privateKey" | "password" | "agent";
|
|
80
|
+
/** True when a proxy command carries the first hop; the command itself is withheld. */
|
|
81
|
+
viaProxyCommand: boolean;
|
|
82
|
+
jump?: {
|
|
83
|
+
host: string;
|
|
84
|
+
port: number;
|
|
85
|
+
username: string;
|
|
86
|
+
};
|
|
60
87
|
readonly: boolean;
|
|
61
88
|
allowSudo: boolean;
|
|
62
89
|
allowedPaths: string[];
|
|
@@ -135,17 +162,23 @@ declare class SshConnection {
|
|
|
135
162
|
/** Set when the peer closed a previously established connection. */
|
|
136
163
|
private droppedAfterReady;
|
|
137
164
|
private observedFingerprint;
|
|
165
|
+
private observedJumpFingerprint;
|
|
138
166
|
constructor(profile: SshHostProfile);
|
|
139
167
|
get isConnected(): boolean;
|
|
140
168
|
/** Host key the server presented, once a handshake has been attempted. */
|
|
141
169
|
get hostKeyFingerprint(): string | null;
|
|
170
|
+
/** Host key the jump host presented; null without a jump host or before its handshake. */
|
|
171
|
+
get jumpHostKeyFingerprint(): string | null;
|
|
142
172
|
/** True when a connection was established and then lost, so shell state is gone. */
|
|
143
173
|
get wasDropped(): boolean;
|
|
144
174
|
/**
|
|
145
175
|
* Opens the connection, or joins the in-flight attempt when one is already running.
|
|
146
176
|
*
|
|
177
|
+
* With a proxy command or a jump host the carrier is opened first and handed to ssh2
|
|
178
|
+
* as the socket; it is torn down with the target connection, whichever side closes.
|
|
179
|
+
*
|
|
147
180
|
* @throws {Error} If the connection was closed, authentication fails, the host is
|
|
148
|
-
* unreachable,
|
|
181
|
+
* unreachable, the handshake times out, or the carrier cannot be opened.
|
|
149
182
|
*/
|
|
150
183
|
connect(): Promise<void>;
|
|
151
184
|
/**
|
|
@@ -344,10 +377,14 @@ declare function createSshMcpServer(): SshMcpServerInstance;
|
|
|
344
377
|
* 2) Resolve the policy over the built-in permissive stance; each variable is opt-in restriction
|
|
345
378
|
* 3) Assemble the connection fields
|
|
346
379
|
* 4) Expand the private key path and check it exists
|
|
380
|
+
* 5) Route: proxy command and / or jump host
|
|
347
381
|
*
|
|
348
|
-
* @
|
|
382
|
+
* @param env - Where the `SSH_*` variables are read from. Defaults to the process
|
|
383
|
+
* environment; the `config` command passes the entry it is about to write.
|
|
384
|
+
* @throws {Error} If `SSH_HOST` is set without `SSH_USER`, a `SSH_JUMP_*` variable is set
|
|
385
|
+
* without `SSH_JUMP_HOST`, or a typed value is malformed.
|
|
349
386
|
*/
|
|
350
|
-
declare function loadHostProfile(): SshHostProfile | null;
|
|
387
|
+
declare function loadHostProfile(env?: NodeJS.ProcessEnv): SshHostProfile | null;
|
|
351
388
|
/** Strips every secret so the profile can be described back to the model. */
|
|
352
389
|
declare function toHostSummary(profile: SshHostProfile): SshHostSummary;
|
|
353
390
|
|
|
@@ -495,7 +532,7 @@ declare const $logger: Logger;
|
|
|
495
532
|
/** Env var overriding the stderr log level ("debug" | "info" | "warn" | "error" | "silent"). */
|
|
496
533
|
declare const LOG_LEVEL_ENV = "SSH_MCP_LOG_LEVEL";
|
|
497
534
|
declare const SERVER_NAME = "akms-mcp-ssh";
|
|
498
|
-
declare const SERVER_VERSION = "0.0
|
|
535
|
+
declare const SERVER_VERSION = "0.1.0";
|
|
499
536
|
|
|
500
537
|
/**
|
|
501
538
|
* Environment variables that define the host, one MCP server entry per host.
|
|
@@ -520,6 +557,22 @@ declare const SINGLE_HOST_ENV: {
|
|
|
520
557
|
readonly DESCRIPTION: "SSH_DESCRIPTION";
|
|
521
558
|
/** Directory new sessions start in. */
|
|
522
559
|
readonly CWD: "SSH_CWD";
|
|
560
|
+
/**
|
|
561
|
+
* Command whose stdin/stdout carry the SSH stream, like OpenSSH's `ProxyCommand`.
|
|
562
|
+
* `%h` / `%p` / `%r` expand to the first hop's host, port and user.
|
|
563
|
+
*/
|
|
564
|
+
readonly PROXY_COMMAND: "SSH_PROXY_COMMAND";
|
|
565
|
+
/** Presence of this variable routes the connection through a jump host. */
|
|
566
|
+
readonly JUMP_HOST: "SSH_JUMP_HOST";
|
|
567
|
+
readonly JUMP_PORT: "SSH_JUMP_PORT";
|
|
568
|
+
/** Defaults to `SSH_USER`. */
|
|
569
|
+
readonly JUMP_USER: "SSH_JUMP_USER";
|
|
570
|
+
/** Path to the jump host's private key file; defaults to `SSH_KEY`. */
|
|
571
|
+
readonly JUMP_KEY: "SSH_JUMP_KEY";
|
|
572
|
+
readonly JUMP_PASSPHRASE: "SSH_JUMP_PASSPHRASE";
|
|
573
|
+
readonly JUMP_PASSWORD: "SSH_JUMP_PASSWORD";
|
|
574
|
+
/** Pinned jump host key, `SHA256:…`. */
|
|
575
|
+
readonly JUMP_HOST_KEY: "SSH_JUMP_HOST_KEY";
|
|
523
576
|
readonly READONLY: "SSH_READONLY";
|
|
524
577
|
readonly ALLOW_SUDO: "SSH_ALLOW_SUDO";
|
|
525
578
|
/** Comma-separated binary names. */
|
|
@@ -534,4 +587,4 @@ declare const SINGLE_HOST_ENV: {
|
|
|
534
587
|
readonly MAX_READ_FILE_BYTES: "SSH_MAX_READ_BYTES";
|
|
535
588
|
};
|
|
536
589
|
|
|
537
|
-
export { $logger, GuardRejectionError, type GuardVerdict, LOG_LEVEL_ENV, type LogLevel, type Logger, type RemoteDirectoryListing, type RemoteFileContent, type RemotePathAccess, SERVER_NAME, SERVER_VERSION, SINGLE_HOST_ENV, type SegmentAnalysis, SshConnection, type SshExecOptions, type SshExecResult, type SshHostProfile, type SshHostSummary, type SshMcpServerInstance, type SshPolicy, type SshRemoteEntry, SshSession, type SshSessionInfo, SshSessionManager, type ToolContext, analyzeSegment, canonicalizeCommand, createSshMcpServer, downloadFile, extractSubstitutions, inspectCommand, inspectLocalPath, inspectRemotePath, inspectWorkingDirectory, listRemoteDirectory, loadHostProfile, normalizeCommandText, readRemoteFile, registerAllTools, splitCommandSegments, stripQuotedText, toHostSummary, uploadFile, writeRemoteFile };
|
|
590
|
+
export { $logger, GuardRejectionError, type GuardVerdict, LOG_LEVEL_ENV, type LogLevel, type Logger, type RemoteDirectoryListing, type RemoteFileContent, type RemotePathAccess, SERVER_NAME, SERVER_VERSION, SINGLE_HOST_ENV, type SegmentAnalysis, SshConnection, type SshExecOptions, type SshExecResult, type SshHostProfile, type SshHostSummary, type SshJumpProfile, type SshMcpServerInstance, type SshPolicy, type SshRemoteEntry, SshSession, type SshSessionInfo, SshSessionManager, type ToolContext, analyzeSegment, canonicalizeCommand, createSshMcpServer, downloadFile, extractSubstitutions, inspectCommand, inspectLocalPath, inspectRemotePath, inspectWorkingDirectory, listRemoteDirectory, loadHostProfile, normalizeCommandText, readRemoteFile, registerAllTools, splitCommandSegments, stripQuotedText, toHostSummary, uploadFile, writeRemoteFile };
|
package/lib/index.d.ts
CHANGED
|
@@ -28,6 +28,18 @@ interface SshPolicy {
|
|
|
28
28
|
/** Remote path prefixes the file tools may touch. Empty means unrestricted. */
|
|
29
29
|
allowedPaths: string[];
|
|
30
30
|
}
|
|
31
|
+
/** Intermediate host the target is reached through, as OpenSSH's `ProxyJump` / `-J`. */
|
|
32
|
+
interface SshJumpProfile {
|
|
33
|
+
host: string;
|
|
34
|
+
port: number;
|
|
35
|
+
username: string;
|
|
36
|
+
/** Expanded absolute path to a private key file. */
|
|
37
|
+
privateKeyPath?: string;
|
|
38
|
+
passphrase?: string;
|
|
39
|
+
password?: string;
|
|
40
|
+
/** Expected jump host key, `SHA256:…`; a mismatch aborts the connection. */
|
|
41
|
+
hostKeyFingerprint?: string;
|
|
42
|
+
}
|
|
31
43
|
/** The registered host: where to connect, how to authenticate, what is permitted. */
|
|
32
44
|
interface SshHostProfile {
|
|
33
45
|
/** Alias shown to the model, from `SSH_NAME`; defaults to the hostname. */
|
|
@@ -47,6 +59,14 @@ interface SshHostProfile {
|
|
|
47
59
|
hostKeyFingerprint?: string;
|
|
48
60
|
/** Directory every session starts in; falls back to the login shell's default. */
|
|
49
61
|
defaultCwd?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Command whose stdin/stdout carry the SSH stream instead of a TCP socket — OpenSSH's
|
|
64
|
+
* `ProxyCommand`. It carries the first hop: the jump host when one is set, else the
|
|
65
|
+
* target. `%h` / `%p` / `%r` expand to that hop's host, port and user.
|
|
66
|
+
*/
|
|
67
|
+
proxyCommand?: string;
|
|
68
|
+
/** Jump host the target is reached through via a forwarded TCP channel. */
|
|
69
|
+
jump?: SshJumpProfile;
|
|
50
70
|
policy: SshPolicy;
|
|
51
71
|
}
|
|
52
72
|
/** Credential-free view of the profile, safe to hand back to the model. */
|
|
@@ -57,6 +77,13 @@ interface SshHostSummary {
|
|
|
57
77
|
username: string;
|
|
58
78
|
description?: string;
|
|
59
79
|
authMethod: "privateKey" | "password" | "agent";
|
|
80
|
+
/** True when a proxy command carries the first hop; the command itself is withheld. */
|
|
81
|
+
viaProxyCommand: boolean;
|
|
82
|
+
jump?: {
|
|
83
|
+
host: string;
|
|
84
|
+
port: number;
|
|
85
|
+
username: string;
|
|
86
|
+
};
|
|
60
87
|
readonly: boolean;
|
|
61
88
|
allowSudo: boolean;
|
|
62
89
|
allowedPaths: string[];
|
|
@@ -135,17 +162,23 @@ declare class SshConnection {
|
|
|
135
162
|
/** Set when the peer closed a previously established connection. */
|
|
136
163
|
private droppedAfterReady;
|
|
137
164
|
private observedFingerprint;
|
|
165
|
+
private observedJumpFingerprint;
|
|
138
166
|
constructor(profile: SshHostProfile);
|
|
139
167
|
get isConnected(): boolean;
|
|
140
168
|
/** Host key the server presented, once a handshake has been attempted. */
|
|
141
169
|
get hostKeyFingerprint(): string | null;
|
|
170
|
+
/** Host key the jump host presented; null without a jump host or before its handshake. */
|
|
171
|
+
get jumpHostKeyFingerprint(): string | null;
|
|
142
172
|
/** True when a connection was established and then lost, so shell state is gone. */
|
|
143
173
|
get wasDropped(): boolean;
|
|
144
174
|
/**
|
|
145
175
|
* Opens the connection, or joins the in-flight attempt when one is already running.
|
|
146
176
|
*
|
|
177
|
+
* With a proxy command or a jump host the carrier is opened first and handed to ssh2
|
|
178
|
+
* as the socket; it is torn down with the target connection, whichever side closes.
|
|
179
|
+
*
|
|
147
180
|
* @throws {Error} If the connection was closed, authentication fails, the host is
|
|
148
|
-
* unreachable,
|
|
181
|
+
* unreachable, the handshake times out, or the carrier cannot be opened.
|
|
149
182
|
*/
|
|
150
183
|
connect(): Promise<void>;
|
|
151
184
|
/**
|
|
@@ -344,10 +377,14 @@ declare function createSshMcpServer(): SshMcpServerInstance;
|
|
|
344
377
|
* 2) Resolve the policy over the built-in permissive stance; each variable is opt-in restriction
|
|
345
378
|
* 3) Assemble the connection fields
|
|
346
379
|
* 4) Expand the private key path and check it exists
|
|
380
|
+
* 5) Route: proxy command and / or jump host
|
|
347
381
|
*
|
|
348
|
-
* @
|
|
382
|
+
* @param env - Where the `SSH_*` variables are read from. Defaults to the process
|
|
383
|
+
* environment; the `config` command passes the entry it is about to write.
|
|
384
|
+
* @throws {Error} If `SSH_HOST` is set without `SSH_USER`, a `SSH_JUMP_*` variable is set
|
|
385
|
+
* without `SSH_JUMP_HOST`, or a typed value is malformed.
|
|
349
386
|
*/
|
|
350
|
-
declare function loadHostProfile(): SshHostProfile | null;
|
|
387
|
+
declare function loadHostProfile(env?: NodeJS.ProcessEnv): SshHostProfile | null;
|
|
351
388
|
/** Strips every secret so the profile can be described back to the model. */
|
|
352
389
|
declare function toHostSummary(profile: SshHostProfile): SshHostSummary;
|
|
353
390
|
|
|
@@ -495,7 +532,7 @@ declare const $logger: Logger;
|
|
|
495
532
|
/** Env var overriding the stderr log level ("debug" | "info" | "warn" | "error" | "silent"). */
|
|
496
533
|
declare const LOG_LEVEL_ENV = "SSH_MCP_LOG_LEVEL";
|
|
497
534
|
declare const SERVER_NAME = "akms-mcp-ssh";
|
|
498
|
-
declare const SERVER_VERSION = "0.0
|
|
535
|
+
declare const SERVER_VERSION = "0.1.0";
|
|
499
536
|
|
|
500
537
|
/**
|
|
501
538
|
* Environment variables that define the host, one MCP server entry per host.
|
|
@@ -520,6 +557,22 @@ declare const SINGLE_HOST_ENV: {
|
|
|
520
557
|
readonly DESCRIPTION: "SSH_DESCRIPTION";
|
|
521
558
|
/** Directory new sessions start in. */
|
|
522
559
|
readonly CWD: "SSH_CWD";
|
|
560
|
+
/**
|
|
561
|
+
* Command whose stdin/stdout carry the SSH stream, like OpenSSH's `ProxyCommand`.
|
|
562
|
+
* `%h` / `%p` / `%r` expand to the first hop's host, port and user.
|
|
563
|
+
*/
|
|
564
|
+
readonly PROXY_COMMAND: "SSH_PROXY_COMMAND";
|
|
565
|
+
/** Presence of this variable routes the connection through a jump host. */
|
|
566
|
+
readonly JUMP_HOST: "SSH_JUMP_HOST";
|
|
567
|
+
readonly JUMP_PORT: "SSH_JUMP_PORT";
|
|
568
|
+
/** Defaults to `SSH_USER`. */
|
|
569
|
+
readonly JUMP_USER: "SSH_JUMP_USER";
|
|
570
|
+
/** Path to the jump host's private key file; defaults to `SSH_KEY`. */
|
|
571
|
+
readonly JUMP_KEY: "SSH_JUMP_KEY";
|
|
572
|
+
readonly JUMP_PASSPHRASE: "SSH_JUMP_PASSPHRASE";
|
|
573
|
+
readonly JUMP_PASSWORD: "SSH_JUMP_PASSWORD";
|
|
574
|
+
/** Pinned jump host key, `SHA256:…`. */
|
|
575
|
+
readonly JUMP_HOST_KEY: "SSH_JUMP_HOST_KEY";
|
|
523
576
|
readonly READONLY: "SSH_READONLY";
|
|
524
577
|
readonly ALLOW_SUDO: "SSH_ALLOW_SUDO";
|
|
525
578
|
/** Comma-separated binary names. */
|
|
@@ -534,4 +587,4 @@ declare const SINGLE_HOST_ENV: {
|
|
|
534
587
|
readonly MAX_READ_FILE_BYTES: "SSH_MAX_READ_BYTES";
|
|
535
588
|
};
|
|
536
589
|
|
|
537
|
-
export { $logger, GuardRejectionError, type GuardVerdict, LOG_LEVEL_ENV, type LogLevel, type Logger, type RemoteDirectoryListing, type RemoteFileContent, type RemotePathAccess, SERVER_NAME, SERVER_VERSION, SINGLE_HOST_ENV, type SegmentAnalysis, SshConnection, type SshExecOptions, type SshExecResult, type SshHostProfile, type SshHostSummary, type SshMcpServerInstance, type SshPolicy, type SshRemoteEntry, SshSession, type SshSessionInfo, SshSessionManager, type ToolContext, analyzeSegment, canonicalizeCommand, createSshMcpServer, downloadFile, extractSubstitutions, inspectCommand, inspectLocalPath, inspectRemotePath, inspectWorkingDirectory, listRemoteDirectory, loadHostProfile, normalizeCommandText, readRemoteFile, registerAllTools, splitCommandSegments, stripQuotedText, toHostSummary, uploadFile, writeRemoteFile };
|
|
590
|
+
export { $logger, GuardRejectionError, type GuardVerdict, LOG_LEVEL_ENV, type LogLevel, type Logger, type RemoteDirectoryListing, type RemoteFileContent, type RemotePathAccess, SERVER_NAME, SERVER_VERSION, SINGLE_HOST_ENV, type SegmentAnalysis, SshConnection, type SshExecOptions, type SshExecResult, type SshHostProfile, type SshHostSummary, type SshJumpProfile, type SshMcpServerInstance, type SshPolicy, type SshRemoteEntry, SshSession, type SshSessionInfo, SshSessionManager, type ToolContext, analyzeSegment, canonicalizeCommand, createSshMcpServer, downloadFile, extractSubstitutions, inspectCommand, inspectLocalPath, inspectRemotePath, inspectWorkingDirectory, listRemoteDirectory, loadHostProfile, normalizeCommandText, readRemoteFile, registerAllTools, splitCommandSegments, stripQuotedText, toHostSummary, uploadFile, writeRemoteFile };
|