enterprise-ssh-mcp-server 0.3.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 +266 -0
- package/dist/buffers.d.ts +42 -0
- package/dist/buffers.js +123 -0
- package/dist/buffers.js.map +1 -0
- package/dist/env-profiles.d.ts +62 -0
- package/dist/env-profiles.js +417 -0
- package/dist/env-profiles.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1805 -0
- package/dist/index.js.map +1 -0
- package/dist/remote-edit.d.ts +91 -0
- package/dist/remote-edit.js +426 -0
- package/dist/remote-edit.js.map +1 -0
- package/dist/remote-path.d.ts +4 -0
- package/dist/remote-path.js +24 -0
- package/dist/remote-path.js.map +1 -0
- package/dist/runtime-config.d.ts +36 -0
- package/dist/runtime-config.js +130 -0
- package/dist/runtime-config.js.map +1 -0
- package/dist/session-registry.d.ts +9 -0
- package/dist/session-registry.js +35 -0
- package/dist/session-registry.js.map +1 -0
- package/dist/sftp-ops.d.ts +46 -0
- package/dist/sftp-ops.js +306 -0
- package/dist/sftp-ops.js.map +1 -0
- package/dist/ssh-session.d.ts +146 -0
- package/dist/ssh-session.js +618 -0
- package/dist/ssh-session.js.map +1 -0
- package/dist/tool-result.d.ts +11 -0
- package/dist/tool-result.js +67 -0
- package/dist/tool-result.js.map +1 -0
- package/dist/transfer-manager.d.ts +60 -0
- package/dist/transfer-manager.js +339 -0
- package/dist/transfer-manager.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { dirnameRemote, joinRemotePath, normalizeRemotePath } from "./remote-path.js";
|
|
3
|
+
import { sftpMkdirRecursive, sftpReadDir, sftpRename, sftpStat, sftpUnlink, sftpWriteFile, statsToJson, } from "./sftp-ops.js";
|
|
4
|
+
import { McpToolError } from "./tool-result.js";
|
|
5
|
+
const DEFAULT_IGNORE_NAMES = new Set([
|
|
6
|
+
".git",
|
|
7
|
+
"node_modules",
|
|
8
|
+
"dist",
|
|
9
|
+
"build",
|
|
10
|
+
"coverage",
|
|
11
|
+
".next",
|
|
12
|
+
".nuxt",
|
|
13
|
+
".turbo",
|
|
14
|
+
".cache",
|
|
15
|
+
"target",
|
|
16
|
+
"vendor",
|
|
17
|
+
"__pycache__",
|
|
18
|
+
]);
|
|
19
|
+
export function sha256(buffer) {
|
|
20
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
export function defaultEditRoot(profile) {
|
|
23
|
+
const root = profile.editRoot ?? profile.defaultDir;
|
|
24
|
+
if (root === undefined || root.trim().length === 0) {
|
|
25
|
+
throw new McpToolError("ssh_project_root_required", "SSH profile needs DEFAULT_DIR, EDIT_ROOT, or projectRoot", {
|
|
26
|
+
profileName: profile.name,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return root;
|
|
30
|
+
}
|
|
31
|
+
export function ensureProfileAllowsEdit(profile) {
|
|
32
|
+
if (profile.allowEdit !== true) {
|
|
33
|
+
throw new McpToolError("ssh_profile_edit_disabled", "SSH profile editing is disabled", {
|
|
34
|
+
profileName: profile.name,
|
|
35
|
+
requiredEnv: `SSH_MCP_SERVER_<N>_ALLOW_EDIT=true`,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function resolveProjectRoot(sftp, profile, projectRoot) {
|
|
40
|
+
const editRoot = await sftpRealpathSafe(sftp, defaultEditRoot(profile));
|
|
41
|
+
const candidatePath = projectRoot === undefined ? editRoot : toAbsoluteRemotePath(editRoot, projectRoot);
|
|
42
|
+
const realProjectRoot = await sftpRealpathSafe(sftp, candidatePath);
|
|
43
|
+
assertPathInsideRoot(editRoot, realProjectRoot, projectRoot ?? ".");
|
|
44
|
+
return realProjectRoot;
|
|
45
|
+
}
|
|
46
|
+
export async function resolveSafeRemotePath(sftp, profile, projectRoot, filePath, mustExist) {
|
|
47
|
+
const rootPath = await resolveProjectRoot(sftp, profile, projectRoot);
|
|
48
|
+
const candidatePath = toAbsoluteRemotePath(rootPath, filePath);
|
|
49
|
+
assertPathInsideRoot(rootPath, candidatePath, filePath);
|
|
50
|
+
if (mustExist) {
|
|
51
|
+
const realPath = await sftpRealpathSafe(sftp, candidatePath);
|
|
52
|
+
assertPathInsideRoot(rootPath, realPath, filePath);
|
|
53
|
+
return { rootPath, remotePath: realPath };
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const realPath = await sftpRealpathSafe(sftp, candidatePath);
|
|
57
|
+
assertPathInsideRoot(rootPath, realPath, filePath);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (!isMissingPathLike(error)) {
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
const parentPath = dirnameRemote(candidatePath);
|
|
64
|
+
const parentRealPath = await sftpRealpathSafe(sftp, parentPath);
|
|
65
|
+
assertPathInsideRoot(rootPath, parentRealPath, filePath);
|
|
66
|
+
}
|
|
67
|
+
return { rootPath, remotePath: candidatePath };
|
|
68
|
+
}
|
|
69
|
+
export async function readRemoteFileSnapshot(sftp, remotePath, maxBytes) {
|
|
70
|
+
const stats = await sftpStat(sftp, remotePath, true);
|
|
71
|
+
if (!stats.isFile()) {
|
|
72
|
+
throw new McpToolError("ssh_edit_path_not_file", "Remote path is not a regular file", { remotePath });
|
|
73
|
+
}
|
|
74
|
+
if (stats.size > maxBytes) {
|
|
75
|
+
throw new McpToolError("ssh_edit_file_too_large", "Remote file exceeds max edit size", {
|
|
76
|
+
remotePath,
|
|
77
|
+
bytes: stats.size,
|
|
78
|
+
maxBytes,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const data = await readRemoteFileBuffer(sftp, remotePath);
|
|
82
|
+
return {
|
|
83
|
+
remotePath,
|
|
84
|
+
data,
|
|
85
|
+
sha256: sha256(data),
|
|
86
|
+
stats,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function publicSnapshot(snapshot, encoding) {
|
|
90
|
+
return {
|
|
91
|
+
remotePath: snapshot.remotePath,
|
|
92
|
+
data: encoding === "base64" ? snapshot.data.toString("base64") : snapshot.data.toString("utf8"),
|
|
93
|
+
encoding,
|
|
94
|
+
bytes: snapshot.data.length,
|
|
95
|
+
sha256: snapshot.sha256,
|
|
96
|
+
stats: statsToJson(snapshot.stats),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function assertExpectedSha256(snapshot, expectedSha256, requireExpectedSha256, remotePath) {
|
|
100
|
+
if (snapshot === undefined) {
|
|
101
|
+
if (expectedSha256 !== undefined && expectedSha256 !== "absent") {
|
|
102
|
+
throw new McpToolError("ssh_edit_expected_hash_mismatch", "Remote file is absent but expected a hash", {
|
|
103
|
+
remotePath,
|
|
104
|
+
expectedSha256,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (expectedSha256 === undefined && requireExpectedSha256) {
|
|
110
|
+
throw new McpToolError("ssh_edit_expected_hash_required", "expectedSha256 is required for existing files", {
|
|
111
|
+
remotePath,
|
|
112
|
+
currentSha256: snapshot.sha256,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (expectedSha256 === "absent") {
|
|
116
|
+
throw new McpToolError("ssh_edit_expected_hash_mismatch", "Remote file exists but expected absent", {
|
|
117
|
+
remotePath,
|
|
118
|
+
currentSha256: snapshot.sha256,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (expectedSha256 !== undefined && expectedSha256 !== snapshot.sha256) {
|
|
122
|
+
throw new McpToolError("ssh_edit_expected_hash_mismatch", "Remote file changed since it was read", {
|
|
123
|
+
remotePath,
|
|
124
|
+
expectedSha256,
|
|
125
|
+
currentSha256: snapshot.sha256,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export async function writeRemoteFileAtomic(sftp, remotePath, data, mode, createDirs) {
|
|
130
|
+
if (createDirs) {
|
|
131
|
+
await sftpMkdirRecursive(sftp, dirnameRemote(remotePath));
|
|
132
|
+
}
|
|
133
|
+
const tempPath = `${remotePath}.mcp-edit-${Date.now()}-${randomUUID()}.tmp`;
|
|
134
|
+
try {
|
|
135
|
+
await sftpWriteFile(sftp, tempPath, data, mode, "wx");
|
|
136
|
+
await sftpRename(sftp, tempPath, remotePath);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
await sftpUnlink(sftp, tempPath).catch(() => undefined);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export async function createRemoteBackup(sftp, profile, rootPath, snapshot) {
|
|
144
|
+
const editId = randomUUID();
|
|
145
|
+
const backupRootCandidate = profile.backupDir === undefined
|
|
146
|
+
? dirnameRemote(snapshot.remotePath)
|
|
147
|
+
: toAbsoluteRemotePath(rootPath, profile.backupDir);
|
|
148
|
+
assertPathInsideRoot(rootPath, backupRootCandidate, profile.backupDir ?? dirnameRemote(snapshot.remotePath));
|
|
149
|
+
await sftpMkdirRecursive(sftp, backupRootCandidate);
|
|
150
|
+
const backupRoot = await sftpRealpathSafe(sftp, backupRootCandidate);
|
|
151
|
+
assertPathInsideRoot(rootPath, backupRoot, profile.backupDir ?? dirnameRemote(snapshot.remotePath));
|
|
152
|
+
const backupPath = joinRemotePath(backupRoot, `.mcp-edit-backup-${Date.now()}-${editId}`);
|
|
153
|
+
await sftpWriteFile(sftp, backupPath, snapshot.data, snapshot.stats.mode & 0o777, "wx");
|
|
154
|
+
return {
|
|
155
|
+
editId,
|
|
156
|
+
originalPath: snapshot.remotePath,
|
|
157
|
+
backupPath,
|
|
158
|
+
sha256: snapshot.sha256,
|
|
159
|
+
bytes: snapshot.data.length,
|
|
160
|
+
createdAt: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
export async function readRemoteTree(sftp, rootPath, options) {
|
|
164
|
+
let entryCount = 0;
|
|
165
|
+
let truncated = false;
|
|
166
|
+
const walk = async (currentPath, depth) => {
|
|
167
|
+
if (depth > options.maxDepth || truncated) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const entries = await sftpReadDir(sftp, currentPath);
|
|
171
|
+
const output = [];
|
|
172
|
+
for (const entry of entries) {
|
|
173
|
+
if (entry.filename === "." || entry.filename === "..") {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (!options.includeHidden && entry.filename.startsWith(".")) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (shouldIgnoreName(entry.filename, options.ignoreNames)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (entryCount >= options.maxEntries) {
|
|
183
|
+
truncated = true;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
const childPath = joinRemotePath(currentPath, entry.filename);
|
|
187
|
+
const stats = statsToJson(entry.attrs);
|
|
188
|
+
entryCount += 1;
|
|
189
|
+
const treeEntry = {
|
|
190
|
+
path: childPath,
|
|
191
|
+
type: stats.type,
|
|
192
|
+
size: stats.size,
|
|
193
|
+
permissionsOctal: stats.permissionsOctal,
|
|
194
|
+
mtime: stats.mtime,
|
|
195
|
+
};
|
|
196
|
+
if (entry.attrs.isDirectory() && depth < options.maxDepth) {
|
|
197
|
+
treeEntry.children = await walk(childPath, depth + 1);
|
|
198
|
+
}
|
|
199
|
+
output.push(treeEntry);
|
|
200
|
+
}
|
|
201
|
+
return output.sort((left, right) => `${left.type}:${left.path}`.localeCompare(`${right.type}:${right.path}`));
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
rootPath,
|
|
205
|
+
entries: await walk(rootPath, 1),
|
|
206
|
+
truncated,
|
|
207
|
+
entryCount,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
export function parseUnifiedPatch(patch) {
|
|
211
|
+
const lines = patch.replace(/\r\n/g, "\n").split("\n");
|
|
212
|
+
const files = [];
|
|
213
|
+
let index = 0;
|
|
214
|
+
let currentFile;
|
|
215
|
+
while (index < lines.length) {
|
|
216
|
+
const line = lines[index] ?? "";
|
|
217
|
+
if (line.startsWith("--- ")) {
|
|
218
|
+
const oldPath = parsePatchPath(line.slice(4));
|
|
219
|
+
const nextLine = lines[index + 1];
|
|
220
|
+
if (nextLine === undefined || !nextLine.startsWith("+++ ")) {
|
|
221
|
+
throw new McpToolError("invalid_unified_patch", "Unified patch file header is missing +++ line", { line });
|
|
222
|
+
}
|
|
223
|
+
currentFile = {
|
|
224
|
+
oldPath,
|
|
225
|
+
newPath: parsePatchPath(nextLine.slice(4)),
|
|
226
|
+
hunks: [],
|
|
227
|
+
isNewFile: oldPath === "/dev/null",
|
|
228
|
+
isDeletedFile: parsePatchPath(nextLine.slice(4)) === "/dev/null",
|
|
229
|
+
};
|
|
230
|
+
files.push(currentFile);
|
|
231
|
+
index += 2;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (line.startsWith("@@ ")) {
|
|
235
|
+
if (currentFile === undefined) {
|
|
236
|
+
throw new McpToolError("invalid_unified_patch", "Unified patch hunk appeared before file header", { line });
|
|
237
|
+
}
|
|
238
|
+
const hunk = parseHunkHeader(line);
|
|
239
|
+
index += 1;
|
|
240
|
+
while (index < lines.length) {
|
|
241
|
+
const hunkLine = lines[index] ?? "";
|
|
242
|
+
if (hunkLine.startsWith("--- ") || hunkLine.startsWith("@@ ")) {
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
if (hunkLine.startsWith("\\ No newline")) {
|
|
246
|
+
index += 1;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const marker = hunkLine[0];
|
|
250
|
+
const text = hunkLine.slice(1);
|
|
251
|
+
if (marker === " ") {
|
|
252
|
+
hunk.lines.push({ kind: "context", text });
|
|
253
|
+
}
|
|
254
|
+
else if (marker === "-") {
|
|
255
|
+
hunk.lines.push({ kind: "remove", text });
|
|
256
|
+
}
|
|
257
|
+
else if (marker === "+") {
|
|
258
|
+
hunk.lines.push({ kind: "add", text });
|
|
259
|
+
}
|
|
260
|
+
else if (hunkLine.length > 0) {
|
|
261
|
+
throw new McpToolError("invalid_unified_patch", "Invalid unified patch hunk line", { line: hunkLine });
|
|
262
|
+
}
|
|
263
|
+
index += 1;
|
|
264
|
+
}
|
|
265
|
+
currentFile.hunks.push(hunk);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
index += 1;
|
|
269
|
+
}
|
|
270
|
+
if (files.length === 0) {
|
|
271
|
+
throw new McpToolError("invalid_unified_patch", "Unified patch did not contain any files");
|
|
272
|
+
}
|
|
273
|
+
return files;
|
|
274
|
+
}
|
|
275
|
+
export function applyUnifiedPatch(original, patchFile) {
|
|
276
|
+
if (patchFile.isDeletedFile) {
|
|
277
|
+
throw new McpToolError("unsupported_unified_patch", "File deletion patches are not applied by patch tools", {
|
|
278
|
+
oldPath: patchFile.oldPath,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
const split = splitText(original);
|
|
282
|
+
const output = [];
|
|
283
|
+
let pointer = 0;
|
|
284
|
+
for (const hunk of patchFile.hunks) {
|
|
285
|
+
const targetIndex = hunk.oldStart === 0 ? 0 : hunk.oldStart - 1;
|
|
286
|
+
if (targetIndex < pointer || targetIndex > split.lines.length) {
|
|
287
|
+
throw new McpToolError("unified_patch_context_mismatch", "Unified patch hunk location does not match file", {
|
|
288
|
+
oldStart: hunk.oldStart,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
output.push(...split.lines.slice(pointer, targetIndex));
|
|
292
|
+
pointer = targetIndex;
|
|
293
|
+
for (const line of hunk.lines) {
|
|
294
|
+
if (line.kind === "add") {
|
|
295
|
+
output.push(line.text);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const actual = split.lines[pointer];
|
|
299
|
+
if (actual !== line.text) {
|
|
300
|
+
throw new McpToolError("unified_patch_context_mismatch", "Unified patch context does not match file", {
|
|
301
|
+
expected: line.text,
|
|
302
|
+
actual,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (line.kind === "context") {
|
|
306
|
+
output.push(actual);
|
|
307
|
+
}
|
|
308
|
+
pointer += 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
output.push(...split.lines.slice(pointer));
|
|
312
|
+
return joinText(output, split.trailingNewline);
|
|
313
|
+
}
|
|
314
|
+
export function patchTargetPath(patchFile) {
|
|
315
|
+
if (patchFile.isDeletedFile) {
|
|
316
|
+
return stripPatchPathPrefix(patchFile.oldPath);
|
|
317
|
+
}
|
|
318
|
+
return stripPatchPathPrefix(patchFile.newPath);
|
|
319
|
+
}
|
|
320
|
+
export function maxEditFileBytes(profile, fallback) {
|
|
321
|
+
return profile.maxEditFileBytes ?? fallback;
|
|
322
|
+
}
|
|
323
|
+
export function defaultTreeOptions(input) {
|
|
324
|
+
return {
|
|
325
|
+
maxDepth: input.maxDepth ?? 4,
|
|
326
|
+
maxEntries: input.maxEntries ?? 500,
|
|
327
|
+
includeHidden: input.includeHidden ?? false,
|
|
328
|
+
ignoreNames: input.ignoreNames ?? [...DEFAULT_IGNORE_NAMES],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
async function readRemoteFileBuffer(sftp, remotePath) {
|
|
332
|
+
return new Promise((resolve, reject) => {
|
|
333
|
+
const chunks = [];
|
|
334
|
+
const stream = sftp.createReadStream(remotePath);
|
|
335
|
+
stream.on("data", (chunk) => {
|
|
336
|
+
chunks.push(chunk);
|
|
337
|
+
});
|
|
338
|
+
stream.on("end", () => {
|
|
339
|
+
resolve(Buffer.concat(chunks));
|
|
340
|
+
});
|
|
341
|
+
stream.on("error", (error) => {
|
|
342
|
+
reject(new McpToolError("sftp_readFile_failed", error.message, { action: "readFile", remotePath }));
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function parseHunkHeader(line) {
|
|
347
|
+
const match = /^@@ -(?<oldStart>\d+)(?:,(?<oldCount>\d+))? \+(?<newStart>\d+)(?:,(?<newCount>\d+))? @@/.exec(line);
|
|
348
|
+
if (match?.groups === undefined) {
|
|
349
|
+
throw new McpToolError("invalid_unified_patch", "Invalid unified patch hunk header", { line });
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
oldStart: Number.parseInt(match.groups.oldStart ?? "0", 10),
|
|
353
|
+
oldCount: Number.parseInt(match.groups.oldCount ?? "1", 10),
|
|
354
|
+
newStart: Number.parseInt(match.groups.newStart ?? "0", 10),
|
|
355
|
+
newCount: Number.parseInt(match.groups.newCount ?? "1", 10),
|
|
356
|
+
lines: [],
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function parsePatchPath(rawPath) {
|
|
360
|
+
const [path] = rawPath.trim().split(/\s+/);
|
|
361
|
+
if (path === undefined || path.length === 0) {
|
|
362
|
+
throw new McpToolError("invalid_unified_patch", "Unified patch path is empty", { rawPath });
|
|
363
|
+
}
|
|
364
|
+
return path;
|
|
365
|
+
}
|
|
366
|
+
function stripPatchPathPrefix(patchPath) {
|
|
367
|
+
if (patchPath === "/dev/null") {
|
|
368
|
+
return patchPath;
|
|
369
|
+
}
|
|
370
|
+
if (/^[ab]\//.test(patchPath)) {
|
|
371
|
+
return patchPath.slice(2);
|
|
372
|
+
}
|
|
373
|
+
return patchPath;
|
|
374
|
+
}
|
|
375
|
+
function splitText(text) {
|
|
376
|
+
const normalized = text.replace(/\r\n/g, "\n");
|
|
377
|
+
const trailingNewline = normalized.endsWith("\n");
|
|
378
|
+
const body = trailingNewline ? normalized.slice(0, -1) : normalized;
|
|
379
|
+
return {
|
|
380
|
+
lines: body.length === 0 ? [] : body.split("\n"),
|
|
381
|
+
trailingNewline,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function joinText(lines, trailingNewline) {
|
|
385
|
+
return `${lines.join("\n")}${trailingNewline ? "\n" : ""}`;
|
|
386
|
+
}
|
|
387
|
+
function toAbsoluteRemotePath(rootPath, filePath) {
|
|
388
|
+
const normalizedFilePath = normalizeRemotePath(filePath);
|
|
389
|
+
if (normalizedFilePath.startsWith("/")) {
|
|
390
|
+
return normalizedFilePath;
|
|
391
|
+
}
|
|
392
|
+
return normalizeRemotePath(joinRemotePath(rootPath, normalizedFilePath));
|
|
393
|
+
}
|
|
394
|
+
function assertPathInsideRoot(rootPath, remotePath, requestedPath) {
|
|
395
|
+
const normalizedRoot = normalizeRemotePath(rootPath);
|
|
396
|
+
const normalizedPath = normalizeRemotePath(remotePath);
|
|
397
|
+
if (normalizedPath === normalizedRoot || normalizedPath.startsWith(`${normalizedRoot}/`)) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
throw new McpToolError("ssh_edit_path_outside_root", "Remote path is outside the project root", {
|
|
401
|
+
requestedPath,
|
|
402
|
+
rootPath: normalizedRoot,
|
|
403
|
+
remotePath: normalizedPath,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
function shouldIgnoreName(name, ignoreNames) {
|
|
407
|
+
return DEFAULT_IGNORE_NAMES.has(name) || ignoreNames.includes(name);
|
|
408
|
+
}
|
|
409
|
+
function sftpRealpathSafe(sftp, remotePath) {
|
|
410
|
+
return new Promise((resolve, reject) => {
|
|
411
|
+
sftp.realpath(remotePath, (error, absolutePath) => {
|
|
412
|
+
if (error != null) {
|
|
413
|
+
reject(new McpToolError("sftp_realpath_failed", error.message, { action: "realpath", remotePath }));
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
resolve(normalizeRemotePath(absolutePath));
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function isMissingPathLike(error) {
|
|
421
|
+
if (error instanceof McpToolError) {
|
|
422
|
+
return /no such file|not found|failure/i.test(error.message);
|
|
423
|
+
}
|
|
424
|
+
return /no such file|not found/i.test(error.message);
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=remote-edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-edit.js","sourceRoot":"","sources":["../src/remote-edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function normalizeRemotePath(remotePath: string): string;
|
|
2
|
+
export declare function dirnameRemote(remotePath: string): string;
|
|
3
|
+
export declare function splitRemotePath(remotePath: string): string[];
|
|
4
|
+
export declare function joinRemotePath(...parts: string[]): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
export function normalizeRemotePath(remotePath) {
|
|
3
|
+
if (remotePath.length === 0) {
|
|
4
|
+
return ".";
|
|
5
|
+
}
|
|
6
|
+
if (remotePath.startsWith("/")) {
|
|
7
|
+
return posix.normalize(remotePath);
|
|
8
|
+
}
|
|
9
|
+
return posix.normalize(remotePath);
|
|
10
|
+
}
|
|
11
|
+
export function dirnameRemote(remotePath) {
|
|
12
|
+
const normalized = normalizeRemotePath(remotePath);
|
|
13
|
+
const dirname = posix.dirname(normalized);
|
|
14
|
+
return dirname.length === 0 ? "." : dirname;
|
|
15
|
+
}
|
|
16
|
+
export function splitRemotePath(remotePath) {
|
|
17
|
+
return normalizeRemotePath(remotePath)
|
|
18
|
+
.split("/")
|
|
19
|
+
.filter((part) => part.length > 0 && part !== ".");
|
|
20
|
+
}
|
|
21
|
+
export function joinRemotePath(...parts) {
|
|
22
|
+
return posix.join(...parts);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=remote-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-path.js","sourceRoot":"","sources":["../src/remote-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,MAAM,UAAU,mBAAmB,CAAC,UAAkB;IACpD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,OAAO,mBAAmB,CAAC,UAAU,CAAC;SACnC,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAG,KAAe;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface RuntimeConfig {
|
|
2
|
+
envPath: string;
|
|
3
|
+
toolset: Toolset;
|
|
4
|
+
compactJson: boolean;
|
|
5
|
+
enableDangerousTools: boolean;
|
|
6
|
+
defaultSshPort: number;
|
|
7
|
+
defaultAgentForward: boolean;
|
|
8
|
+
defaultTryKeyboard: boolean;
|
|
9
|
+
defaultKeepaliveIntervalMs: number;
|
|
10
|
+
defaultKeepaliveCountMax: number;
|
|
11
|
+
defaultReadyTimeoutMs: number;
|
|
12
|
+
defaultConnectionTimeoutMs: number;
|
|
13
|
+
defaultExecTimeoutMs: number;
|
|
14
|
+
defaultMaxOutputBytes: number;
|
|
15
|
+
defaultShellAllocatePty: boolean;
|
|
16
|
+
defaultShellRingBufferBytes: number;
|
|
17
|
+
defaultShellReadMaxBytes: number;
|
|
18
|
+
defaultSftpReadMaxBytes: number;
|
|
19
|
+
defaultTransferChunkSizeBytes: number;
|
|
20
|
+
defaultTransferResume: boolean;
|
|
21
|
+
defaultTransferOverwrite: boolean;
|
|
22
|
+
defaultTransferAtomic: boolean;
|
|
23
|
+
defaultMaxEditFileBytes: number;
|
|
24
|
+
defaultMaxPatchBytes: number;
|
|
25
|
+
defaultLocalTunnelHost: string;
|
|
26
|
+
defaultRemoteTunnelHost: string;
|
|
27
|
+
}
|
|
28
|
+
export type Toolset = "agent" | "full";
|
|
29
|
+
export declare class RuntimeConfigRegistry {
|
|
30
|
+
private readonly envPath;
|
|
31
|
+
private config;
|
|
32
|
+
constructor(envPath: string);
|
|
33
|
+
get(): RuntimeConfig;
|
|
34
|
+
reload(): RuntimeConfig;
|
|
35
|
+
}
|
|
36
|
+
export declare function loadRuntimeConfig(envPath: string): RuntimeConfig;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { parseEnvFile } from "./env-profiles.js";
|
|
3
|
+
import { McpToolError } from "./tool-result.js";
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
toolset: "agent",
|
|
6
|
+
compactJson: true,
|
|
7
|
+
enableDangerousTools: false,
|
|
8
|
+
defaultSshPort: 22,
|
|
9
|
+
defaultAgentForward: false,
|
|
10
|
+
defaultTryKeyboard: false,
|
|
11
|
+
defaultKeepaliveIntervalMs: 10_000,
|
|
12
|
+
defaultKeepaliveCountMax: 3,
|
|
13
|
+
defaultReadyTimeoutMs: 20_000,
|
|
14
|
+
defaultConnectionTimeoutMs: 30_000,
|
|
15
|
+
defaultExecTimeoutMs: 60_000,
|
|
16
|
+
defaultMaxOutputBytes: 1024 * 1024,
|
|
17
|
+
defaultShellAllocatePty: true,
|
|
18
|
+
defaultShellRingBufferBytes: 1024 * 1024,
|
|
19
|
+
defaultShellReadMaxBytes: 256 * 1024,
|
|
20
|
+
defaultSftpReadMaxBytes: 1024 * 1024,
|
|
21
|
+
defaultTransferChunkSizeBytes: 1024 * 1024,
|
|
22
|
+
defaultTransferResume: true,
|
|
23
|
+
defaultTransferOverwrite: false,
|
|
24
|
+
defaultTransferAtomic: false,
|
|
25
|
+
defaultMaxEditFileBytes: 1024 * 1024,
|
|
26
|
+
defaultMaxPatchBytes: 2 * 1024 * 1024,
|
|
27
|
+
defaultLocalTunnelHost: "127.0.0.1",
|
|
28
|
+
defaultRemoteTunnelHost: "127.0.0.1",
|
|
29
|
+
};
|
|
30
|
+
export class RuntimeConfigRegistry {
|
|
31
|
+
envPath;
|
|
32
|
+
config;
|
|
33
|
+
constructor(envPath) {
|
|
34
|
+
this.envPath = envPath;
|
|
35
|
+
this.config = loadRuntimeConfig(envPath);
|
|
36
|
+
}
|
|
37
|
+
get() {
|
|
38
|
+
return this.config;
|
|
39
|
+
}
|
|
40
|
+
reload() {
|
|
41
|
+
this.config = loadRuntimeConfig(this.envPath);
|
|
42
|
+
return this.config;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function loadRuntimeConfig(envPath) {
|
|
46
|
+
const variables = existsSync(envPath) ? parseEnvFile(readFileSync(envPath, "utf8")) : new Map();
|
|
47
|
+
return {
|
|
48
|
+
envPath,
|
|
49
|
+
toolset: readToolset(variables, "SSH_MCP_TOOLSET", DEFAULT_CONFIG.toolset),
|
|
50
|
+
compactJson: readBoolean(variables, "SSH_MCP_COMPACT_JSON", DEFAULT_CONFIG.compactJson),
|
|
51
|
+
enableDangerousTools: readBoolean(variables, "SSH_MCP_ENABLE_DANGEROUS_TOOLS", DEFAULT_CONFIG.enableDangerousTools),
|
|
52
|
+
defaultSshPort: readInteger(variables, "SSH_MCP_DEFAULT_SSH_PORT", DEFAULT_CONFIG.defaultSshPort, 1, 65_535),
|
|
53
|
+
defaultAgentForward: readBoolean(variables, "SSH_MCP_DEFAULT_AGENT_FORWARD", DEFAULT_CONFIG.defaultAgentForward),
|
|
54
|
+
defaultTryKeyboard: readBoolean(variables, "SSH_MCP_DEFAULT_TRY_KEYBOARD", DEFAULT_CONFIG.defaultTryKeyboard),
|
|
55
|
+
defaultKeepaliveIntervalMs: readInteger(variables, "SSH_MCP_DEFAULT_KEEPALIVE_INTERVAL_MS", DEFAULT_CONFIG.defaultKeepaliveIntervalMs, 0, 3_600_000),
|
|
56
|
+
defaultKeepaliveCountMax: readInteger(variables, "SSH_MCP_DEFAULT_KEEPALIVE_COUNT_MAX", DEFAULT_CONFIG.defaultKeepaliveCountMax, 1, 100),
|
|
57
|
+
defaultReadyTimeoutMs: readInteger(variables, "SSH_MCP_DEFAULT_READY_TIMEOUT_MS", DEFAULT_CONFIG.defaultReadyTimeoutMs, 1_000, 3_600_000),
|
|
58
|
+
defaultConnectionTimeoutMs: readInteger(variables, "SSH_MCP_DEFAULT_CONNECTION_TIMEOUT_MS", DEFAULT_CONFIG.defaultConnectionTimeoutMs, 1_000, 3_600_000),
|
|
59
|
+
defaultExecTimeoutMs: readInteger(variables, "SSH_MCP_DEFAULT_EXEC_TIMEOUT_MS", DEFAULT_CONFIG.defaultExecTimeoutMs, 1, 86_400_000),
|
|
60
|
+
defaultMaxOutputBytes: readInteger(variables, "SSH_MCP_DEFAULT_MAX_OUTPUT_BYTES", DEFAULT_CONFIG.defaultMaxOutputBytes, 1, 64 * 1024 * 1024),
|
|
61
|
+
defaultShellAllocatePty: readBoolean(variables, "SSH_MCP_DEFAULT_SHELL_ALLOCATE_PTY", DEFAULT_CONFIG.defaultShellAllocatePty),
|
|
62
|
+
defaultShellRingBufferBytes: readInteger(variables, "SSH_MCP_DEFAULT_SHELL_RING_BUFFER_BYTES", DEFAULT_CONFIG.defaultShellRingBufferBytes, 1024, 64 * 1024 * 1024),
|
|
63
|
+
defaultShellReadMaxBytes: readInteger(variables, "SSH_MCP_DEFAULT_SHELL_READ_MAX_BYTES", DEFAULT_CONFIG.defaultShellReadMaxBytes, 1, 64 * 1024 * 1024),
|
|
64
|
+
defaultSftpReadMaxBytes: readInteger(variables, "SSH_MCP_DEFAULT_SFTP_READ_MAX_BYTES", DEFAULT_CONFIG.defaultSftpReadMaxBytes, 1, 64 * 1024 * 1024),
|
|
65
|
+
defaultTransferChunkSizeBytes: readInteger(variables, "SSH_MCP_DEFAULT_TRANSFER_CHUNK_SIZE_BYTES", DEFAULT_CONFIG.defaultTransferChunkSizeBytes, 16 * 1024, 16 * 1024 * 1024),
|
|
66
|
+
defaultTransferResume: readBoolean(variables, "SSH_MCP_DEFAULT_TRANSFER_RESUME", DEFAULT_CONFIG.defaultTransferResume),
|
|
67
|
+
defaultTransferOverwrite: readBoolean(variables, "SSH_MCP_DEFAULT_TRANSFER_OVERWRITE", DEFAULT_CONFIG.defaultTransferOverwrite),
|
|
68
|
+
defaultTransferAtomic: readBoolean(variables, "SSH_MCP_DEFAULT_TRANSFER_ATOMIC", DEFAULT_CONFIG.defaultTransferAtomic),
|
|
69
|
+
defaultMaxEditFileBytes: readInteger(variables, "SSH_MCP_DEFAULT_MAX_EDIT_FILE_BYTES", DEFAULT_CONFIG.defaultMaxEditFileBytes, 1, 64 * 1024 * 1024),
|
|
70
|
+
defaultMaxPatchBytes: readInteger(variables, "SSH_MCP_DEFAULT_MAX_PATCH_BYTES", DEFAULT_CONFIG.defaultMaxPatchBytes, 1, 16 * 1024 * 1024),
|
|
71
|
+
defaultLocalTunnelHost: readString(variables, "SSH_MCP_DEFAULT_LOCAL_TUNNEL_HOST", DEFAULT_CONFIG.defaultLocalTunnelHost),
|
|
72
|
+
defaultRemoteTunnelHost: readString(variables, "SSH_MCP_DEFAULT_REMOTE_TUNNEL_HOST", DEFAULT_CONFIG.defaultRemoteTunnelHost),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function readString(variables, key, fallback) {
|
|
76
|
+
const value = variables.get(key);
|
|
77
|
+
if (value === undefined || value.trim().length === 0) {
|
|
78
|
+
return fallback;
|
|
79
|
+
}
|
|
80
|
+
return value.trim();
|
|
81
|
+
}
|
|
82
|
+
function readToolset(variables, key, fallback) {
|
|
83
|
+
const value = variables.get(key);
|
|
84
|
+
if (value === undefined || value.trim().length === 0) {
|
|
85
|
+
return fallback;
|
|
86
|
+
}
|
|
87
|
+
const normalized = value.trim().toLowerCase();
|
|
88
|
+
if (normalized === "agent" || normalized === "full") {
|
|
89
|
+
return normalized;
|
|
90
|
+
}
|
|
91
|
+
throw new McpToolError("invalid_runtime_config", "Runtime config value must be a supported toolset", {
|
|
92
|
+
key,
|
|
93
|
+
value,
|
|
94
|
+
supportedToolsets: ["agent", "full"],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function readInteger(variables, key, fallback, minInclusive, maxInclusive) {
|
|
98
|
+
const value = variables.get(key);
|
|
99
|
+
if (value === undefined || value.trim().length === 0) {
|
|
100
|
+
return fallback;
|
|
101
|
+
}
|
|
102
|
+
const parsed = Number.parseInt(value, 10);
|
|
103
|
+
if (!Number.isInteger(parsed) || String(parsed) !== value.trim()) {
|
|
104
|
+
throw new McpToolError("invalid_runtime_config", "Runtime config value must be an integer", { key, value });
|
|
105
|
+
}
|
|
106
|
+
if (parsed < minInclusive || parsed > maxInclusive) {
|
|
107
|
+
throw new McpToolError("invalid_runtime_config", "Runtime config value is outside the allowed range", {
|
|
108
|
+
key,
|
|
109
|
+
value,
|
|
110
|
+
minInclusive,
|
|
111
|
+
maxInclusive,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
function readBoolean(variables, key, fallback) {
|
|
117
|
+
const value = variables.get(key);
|
|
118
|
+
if (value === undefined || value.trim().length === 0) {
|
|
119
|
+
return fallback;
|
|
120
|
+
}
|
|
121
|
+
const normalized = value.trim().toLowerCase();
|
|
122
|
+
if (["true", "1", "yes", "y", "on"].includes(normalized)) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (["false", "0", "no", "n", "off"].includes(normalized)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
throw new McpToolError("invalid_runtime_config", "Runtime config value must be boolean-like", { key, value });
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=runtime-config.js.map
|