@lzm04521/ssh-mcp-server 1.1.5

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 (78) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +157 -0
  3. package/admin-web/dist/assets/index-DXbr5DVR.js +494 -0
  4. package/admin-web/dist/index.html +6 -0
  5. package/admin-web/dist/logo.png +0 -0
  6. package/build/cli/command-line-parser.js +715 -0
  7. package/build/cli/command-line-parser.js.map +1 -0
  8. package/build/cli/run-mode.js +44 -0
  9. package/build/cli/run-mode.js.map +1 -0
  10. package/build/cli/stdio-proxy.js +304 -0
  11. package/build/cli/stdio-proxy.js.map +1 -0
  12. package/build/config/index.js +5 -0
  13. package/build/config/index.js.map +1 -0
  14. package/build/config/server.js +16 -0
  15. package/build/config/server.js.map +1 -0
  16. package/build/core/mcp-http-server.js +14 -0
  17. package/build/core/mcp-http-server.js.map +1 -0
  18. package/build/core/mcp-server.js +95 -0
  19. package/build/core/mcp-server.js.map +1 -0
  20. package/build/index.js +98 -0
  21. package/build/index.js.map +1 -0
  22. package/build/models/admin-types.js +135 -0
  23. package/build/models/admin-types.js.map +1 -0
  24. package/build/models/types.js +2 -0
  25. package/build/models/types.js.map +1 -0
  26. package/build/server/index.js +128 -0
  27. package/build/server/index.js.map +1 -0
  28. package/build/server/routes/admin.js +929 -0
  29. package/build/server/routes/admin.js.map +1 -0
  30. package/build/server/routes/audit.js +9 -0
  31. package/build/server/routes/audit.js.map +1 -0
  32. package/build/server/routes/backups.js +11 -0
  33. package/build/server/routes/backups.js.map +1 -0
  34. package/build/server/routes/mcp.js +52 -0
  35. package/build/server/routes/mcp.js.map +1 -0
  36. package/build/server/routes/settings.js +49 -0
  37. package/build/server/routes/settings.js.map +1 -0
  38. package/build/server/routes/system.js +147 -0
  39. package/build/server/routes/system.js.map +1 -0
  40. package/build/services/audit-store.js +123 -0
  41. package/build/services/audit-store.js.map +1 -0
  42. package/build/services/autostart-service.js +55 -0
  43. package/build/services/autostart-service.js.map +1 -0
  44. package/build/services/backup-scheduler.js +90 -0
  45. package/build/services/backup-scheduler.js.map +1 -0
  46. package/build/services/backup-service.js +113 -0
  47. package/build/services/backup-service.js.map +1 -0
  48. package/build/services/config-store.js +163 -0
  49. package/build/services/config-store.js.map +1 -0
  50. package/build/services/defaults.js +35 -0
  51. package/build/services/defaults.js.map +1 -0
  52. package/build/services/restart-helper.js +43 -0
  53. package/build/services/restart-helper.js.map +1 -0
  54. package/build/services/ssh-connection-manager.js +1775 -0
  55. package/build/services/ssh-connection-manager.js.map +1 -0
  56. package/build/services/update-service.js +93 -0
  57. package/build/services/update-service.js.map +1 -0
  58. package/build/tools/download.js +41 -0
  59. package/build/tools/download.js.map +1 -0
  60. package/build/tools/execute-command.js +53 -0
  61. package/build/tools/execute-command.js.map +1 -0
  62. package/build/tools/index.js +17 -0
  63. package/build/tools/index.js.map +1 -0
  64. package/build/tools/list-directory.js +57 -0
  65. package/build/tools/list-directory.js.map +1 -0
  66. package/build/tools/list-servers.js +51 -0
  67. package/build/tools/list-servers.js.map +1 -0
  68. package/build/tools/upload.js +41 -0
  69. package/build/tools/upload.js.map +1 -0
  70. package/build/utils/logger.js +28 -0
  71. package/build/utils/logger.js.map +1 -0
  72. package/build/utils/ssh-config-parser.js +195 -0
  73. package/build/utils/ssh-config-parser.js.map +1 -0
  74. package/build/utils/status-collector.js +226 -0
  75. package/build/utils/status-collector.js.map +1 -0
  76. package/build/utils/tool-error.js +20 -0
  77. package/build/utils/tool-error.js.map +1 -0
  78. package/package.json +69 -0
