@akms/mcp-ssh 0.1.5 → 0.1.6
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 +1 -1
- package/lib/cli.cjs +26 -3
- package/lib/cli.cjs.map +1 -1
- package/lib/cli.js +26 -3
- package/lib/cli.js.map +1 -1
- package/lib/index.cjs +13 -2
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +13 -2
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ Only entries that launch this package are listed or touched. An edit keeps every
|
|
|
84
84
|
|
|
85
85
|
`SSH_HOST` + `SSH_USER` is the whole minimum, and the **private key stays a file on disk** — only its path goes in the config. Because each server fronts one host, the agent never names it: `ssh_exec({ command: "df -h" })` is a complete call. The server name (`ssh-prod`) is what the agent sees in its tool list, so name it after the host.
|
|
86
86
|
|
|
87
|
-
The server speaks MCP over **stdio**: stdout carries the JSON-RPC stream and all logging goes to stderr. Running it by hand in a terminal only prints the startup line and waits.
|
|
87
|
+
The server speaks MCP over **stdio**: stdout carries the JSON-RPC stream and all logging goes to stderr. Running it by hand in a terminal only prints the startup line and waits. When the client goes away — stdin ends, or the process is simply gone — the server closes its sessions and exits within a few seconds on its own; a stderr nobody reads is never a reason to stay. Its log says `mcp server ready on stdio` with its `pid`, for when one has to be found among a client's processes.
|
|
88
88
|
|
|
89
89
|
## 🗂️ Host configuration
|
|
90
90
|
|
package/lib/cli.cjs
CHANGED
|
@@ -31,11 +31,12 @@ var DEFAULT_MAX_READ_FILE_BYTES = 2e5;
|
|
|
31
31
|
var KEEPALIVE_INTERVAL_MS = 15e3;
|
|
32
32
|
var SESSION_IDLE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
33
33
|
var SESSION_SWEEP_INTERVAL_MS = 6e4;
|
|
34
|
+
var SHUTDOWN_DEADLINE_MS = 5e3;
|
|
34
35
|
var CWD_MARKER = "__AKMS_SSH_CWD__";
|
|
35
36
|
var MAX_DIRECTORY_ENTRIES = 1e3;
|
|
36
37
|
var SERVER_NAME = "akms-mcp-ssh";
|
|
37
38
|
var PACKAGE_NAME = "@akms/mcp-ssh";
|
|
38
|
-
var SERVER_VERSION = "0.1.
|
|
39
|
+
var SERVER_VERSION = "0.1.6";
|
|
39
40
|
|
|
40
41
|
// src/_defs/command-rules.ts
|
|
41
42
|
var CRITICAL_PATH_PATTERN = new RegExp(
|
|
@@ -498,6 +499,10 @@ var LEVEL_WEIGHTS = {
|
|
|
498
499
|
error: 4
|
|
499
500
|
};
|
|
500
501
|
var SECRET_META_KEYS = ["password", "passphrase", "privatekey", "privatekeypath", "secret", "token"];
|
|
502
|
+
var stderrBroken = false;
|
|
503
|
+
process.stderr.on("error", () => {
|
|
504
|
+
stderrBroken = true;
|
|
505
|
+
});
|
|
501
506
|
function resolveThreshold() {
|
|
502
507
|
const configured = process.env[LOG_LEVEL_ENV];
|
|
503
508
|
if (configured == null) {
|
|
@@ -521,6 +526,9 @@ function maskMeta(meta) {
|
|
|
521
526
|
return masked;
|
|
522
527
|
}
|
|
523
528
|
function write(level, message, meta) {
|
|
529
|
+
if (stderrBroken == true) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
524
532
|
const threshold = resolveThreshold();
|
|
525
533
|
if (threshold === "silent") {
|
|
526
534
|
return;
|
|
@@ -534,8 +542,12 @@ function write(level, message, meta) {
|
|
|
534
542
|
if (Object.keys(masked).length > 0) {
|
|
535
543
|
line += ` ${JSON.stringify(masked)}`;
|
|
536
544
|
}
|
|
537
|
-
|
|
545
|
+
try {
|
|
546
|
+
process.stderr.write(`${line}
|
|
538
547
|
`);
|
|
548
|
+
} catch {
|
|
549
|
+
stderrBroken = true;
|
|
550
|
+
}
|
|
539
551
|
}
|
|
540
552
|
function createLogger(boundMeta) {
|
|
541
553
|
return {
|
|
@@ -5774,6 +5786,12 @@ async function main() {
|
|
|
5774
5786
|
instance.shutdown();
|
|
5775
5787
|
process.exit(exitCode);
|
|
5776
5788
|
}
|
|
5789
|
+
process.on("uncaughtException", (error) => {
|
|
5790
|
+
_logger.error(error, "uncaught exception; the server keeps running");
|
|
5791
|
+
});
|
|
5792
|
+
process.on("unhandledRejection", (reason) => {
|
|
5793
|
+
_logger.error(reason, "unhandled rejection; the server keeps running");
|
|
5794
|
+
});
|
|
5777
5795
|
let shuttingDown = false;
|
|
5778
5796
|
const shutdown = (signal) => {
|
|
5779
5797
|
if (shuttingDown == true) {
|
|
@@ -5781,6 +5799,10 @@ async function main() {
|
|
|
5781
5799
|
}
|
|
5782
5800
|
shuttingDown = true;
|
|
5783
5801
|
_logger.info("shutting down", { signal });
|
|
5802
|
+
setTimeout(() => {
|
|
5803
|
+
_logger.warn("shutdown did not finish in time; exiting anyway", { deadline_ms: SHUTDOWN_DEADLINE_MS });
|
|
5804
|
+
process.exit(0);
|
|
5805
|
+
}, SHUTDOWN_DEADLINE_MS).unref();
|
|
5784
5806
|
instance.shutdown();
|
|
5785
5807
|
void instance.server.close().finally(() => {
|
|
5786
5808
|
process.exit(0);
|
|
@@ -5800,7 +5822,8 @@ async function main() {
|
|
|
5800
5822
|
_logger.info("mcp server ready on stdio", {
|
|
5801
5823
|
server: SERVER_NAME,
|
|
5802
5824
|
version: SERVER_VERSION,
|
|
5803
|
-
profile: instance.profile?.name ?? null
|
|
5825
|
+
profile: instance.profile?.name ?? null,
|
|
5826
|
+
pid: process.pid
|
|
5804
5827
|
});
|
|
5805
5828
|
}
|
|
5806
5829
|
main().catch((error) => {
|