smooth-ssh-mcp 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +319 -0
  3. package/README.md +32 -0
  4. package/README.zh-CN.md +319 -0
  5. package/bin/smooth-ssh-mcp-codex +43 -0
  6. package/dist/audit.d.ts +23 -0
  7. package/dist/audit.js +140 -0
  8. package/dist/audit.js.map +1 -0
  9. package/dist/auth.d.ts +8 -0
  10. package/dist/auth.js +19 -0
  11. package/dist/auth.js.map +1 -0
  12. package/dist/doctor.d.ts +27 -0
  13. package/dist/doctor.js +169 -0
  14. package/dist/doctor.js.map +1 -0
  15. package/dist/forwardManager.d.ts +49 -0
  16. package/dist/forwardManager.js +141 -0
  17. package/dist/forwardManager.js.map +1 -0
  18. package/dist/init.d.ts +21 -0
  19. package/dist/init.js +80 -0
  20. package/dist/init.js.map +1 -0
  21. package/dist/inventory.d.ts +4 -0
  22. package/dist/inventory.js +262 -0
  23. package/dist/inventory.js.map +1 -0
  24. package/dist/mcpServer.d.ts +8 -0
  25. package/dist/mcpServer.js +403 -0
  26. package/dist/mcpServer.js.map +1 -0
  27. package/dist/operations.d.ts +167 -0
  28. package/dist/operations.js +1240 -0
  29. package/dist/operations.js.map +1 -0
  30. package/dist/policy.d.ts +21 -0
  31. package/dist/policy.js +470 -0
  32. package/dist/policy.js.map +1 -0
  33. package/dist/redaction.d.ts +2 -0
  34. package/dist/redaction.js +64 -0
  35. package/dist/redaction.js.map +1 -0
  36. package/dist/runner.d.ts +24 -0
  37. package/dist/runner.js +90 -0
  38. package/dist/runner.js.map +1 -0
  39. package/dist/server.d.ts +9 -0
  40. package/dist/server.js +130 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/sessionManager.d.ts +77 -0
  43. package/dist/sessionManager.js +195 -0
  44. package/dist/sessionManager.js.map +1 -0
  45. package/dist/sshArgs.d.ts +24 -0
  46. package/dist/sshArgs.js +135 -0
  47. package/dist/sshArgs.js.map +1 -0
  48. package/dist/stateStore.d.ts +27 -0
  49. package/dist/stateStore.js +99 -0
  50. package/dist/stateStore.js.map +1 -0
  51. package/dist/types.d.ts +95 -0
  52. package/dist/types.js +2 -0
  53. package/dist/types.js.map +1 -0
  54. package/docs/mcp-client.example.json +15 -0
  55. package/examples/hosts.example.yaml +79 -0
  56. package/package.json +58 -0