@@ -0,0 +1,195 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ /**
5
+ * 查找 SSH 配置文件中指定主机别名的配置
6
+ * @param hostAlias 主机别名
7
+ * @param configFilePath 配置文件路径,默认为 ~/.ssh/config
8
+ * @returns 解析后的配置项,未找到返回 null
9
+ */
10
+ export function lookupSshConfig(hostAlias, configFilePath) {
11
+ const configPath = configFilePath || path.join(os.homedir(), '.ssh', 'config');
12
+ // 默认路径不存在时静默返回 null
13
+ if (!configFilePath && !fs.existsSync(configPath)) {
14
+ return null;
15
+ }
16
+ // 显式指定路径不存在时抛错
17
+ if (configFilePath && !fs.existsSync(configPath)) {
18
+ throw new Error(`SSH config file not found: ${configPath}`);
19
+ }
20
+ const blocks = parseConfigFile(configPath, new Set());
21
+ return matchHost(hostAlias, blocks);
22
+ }
23
+ /**
24
+ * 解析 SSH 配置文件
25
+ */
26
+ function parseConfigFile(filePath, visited) {
27
+ // 防止循环引用
28
+ const realPath = fs.realpathSync(filePath);
29
+ if (visited.has(realPath)) {
30
+ return [];
31
+ }
32
+ visited.add(realPath);
33
+ const content = fs.readFileSync(filePath, 'utf-8');
34
+ const lines = content.split('\n');
35
+ const blocks = [];
36
+ let currentBlock = null;
37
+ for (let line of lines) {
38
+ // 移除注释和前后空白
39
+ const commentIndex = line.indexOf('#');
40
+ if (commentIndex !== -1) {
41
+ line = line.substring(0, commentIndex);
42
+ }
43
+ line = line.trim();
44
+ if (!line)
45
+ continue;
46
+ // 解析 Include 指令
47
+ if (line.toLowerCase().startsWith('include ')) {
48
+ if (currentBlock) {
49
+ blocks.push(currentBlock);
50
+ currentBlock = null;
51
+ }
52
+ const pattern = line.substring(8).trim();
53
+ const includePaths = expandIncludePath(pattern, path.dirname(filePath));
54
+ for (const includePath of includePaths) {
55
+ if (fs.existsSync(includePath)) {
56
+ blocks.push(...parseConfigFile(includePath, visited));
57
+ }
58
+ }
59
+ continue;
60
+ }
61
+ // 解析 Host 行
62
+ if (line.toLowerCase().startsWith('host ')) {
63
+ if (currentBlock) {
64
+ blocks.push(currentBlock);
65
+ }
66
+ const hostPatterns = line.substring(5).trim().split(/\s+/);
67
+ currentBlock = {
68
+ patterns: hostPatterns,
69
+ config: new Map()
70
+ };
71
+ continue;
72
+ }
73
+ // 解析配置项
74
+ if (!currentBlock) {
75
+ currentBlock = {
76
+ patterns: ['*'],
77
+ config: new Map()
78
+ };
79
+ }
80
+ const spaceIndex = line.search(/\s/);
81
+ if (spaceIndex !== -1) {
82
+ const key = line.substring(0, spaceIndex).toLowerCase();
83
+ const value = line.substring(spaceIndex + 1).trim();
84
+ // 只保存第一次出现的值(SSH first-match-wins)
85
+ if (!currentBlock.config.has(key)) {
86
+ currentBlock.config.set(key, value);
87
+ }
88
+ }
89
+ }
90
+ if (currentBlock) {
91
+ blocks.push(currentBlock);
92
+ }
93
+ return blocks;
94
+ }
95
+ /**
96
+ * 展开 Include 路径(支持 ~ 和通配符)
97
+ */
98
+ function expandIncludePath(pattern, baseDir) {
99
+ // 展开 ~
100
+ if (pattern.startsWith('~/')) {
101
+ pattern = path.join(os.homedir(), pattern.substring(2));
102
+ }
103
+ else if (pattern.startsWith('~')) {
104
+ // ~user 形式不支持,直接返回空
105
+ return [];
106
+ }
107
+ else if (!path.isAbsolute(pattern)) {
108
+ // 相对路径相对于配置文件所在目录
109
+ pattern = path.join(baseDir, pattern);
110
+ }
111
+ // 使用 glob 展开通配符
112
+ try {
113
+ // Node.js 22+ 支持 fs.globSync
114
+ if (typeof fs.globSync === 'function') {
115
+ return fs.globSync(pattern);
116
+ }
117
+ }
118
+ catch (e) {
119
+ // glob 失败时静默跳过
120
+ }
121
+ // 降级:无通配符时直接返回
122
+ if (!pattern.includes('*') && !pattern.includes('?')) {
123
+ return [pattern];
124
+ }
125
+ return [];
126
+ }
127
+ /**
128
+ * 匹配主机别名
129
+ */
130
+ function matchHost(hostAlias, blocks) {
131
+ const result = {};
132
+ for (const block of blocks) {
133
+ const matched = hostBlockMatches(hostAlias, block.patterns);
134
+ if (!matched)
135
+ continue;
136
+ // first-match-wins:只取第一个匹配到的值
137
+ if (!result.hostName && block.config.has('hostname')) {
138
+ result.hostName = block.config.get('hostname');
139
+ }
140
+ if (!result.user && block.config.has('user')) {
141
+ result.user = block.config.get('user');
142
+ }
143
+ if (!result.port && block.config.has('port')) {
144
+ const portStr = block.config.get('port');
145
+ const portNum = parseInt(portStr, 10);
146
+ if (!isNaN(portNum)) {
147
+ result.port = portNum;
148
+ }
149
+ }
150
+ if (!result.identityFile && block.config.has('identityfile')) {
151
+ result.identityFile = expandTilde(block.config.get('identityfile'));
152
+ }
153
+ }
154
+ return Object.keys(result).length > 0 ? result : null;
155
+ }
156
+ function hostBlockMatches(hostAlias, patterns) {
157
+ let positiveMatch = false;
158
+ for (const pattern of patterns) {
159
+ const isNegated = pattern.startsWith('!');
160
+ const patternBody = isNegated ? pattern.slice(1) : pattern;
161
+ if (!patternBody) {
162
+ continue;
163
+ }
164
+ if (hostPatternMatches(hostAlias, patternBody)) {
165
+ if (isNegated) {
166
+ return false;
167
+ }
168
+ positiveMatch = true;
169
+ }
170
+ }
171
+ return positiveMatch;
172
+ }
173
+ function hostPatternMatches(hostAlias, pattern) {
174
+ if (pattern === '*') {
175
+ return true;
176
+ }
177
+ const regexSource = pattern
178
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
179
+ .replace(/\*/g, '.*')
180
+ .replace(/\?/g, '.');
181
+ return new RegExp(`^${regexSource}$`).test(hostAlias);
182
+ }
183
+ /**
184
+ * 展开路径中的 ~
185
+ */
186
+ function expandTilde(filePath) {
187
+ if (filePath.startsWith('~/')) {
188
+ return path.join(os.homedir(), filePath.substring(2));
189
+ }
190
+ if (filePath === '~') {
191
+ return os.homedir();
192
+ }
193
+ return filePath;
194
+ }
195
+ //# sourceMappingURL=ssh-config-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-config-parser.js","sourceRoot":"","sources":["../../src/utils/ssh-config-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAczB;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,cAAuB;IAEvB,MAAM,UAAU,GAAG,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAE/E,oBAAoB;IACpB,IAAI,CAAC,cAAc,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,eAAe;IACf,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IACtD,OAAO,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,OAAoB;IAC7D,SAAS;IACT,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEtB,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,IAAI,YAAY,GAAqB,IAAI,CAAC;IAE1C,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,YAAY;QACZ,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAEnB,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,gBAAgB;QAChB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC1B,YAAY,GAAG,IAAI,CAAC;YACtB,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACzC,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxE,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;gBACvC,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QAED,YAAY;QACZ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5B,CAAC;YACD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC3D,YAAY,GAAG;gBACb,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,IAAI,GAAG,EAAE;aAClB,CAAC;YACF,SAAS;QACX,CAAC;QAED,QAAQ;QACR,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,YAAY,GAAG;gBACb,QAAQ,EAAE,CAAC,GAAG,CAAC;gBACf,MAAM,EAAE,IAAI,GAAG,EAAE;aAClB,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;YACxD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEpD,mCAAmC;YACnC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAE,OAAe;IACzD,OAAO;IACP,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;SAAM,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,oBAAoB;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,kBAAkB;QAClB,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,gBAAgB;IAChB,IAAI,CAAC;QACH,6BAA6B;QAC7B,IAAI,OAAO,EAAE,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACtC,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,eAAe;IACjB,CAAC;IAED,eAAe;IACf,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,SAAiB,EAAE,MAAmB;IACvD,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE5D,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,8BAA8B;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAQ,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB,EAAE,QAAkB;IAC7D,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QAED,IAAI,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;YAC/C,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,KAAK,CAAC;YACf,CAAC;YACD,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAiB,EAAE,OAAe;IAC5D,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,OAAO;SACxB,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;SACpC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEvB,OAAO,IAAI,MAAM,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,226 @@
1
+ import { Logger } from "./logger.js";
2
+ /**
3
+ * Join the probes into a single remote command, each result introduced by a
4
+ * marker line.
5
+ *
6
+ * Running them separately costs one SSH channel per probe — open, pty request,
7
+ * exec and close, several round trips each — plus a remote shell per probe. In
8
+ * shell transport it is worse still: the per-connection queue serialises them,
9
+ * so the first command the user issues after connecting waits behind all of
10
+ * them.
11
+ *
12
+ * Every probe is wrapped so that a missing tool or a non-zero exit cannot
13
+ * abort the rest, and the whole script ends successfully.
14
+ */
15
+ function buildStatusScript(commands, marker) {
16
+ const probes = Object.entries(commands).map(([field, command]) => `printf '\\n${marker}${field}\\n'; { ${command}; } 2>/dev/null`);
17
+ return `${probes.join("; ")}; true`;
18
+ }
19
+ function parseStatusScriptOutput(output, marker) {
20
+ const values = new Map();
21
+ const normalized = output.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
22
+ // Splitting on a capturing group yields [before, field, value, field, ...].
23
+ const segments = normalized.split(new RegExp(`\\n?${marker}(\\w+)\\n`));
24
+ for (let index = 1; index < segments.length; index += 2) {
25
+ values.set(segments[index], (segments[index + 1] ?? "").trim());
26
+ }
27
+ return values;
28
+ }
29
+ /**
30
+ * Collect system status information from remote server
31
+ */
32
+ export async function collectSystemStatus(runCommand, connectionName, isCommandAllowed = () => true) {
33
+ const status = {
34
+ reachable: true,
35
+ lastUpdated: new Date().toISOString(),
36
+ };
37
+ try {
38
+ // Collected in a single remote command; see buildStatusScript.
39
+ const commands = {
40
+ hostname: "hostname",
41
+ ipAddresses: "ip -o addr show | awk '{print $4}' | grep -v '^127\\.' | cut -d'/' -f1",
42
+ osName: "uname -s",
43
+ osVersion: "cat /etc/os-release 2>/dev/null | grep '^PRETTY_NAME=' | cut -d'=' -f2 | tr -d '\"' || uname -o",
44
+ kernelVersion: "uname -r",
45
+ uptime: "uptime -p 2>/dev/null || uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}'",
46
+ diskSpace: "df -h / | tail -1 | awk '{print \"free:\" $4 \" total:\" $2}'",
47
+ memory: "free -h | grep '^Mem:' | awk '{print \"free:\" $7 \" total:\" $2}'",
48
+ cpuName: "sh -c '(lscpu 2>/dev/null | grep \"^Model name:\" | cut -d\":\" -f2 | xargs || cat /proc/cpuinfo 2>/dev/null | grep \"model name\" | head -1 | cut -d\":\" -f2 | xargs || echo \"$(nproc 2>/dev/null || echo '\''?'\'')-core $(uname -m 2>/dev/null || echo '\''unknown'\'') processor\") || true'",
49
+ cpuUsage: "top -bn1 | grep 'Cpu(s)' | sed 's/.*, *\\([0-9.]*\\)%* id.*/\\1/' | awk '{print 100 - $1}'",
50
+ gpus: "sh -c '(nvidia-smi --query-gpu=name,utilization.gpu --format=csv,noheader,nounits 2>/dev/null | while IFS=\",\" read -r name usage; do echo \"NVIDIA|${name}|${usage}\"; done || lspci | grep -iE \"vga|3d|display\" | while read -r line; do gpu_name=$(echo \"$line\" | cut -d\":\" -f3 | xargs); echo \"OTHER|${gpu_name}|\"; done) || true'",
51
+ gpuPaths: "ls -1 /dev/dri/card* 2>/dev/null | sort -V || echo ''",
52
+ drives: "df -h | awk 'NR>1 && $1 !~ /^(tmpfs|devtmpfs|overlay|shfs|rootfs)$/ && $6 !~ /^(\\/dev|\\/run|\\/sys|\\/proc|\\/boot|\\/usr|\\/lib)$/ && $6 != \"\" {print $1\"|\"$2\"|\"$3\"|\"$4\"|\"$5\"|\"$6}'",
53
+ // Old gpuPaths: "sh -c '(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits 2>/dev/null | head -1 || rocm-smi --showuse 2>/dev/null | grep -i \"GPU use\" | head -1 | awk \"{print \\$NF}\" | tr -d \"%\" || radeontop -l 1 -d - 2>/dev/null | tail -1 | sed -n \"s/.*gpu \\([0-9.]*\\)%.*/\\1/p\" || intel_gpu_top -l 1 -o - 2>/dev/null | tail -1 | awk \"{print \\$NF}\" | tr -d \"%\" || echo \"N/A\") || echo \"N/A\"'",
54
+ processes: "ps aux | wc -l",
55
+ threads: "ps -eLf | wc -l",
56
+ servicesRunning: "systemctl list-units --type=service --state=running 2>/dev/null | wc -l || service --status-all 2>/dev/null | grep running | wc -l || echo '0'",
57
+ servicesInstalled: "systemctl list-unit-files --type=service 2>/dev/null | wc -l || ls /etc/init.d/ 2>/dev/null | wc -l || echo '0'",
58
+ };
59
+ // Validate each probe before batching. Validating only the combined script
60
+ // would allow one whitelist match to authorize every command in it.
61
+ const allowedCommands = Object.fromEntries(Object.entries(commands).filter(([, command]) => isCommandAllowed(command, connectionName)));
62
+ // Execute the allowed probes and collect results.
63
+ const marker = `__MCP_FIELD_${Math.random().toString(16).slice(2, 10)}_`;
64
+ let values = new Map();
65
+ try {
66
+ if (Object.keys(allowedCommands).length === 0) {
67
+ return status;
68
+ }
69
+ values = parseStatusScriptOutput(await runCommand(buildStatusScript(allowedCommands, marker), connectionName), marker);
70
+ }
71
+ catch {
72
+ // A rejected command (an unreachable host, a command whitelist that does
73
+ // not admit the probe) leaves every field unset, the same as when the
74
+ // probes ran separately and each failed on its own.
75
+ }
76
+ // Parse results
77
+ const readField = (field) => values.get(field) ?? "";
78
+ const hostnameValue = readField("hostname");
79
+ const ipAddressesValue = readField("ipAddresses");
80
+ const osNameValue = readField("osName");
81
+ const osVersionValue = readField("osVersion");
82
+ const kernelVersionValue = readField("kernelVersion");
83
+ const uptimeValue = readField("uptime");
84
+ const diskSpaceValue = readField("diskSpace");
85
+ const memoryValue = readField("memory");
86
+ const cpuNameValue = readField("cpuName");
87
+ const cpuUsageValue = readField("cpuUsage");
88
+ const gpusValue = readField("gpus");
89
+ const gpuPathsValue = readField("gpuPaths");
90
+ const drivesValue = readField("drives");
91
+ const processesValue = readField("processes");
92
+ const threadsValue = readField("threads");
93
+ const servicesRunningValue = readField("servicesRunning");
94
+ const servicesInstalledValue = readField("servicesInstalled");
95
+ if (hostnameValue) {
96
+ status.hostname = hostnameValue;
97
+ }
98
+ if (ipAddressesValue) {
99
+ status.ipAddresses = ipAddressesValue
100
+ .split("\n")
101
+ .filter((ip) => ip.trim() && !ip.includes("127.0.0.1"));
102
+ }
103
+ if (osNameValue) {
104
+ status.osName = osNameValue;
105
+ }
106
+ if (osVersionValue) {
107
+ status.osVersion = osVersionValue;
108
+ }
109
+ if (kernelVersionValue) {
110
+ status.kernelVersion = kernelVersionValue;
111
+ }
112
+ if (uptimeValue) {
113
+ status.uptime = uptimeValue;
114
+ }
115
+ if (diskSpaceValue) {
116
+ const diskMatch = diskSpaceValue.match(/free:(\S+)\s+total:(\S+)/);
117
+ if (diskMatch) {
118
+ status.diskSpace = {
119
+ free: diskMatch[1],
120
+ total: diskMatch[2],
121
+ };
122
+ }
123
+ }
124
+ if (memoryValue) {
125
+ const memMatch = memoryValue.match(/free:(\S+)\s+total:(\S+)/);
126
+ if (memMatch) {
127
+ status.memory = {
128
+ free: memMatch[1],
129
+ total: memMatch[2],
130
+ };
131
+ }
132
+ }
133
+ // Handle CPU name
134
+ if (cpuNameValue && cpuNameValue.trim()) {
135
+ status.cpu = {
136
+ name: cpuNameValue.trim(),
137
+ };
138
+ }
139
+ if (status.cpu && cpuUsageValue && cpuUsageValue !== "N/A") {
140
+ status.cpu.usage = `${parseFloat(cpuUsageValue).toFixed(1)}%`;
141
+ }
142
+ // Handle GPUs
143
+ if (gpusValue && gpusValue.trim()) {
144
+ const gpuPaths = [];
145
+ if (gpuPathsValue) {
146
+ gpuPaths.push(...gpuPathsValue.split("\n").filter((p) => p.trim()));
147
+ }
148
+ const gpuLines = gpusValue.split("\n").filter((line) => line.trim());
149
+ const gpus = [];
150
+ gpuLines.forEach((line, index) => {
151
+ const parts = line.split("|");
152
+ if (parts.length >= 2) {
153
+ const name = parts[1].trim();
154
+ const usage = parts[2]?.trim();
155
+ if (name && name !== "N/A") {
156
+ const gpu = {
157
+ name: name,
158
+ };
159
+ if (usage && usage.trim() !== "" && usage.trim() !== "N/A" && !isNaN(parseFloat(usage.trim()))) {
160
+ gpu.usage = `${parseFloat(usage.trim()).toFixed(1)}%`;
161
+ }
162
+ // Assign path if available
163
+ if (gpuPaths[index]) {
164
+ gpu.path = gpuPaths[index];
165
+ }
166
+ gpus.push(gpu);
167
+ }
168
+ }
169
+ });
170
+ if (gpus.length > 0) {
171
+ status.gpus = gpus;
172
+ }
173
+ }
174
+ // Handle drives
175
+ if (drivesValue && drivesValue.trim()) {
176
+ const driveLines = drivesValue.split("\n").filter((line) => line.trim());
177
+ const drives = [];
178
+ driveLines.forEach((line) => {
179
+ const parts = line.split("|");
180
+ if (parts.length >= 6) {
181
+ const device = parts[0].trim();
182
+ const total = parts[1].trim();
183
+ const used = parts[2].trim();
184
+ const free = parts[3].trim();
185
+ const usagePercent = parts[4].trim();
186
+ const mountPoint = parts[5].trim();
187
+ if (device && mountPoint) {
188
+ drives.push({
189
+ device,
190
+ mountPoint,
191
+ total,
192
+ used,
193
+ free,
194
+ usagePercent,
195
+ });
196
+ }
197
+ }
198
+ });
199
+ if (drives.length > 0) {
200
+ status.drives = drives;
201
+ }
202
+ }
203
+ if (processesValue || threadsValue) {
204
+ const processCount = parseInt(processesValue || "0", 10) - 1; // Subtract header line
205
+ const threadCount = parseInt(threadsValue || "0", 10) - 1; // Subtract header line
206
+ status.processes = {
207
+ running: Math.max(0, processCount),
208
+ threads: Math.max(0, threadCount),
209
+ };
210
+ }
211
+ if (servicesRunningValue || servicesInstalledValue) {
212
+ const runningCount = parseInt(servicesRunningValue || "0", 10) - 1; // Subtract header line
213
+ const installedCount = parseInt(servicesInstalledValue || "0", 10) - 1; // Subtract header line
214
+ status.services = {
215
+ running: Math.max(0, runningCount),
216
+ installed: Math.max(0, installedCount),
217
+ };
218
+ }
219
+ }
220
+ catch (error) {
221
+ Logger.log(`Failed to collect system status for [${connectionName}]: ${error.message}`, "error");
222
+ status.reachable = false;
223
+ }
224
+ return status;
225
+ }
226
+ //# sourceMappingURL=status-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-collector.js","sourceRoot":"","sources":["../../src/utils/status-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export class ToolError extends Error {
2
+ code;
3
+ retriable;
4
+ constructor(code, message, retriable = false) {
5
+ super(message);
6
+ this.code = code;
7
+ this.retriable = retriable;
8
+ this.name = "ToolError";
9
+ }
10
+ }
11
+ export function toToolError(error, fallbackCode) {
12
+ if (error instanceof ToolError) {
13
+ return error;
14
+ }
15
+ if (error instanceof Error) {
16
+ return new ToolError(fallbackCode, error.message, false);
17
+ }
18
+ return new ToolError(fallbackCode, String(error), false);
19
+ }
20
+ //# sourceMappingURL=tool-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-error.js","sourceRoot":"","sources":["../../src/utils/tool-error.ts"],"names":[],"mappings":"AAqBA,MAAM,OAAO,SAAU,SAAQ,KAAK;IAEhB;IAEA;IAHlB,YACkB,IAAmB,EACnC,OAAe,EACC,YAAqB,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAe;QAEnB,cAAS,GAAT,SAAS,CAAiB;QAG1C,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,WAAW,CACzB,KAAc,EACd,YAA2B;IAE3B,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,IAAI,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAC3D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@lzm04521/ssh-mcp-server",
3
+ "version": "1.1.5",
4
+ "description": "SSH-based MCP Server (基于 SSH 的 MCP 服务器)",
5
+ "main": "build/index.js",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=18.0.0"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/lzm04521/ssh-mcp-server.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/lzm04521/ssh-mcp-server/issues"
16
+ },
17
+ "homepage": "https://github.com/lzm04521/ssh-mcp-server#readme",
18
+ "bin": {
19
+ "ssh-mcp-server": "build/index.js"
20
+ },
21
+ "scripts": {
22
+ "test": "node scripts/run-tests.js",
23
+ "test:watch": "node --test --watch test/**/*.test.js",
24
+ "build": "node scripts/build.js",
25
+ "build:watch": "tsc --watch",
26
+ "build:admin": "npm --prefix admin-web run build",
27
+ "dev:watch": "concurrently --shell bash \"npm:build:watch\" \"npm:dev:frontend\"",
28
+ "dev:backend": "npm run build:watch",
29
+ "dev:frontend": "npm --prefix admin-web run dev",
30
+ "dev:admin": "node build/index.js --admin --admin-port 61823",
31
+ "dev:admin:watch": "concurrently --shell bash \"npm:build:watch\" \"npx nodemon --watch build --delay 500 build/index.js --admin --admin-port 61823\"",
32
+ "prepublishOnly": "npm run build",
33
+ "prepack": "node scripts/prepack.js",
34
+ "version:bump": "node scripts/bump-version.mjs"
35
+ },
36
+ "keywords": [
37
+ "ssh",
38
+ "mcp",
39
+ "server",
40
+ "cli"
41
+ ],
42
+ "author": "lzm04521",
43
+ "license": "ISC",
44
+ "dependencies": {
45
+ "@fastify/static": "^10.1.3",
46
+ "@modelcontextprotocol/sdk": "^1.27.0",
47
+ "better-sqlite3": "^13.0.3",
48
+ "chokidar": "^5.0.0",
49
+ "fastify": "^5.12.1",
50
+ "socks": "^2.8.7",
51
+ "ssh2": "^1.17.0",
52
+ "zod": "^4.3.6"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^22.13.10",
56
+ "@types/ssh2": "^1.15.5",
57
+ "c8": "^12.0.0",
58
+ "concurrently": "^10.0.5",
59
+ "cross-env": "^10.1.0",
60
+ "nodemon": "^3.1.14",
61
+ "typescript": "^5.8.2"
62
+ },
63
+ "files": [
64
+ "build/**/*",
65
+ "admin-web/dist/**/*",
66
+ "README.md",
67
+ "LICENSE"
68
+ ]
69
+ }