package/dist/init.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ export type InitActionStatus = "created" | "exists";
2
+ export type InitAction = {
3
+ id: string;
4
+ label: string;
5
+ path: string;
6
+ status: InitActionStatus;
7
+ };
8
+ export type InitReport = {
9
+ ok: boolean;
10
+ actions: InitAction[];
11
+ nextSteps: string[];
12
+ };
13
+ type InitOptions = {
14
+ configPath?: string;
15
+ secretsPath?: string;
16
+ force?: boolean;
17
+ env?: NodeJS.ProcessEnv;
18
+ };
19
+ export declare function runInit(options?: InitOptions): InitReport;
20
+ export declare function formatInitReport(report: InitReport): string;
21
+ export {};
package/dist/init.js ADDED
@@ -0,0 +1,80 @@
1
+ import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { defaultInventoryPath } from "./inventory.js";
4
+ const HOSTS_TEMPLATE = `hosts:
5
+ - id: example-host
6
+ hostname: 192.0.2.10
7
+ user: ubuntu
8
+ port: 22
9
+ identityFile: ~/.ssh/id_ed25519
10
+ environment: dev
11
+ tags: [example]
12
+ capabilities:
13
+ sudo: true
14
+ systemd: true
15
+ policy:
16
+ allowExec: true
17
+ allowPty: true
18
+ allowUpload: false
19
+ allowDownload: false
20
+ allowForward: false
21
+ acceptNewHostKey: false
22
+ permissionLevel: 2
23
+ maxCommandSeconds: 30
24
+ maxOutputBytes: 65536
25
+ `;
26
+ const SECRETS_TEMPLATE = `# Optional password-based host secrets. Prefer SSH keys when possible.
27
+ # Example inventory value: passwordEnv: SMOOTH_SSH_PASSWORD_EXAMPLE_HOST
28
+ SMOOTH_SSH_PASSWORD_EXAMPLE_HOST=change-me
29
+ `;
30
+ export function runInit(options = {}) {
31
+ const env = options.env ?? process.env;
32
+ const configPath = expandHome(options.configPath ?? defaultInventoryPath(), env);
33
+ const secretsPath = expandHome(options.secretsPath ?? env.SMOOTH_SSH_MCP_SECRETS ?? "~/.config/smooth-ssh-mcp/secrets.env", env);
34
+ const configDir = dirname(configPath);
35
+ const actions = [];
36
+ if (existsSync(configDir)) {
37
+ actions.push({ id: "config-dir", label: "Config directory", path: configDir, status: "exists" });
38
+ }
39
+ else {
40
+ mkdirSync(configDir, { recursive: true, mode: 0o700 });
41
+ actions.push({ id: "config-dir", label: "Config directory", path: configDir, status: "created" });
42
+ }
43
+ actions.push(writeTemplate("hosts", "Hosts inventory", configPath, HOSTS_TEMPLATE, options.force));
44
+ actions.push(writeTemplate("secrets", "Secrets file", secretsPath, SECRETS_TEMPLATE, options.force));
45
+ return {
46
+ ok: true,
47
+ actions,
48
+ nextSteps: [
49
+ `Edit ${configPath} with your real hosts.`,
50
+ `Run: smooth-ssh-mcp doctor --config ${configPath} --secrets ${secretsPath}`,
51
+ "Add smooth-ssh-mcp to your MCP client configuration."
52
+ ]
53
+ };
54
+ }
55
+ export function formatInitReport(report) {
56
+ const lines = [
57
+ "smooth-ssh-mcp init: ok",
58
+ ...report.actions.map((action) => `[${action.status}] ${action.label}: ${action.path}`),
59
+ "next steps:",
60
+ ...report.nextSteps.map((step) => `- ${step}`)
61
+ ];
62
+ return lines.join("\n");
63
+ }
64
+ function writeTemplate(id, label, path, text, force = false) {
65
+ if (existsSync(path) && !force) {
66
+ return { id, label, path, status: "exists" };
67
+ }
68
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
69
+ writeFileSync(path, text, { encoding: "utf8", mode: 0o600 });
70
+ chmodSync(path, 0o600);
71
+ return { id, label, path, status: "created" };
72
+ }
73
+ function expandHome(path, env) {
74
+ if (path === "~")
75
+ return env.HOME ?? path;
76
+ if (path.startsWith("~/"))
77
+ return `${env.HOME ?? ""}${path.slice(1)}`;
78
+ return path;
79
+ }
80
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Host, Inventory } from "./types.js";
2
+ export declare function loadInventory(path: string): Inventory;
3
+ export declare function findHost(inventory: Inventory, hostId: string): Host;
4
+ export declare function defaultInventoryPath(): string;
@@ -0,0 +1,262 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { extname, resolve } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ const HOST_ID_PATTERN = /^[A-Za-z0-9._-]+$/;
5
+ const SAFE_SSH_TOKEN_PATTERN = /^[^\s\0\r\n;|&`$<>]+$/;
6
+ const DEFAULT_POLICY = {
7
+ allowExec: true,
8
+ allowPty: true,
9
+ allowUpload: false,
10
+ allowDownload: false,
11
+ allowForward: false,
12
+ acceptNewHostKey: false,
13
+ requireConfirmForSudo: true,
14
+ requireConfirmForWrite: true,
15
+ requireConfirmForProd: true,
16
+ permissionLevel: 2,
17
+ deniedCommandPatterns: [],
18
+ maxCommandSeconds: 30,
19
+ maxOutputBytes: 64 * 1024
20
+ };
21
+ const POLICY_KEYS = new Set([
22
+ "allowExec",
23
+ "allowPty",
24
+ "allowUpload",
25
+ "allowDownload",
26
+ "allowForward",
27
+ "acceptNewHostKey",
28
+ "requireConfirmForSudo",
29
+ "requireConfirmForWrite",
30
+ "requireConfirmForProd",
31
+ "permissionLevel",
32
+ "deniedCommandPatterns",
33
+ "maxCommandSeconds",
34
+ "maxOutputBytes"
35
+ ]);
36
+ export function loadInventory(path) {
37
+ const resolved = resolve(expandHome(path));
38
+ if (!existsSync(resolved)) {
39
+ throw new Error(`Inventory file does not exist: ${resolved}`);
40
+ }
41
+ const text = readFileSync(resolved, "utf8");
42
+ const raw = parseInventory(text, resolved);
43
+ const hosts = (raw.hosts ?? []).map(normalizeHost);
44
+ const ids = new Set();
45
+ for (const host of hosts) {
46
+ if (ids.has(host.id)) {
47
+ throw new Error(`Duplicate host id in inventory: ${host.id}`);
48
+ }
49
+ ids.add(host.id);
50
+ }
51
+ return { hosts };
52
+ }
53
+ export function findHost(inventory, hostId) {
54
+ const host = inventory.hosts.find((candidate) => candidate.id === hostId);
55
+ if (!host) {
56
+ throw new Error(`Host not found in inventory: ${hostId}`);
57
+ }
58
+ return host;
59
+ }
60
+ export function defaultInventoryPath() {
61
+ return process.env.SMOOTH_SSH_MCP_CONFIG ?? "~/.config/smooth-ssh-mcp/hosts.yaml";
62
+ }
63
+ function parseInventory(text, path) {
64
+ if (extname(path).toLowerCase() === ".json") {
65
+ return JSON.parse(text);
66
+ }
67
+ return parseYaml(text);
68
+ }
69
+ function normalizeHost(raw) {
70
+ if (raw.password !== undefined) {
71
+ throw new Error("Inline password is not allowed. Use passwordEnv to reference an environment variable.");
72
+ }
73
+ const id = requiredString(raw.id, "host id");
74
+ if (!HOST_ID_PATTERN.test(id)) {
75
+ throw new Error(`Invalid host id "${id}". Use letters, numbers, dots, underscores, and dashes only.`);
76
+ }
77
+ if (id.startsWith("-")) {
78
+ throw new Error(`Invalid host id "${id}": leading dash is not allowed`);
79
+ }
80
+ const hostname = optionalString(raw.hostname) ?? optionalString(raw.host);
81
+ const sshConfigHost = optionalString(raw.sshConfigHost);
82
+ if (!hostname && !sshConfigHost) {
83
+ throw new Error(`Host ${id} must define hostname or sshConfigHost`);
84
+ }
85
+ if (hostname)
86
+ validateSshToken(hostname, `hostname for ${id}`);
87
+ if (sshConfigHost)
88
+ validateSshToken(sshConfigHost, `sshConfigHost for ${id}`);
89
+ const port = optionalNumber(raw.port);
90
+ if (port !== undefined && (!Number.isInteger(port) || port < 1 || port > 65535)) {
91
+ throw new Error(`Invalid port for ${id}: ${port}`);
92
+ }
93
+ const user = optionalString(raw.user);
94
+ if (user)
95
+ validateSshToken(user, `user for ${id}`);
96
+ const identityFile = optionalString(raw.identityFile) ?? optionalString(raw.keyPath);
97
+ const passwordEnv = optionalString(raw.passwordEnv);
98
+ if (passwordEnv)
99
+ validateEnvName(passwordEnv, `passwordEnv for ${id}`);
100
+ if (identityFile && passwordEnv) {
101
+ throw new Error(`Host ${id} must not define both identityFile and passwordEnv`);
102
+ }
103
+ const proxyJump = optionalString(raw.proxyJump);
104
+ if (proxyJump)
105
+ validateSshToken(proxyJump, `proxyJump for ${id}`);
106
+ const environment = normalizeEnvironment(optionalString(raw.environment));
107
+ const policy = mergePolicy(raw.policy);
108
+ return {
109
+ id,
110
+ hostname: hostname ?? sshConfigHost ?? id,
111
+ port,
112
+ user,
113
+ identityFile: identityFile ? expandHome(identityFile) : undefined,
114
+ passwordEnv,
115
+ sshConfigHost,
116
+ proxyJump,
117
+ defaultCwd: optionalString(raw.defaultCwd),
118
+ tags: normalizeStringArray(raw.tags),
119
+ environment,
120
+ riskLevel: normalizeRisk(optionalString(raw.riskLevel), environment),
121
+ capabilities: normalizeCapabilities(raw.capabilities),
122
+ policy
123
+ };
124
+ }
125
+ function mergePolicy(raw) {
126
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
127
+ return { ...DEFAULT_POLICY };
128
+ }
129
+ const value = raw;
130
+ validatePolicyKeys(value);
131
+ return {
132
+ allowExec: optionalPolicyBoolean(value, "allowExec", DEFAULT_POLICY.allowExec),
133
+ allowPty: optionalPolicyBoolean(value, "allowPty", DEFAULT_POLICY.allowPty),
134
+ allowUpload: optionalPolicyBoolean(value, "allowUpload", DEFAULT_POLICY.allowUpload),
135
+ allowDownload: optionalPolicyBoolean(value, "allowDownload", DEFAULT_POLICY.allowDownload),
136
+ allowForward: optionalPolicyBoolean(value, "allowForward", DEFAULT_POLICY.allowForward),
137
+ acceptNewHostKey: optionalPolicyBoolean(value, "acceptNewHostKey", DEFAULT_POLICY.acceptNewHostKey),
138
+ requireConfirmForSudo: optionalPolicyBoolean(value, "requireConfirmForSudo", DEFAULT_POLICY.requireConfirmForSudo),
139
+ requireConfirmForWrite: optionalPolicyBoolean(value, "requireConfirmForWrite", DEFAULT_POLICY.requireConfirmForWrite),
140
+ requireConfirmForProd: optionalPolicyBoolean(value, "requireConfirmForProd", DEFAULT_POLICY.requireConfirmForProd),
141
+ permissionLevel: optionalPolicyPermissionLevel(value, DEFAULT_POLICY.permissionLevel),
142
+ deniedCommandPatterns: optionalPolicyStringArray(value, "deniedCommandPatterns", DEFAULT_POLICY.deniedCommandPatterns),
143
+ maxCommandSeconds: optionalPolicyNumber(value, "maxCommandSeconds", DEFAULT_POLICY.maxCommandSeconds),
144
+ maxOutputBytes: optionalPolicyNumber(value, "maxOutputBytes", DEFAULT_POLICY.maxOutputBytes)
145
+ };
146
+ }
147
+ function validatePolicyKeys(raw) {
148
+ for (const key of Object.keys(raw)) {
149
+ if (!POLICY_KEYS.has(key)) {
150
+ throw new Error(`Invalid policy.${key}: unsupported policy key`);
151
+ }
152
+ }
153
+ }
154
+ function normalizeEnvironment(value) {
155
+ if (value === "dev" || value === "staging" || value === "prod")
156
+ return value;
157
+ return "unknown";
158
+ }
159
+ function normalizeRisk(value, environment) {
160
+ if (value === "low" || value === "medium" || value === "high")
161
+ return value;
162
+ if (environment === "prod")
163
+ return "high";
164
+ if (environment === "unknown")
165
+ return "medium";
166
+ return "low";
167
+ }
168
+ function normalizeCapabilities(raw) {
169
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
170
+ return undefined;
171
+ const input = raw;
172
+ return {
173
+ sudo: optionalBoolean(input.sudo),
174
+ docker: optionalBoolean(input.docker),
175
+ nginx: optionalBoolean(input.nginx),
176
+ systemd: optionalBoolean(input.systemd),
177
+ openwrt: optionalBoolean(input.openwrt)
178
+ };
179
+ }
180
+ function normalizeStringArray(value) {
181
+ if (!Array.isArray(value))
182
+ return [];
183
+ return value.map(String).filter(Boolean);
184
+ }
185
+ function requiredString(value, label) {
186
+ const result = optionalString(value);
187
+ if (!result)
188
+ throw new Error(`Missing ${label}`);
189
+ return result;
190
+ }
191
+ function optionalString(value) {
192
+ if (typeof value !== "string")
193
+ return undefined;
194
+ const trimmed = value.trim();
195
+ return trimmed.length > 0 ? trimmed : undefined;
196
+ }
197
+ function optionalNumber(value) {
198
+ if (typeof value === "number")
199
+ return value;
200
+ if (typeof value === "string" && value.trim() !== "")
201
+ return Number(value);
202
+ return undefined;
203
+ }
204
+ function optionalBoolean(value) {
205
+ return typeof value === "boolean" ? value : undefined;
206
+ }
207
+ function validateSshToken(value, label) {
208
+ if (value.startsWith("-")) {
209
+ throw new Error(`Invalid ${label}: leading dash is not allowed`);
210
+ }
211
+ if (!SAFE_SSH_TOKEN_PATTERN.test(value)) {
212
+ throw new Error(`Invalid ${label}: contains whitespace or shell metacharacters`);
213
+ }
214
+ }
215
+ function validateEnvName(value, label) {
216
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
217
+ throw new Error(`Invalid ${label}: expected an environment variable name`);
218
+ }
219
+ }
220
+ function optionalPolicyBoolean(raw, key, fallback) {
221
+ const value = raw[key];
222
+ if (value === undefined)
223
+ return fallback;
224
+ if (typeof value !== "boolean")
225
+ throw new Error(`Invalid policy.${key}: expected boolean`);
226
+ return value;
227
+ }
228
+ function optionalPolicyNumber(raw, key, fallback) {
229
+ const value = raw[key];
230
+ if (value === undefined)
231
+ return fallback;
232
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
233
+ throw new Error(`Invalid policy.${key}: expected positive number`);
234
+ }
235
+ return value;
236
+ }
237
+ function optionalPolicyStringArray(raw, key, fallback) {
238
+ const value = raw[key];
239
+ if (value === undefined)
240
+ return fallback;
241
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
242
+ throw new Error(`Invalid policy.${key}: expected string array`);
243
+ }
244
+ return value;
245
+ }
246
+ function optionalPolicyPermissionLevel(raw, fallback) {
247
+ const value = raw.permissionLevel;
248
+ if (value === 1 || value === 2 || value === 3)
249
+ return value;
250
+ if (value !== undefined) {
251
+ throw new Error("Invalid policy.permissionLevel: expected 1, 2, or 3");
252
+ }
253
+ return fallback;
254
+ }
255
+ function expandHome(path) {
256
+ if (path === "~")
257
+ return process.env.HOME ?? path;
258
+ if (path.startsWith("~/"))
259
+ return `${process.env.HOME ?? "~"}${path.slice(1)}`;
260
+ return path;
261
+ }
262
+ //# sourceMappingURL=inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.js","sourceRoot":"","sources":["../src/inventory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { SshOperations } from "./operations.js";
3
+ import type { Auditor } from "./audit.js";
4
+ type McpServerOptions = {
5
+ auditor?: Auditor;
6
+ };
7
+ export declare function createMcpServer(operations: SshOperations, options?: McpServerOptions): McpServer;
8
+ export {};