@mcpcn/mcp-computer-env 1.0.1 → 1.0.4

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/dist/index.d.ts CHANGED
File without changes
package/dist/index.js CHANGED
@@ -29,7 +29,9 @@ function getSystemInfo() {
29
29
  if (match)
30
30
  distro = match[1];
31
31
  }
32
- catch { }
32
+ catch (error) {
33
+ // 忽略文件读取错误,distro 保持为空字符串
34
+ }
33
35
  }
34
36
  return {
35
37
  platform,
@@ -89,18 +91,23 @@ function getCommonDirs() {
89
91
  dirs.pictures = path.join(home, '图片');
90
92
  dirs.videos = path.join(home, '视频');
91
93
  // 兼容英文目录
92
- if (!fs.existsSync(dirs.desktop))
93
- dirs.desktop = path.join(home, 'Desktop');
94
- if (!fs.existsSync(dirs.documents))
95
- dirs.documents = path.join(home, 'Documents');
96
- if (!fs.existsSync(dirs.downloads))
97
- dirs.downloads = path.join(home, 'Downloads');
98
- if (!fs.existsSync(dirs.music))
99
- dirs.music = path.join(home, 'Music');
100
- if (!fs.existsSync(dirs.pictures))
101
- dirs.pictures = path.join(home, 'Pictures');
102
- if (!fs.existsSync(dirs.videos))
103
- dirs.videos = path.join(home, 'Videos');
94
+ try {
95
+ if (!fs.existsSync(dirs.desktop))
96
+ dirs.desktop = path.join(home, 'Desktop');
97
+ if (!fs.existsSync(dirs.documents))
98
+ dirs.documents = path.join(home, 'Documents');
99
+ if (!fs.existsSync(dirs.downloads))
100
+ dirs.downloads = path.join(home, 'Downloads');
101
+ if (!fs.existsSync(dirs.music))
102
+ dirs.music = path.join(home, 'Music');
103
+ if (!fs.existsSync(dirs.pictures))
104
+ dirs.pictures = path.join(home, 'Pictures');
105
+ if (!fs.existsSync(dirs.videos))
106
+ dirs.videos = path.join(home, 'Videos');
107
+ }
108
+ catch (error) {
109
+ // 忽略文件系统检查错误,使用默认值
110
+ }
104
111
  dirs.appData = process.env.XDG_CONFIG_HOME || path.join(home, '.config');
105
112
  }
106
113
  return dirs;
@@ -115,48 +122,102 @@ function getMemoryInfo() {
115
122
  function getNetworkInfo() {
116
123
  return os.networkInterfaces();
117
124
  }
125
+ function normalizeWindowsDiskRow(mountPoint, fileSystem, sizeValue, freeValue) {
126
+ const drive = mountPoint.trim();
127
+ const total = Number.parseInt(sizeValue, 10) || 0;
128
+ const available = Number.parseInt(freeValue, 10) || 0;
129
+ return {
130
+ filesystem: drive,
131
+ mount: drive ? `${drive}\\` : '',
132
+ type: fileSystem.trim(),
133
+ total,
134
+ used: Math.max(total - available, 0),
135
+ available,
136
+ };
137
+ }
138
+ async function getDiskInfoWindowsByWmic() {
139
+ const { stdout } = await execAsync('wmic logicaldisk get Caption,FileSystem,Size,FreeSpace /format:csv');
140
+ const lines = stdout
141
+ .split(/\r?\n/)
142
+ .map((line) => line.trim())
143
+ .filter(Boolean);
144
+ if (lines.length < 2) {
145
+ throw new Error('wmic returned empty output');
146
+ }
147
+ const header = lines[0].replace(/^\uFEFF/, '').split(',').map((item) => item.trim());
148
+ const colIndex = {
149
+ caption: header.indexOf('Caption'),
150
+ fileSystem: header.indexOf('FileSystem'),
151
+ size: header.indexOf('Size'),
152
+ freeSpace: header.indexOf('FreeSpace'),
153
+ };
154
+ if (colIndex.caption < 0 || colIndex.fileSystem < 0 || colIndex.size < 0 || colIndex.freeSpace < 0) {
155
+ throw new Error('wmic returned unexpected columns');
156
+ }
157
+ return lines
158
+ .slice(1)
159
+ .map((line) => line.split(','))
160
+ .map((parts) => normalizeWindowsDiskRow(parts[colIndex.caption] || '', parts[colIndex.fileSystem] || '', parts[colIndex.size] || '', parts[colIndex.freeSpace] || ''))
161
+ .filter((item) => item.filesystem);
162
+ }
163
+ async function getDiskInfoWindowsByPowerShell() {
164
+ const command = 'powershell -NoProfile -Command "Get-CimInstance Win32_LogicalDisk | Select-Object DeviceID,FileSystem,Size,FreeSpace | ConvertTo-Json -Compress"';
165
+ const { stdout } = await execAsync(command);
166
+ const raw = stdout.trim();
167
+ if (!raw) {
168
+ throw new Error('PowerShell returned empty output');
169
+ }
170
+ const parsed = JSON.parse(raw);
171
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
172
+ return rows
173
+ .filter((row) => Boolean(row) && typeof row === 'object')
174
+ .map((row) => normalizeWindowsDiskRow(String((row.DeviceID ?? row.Caption ?? '')), String((row.FileSystem ?? '')), String((row.Size ?? '0')), String((row.FreeSpace ?? '0'))))
175
+ .filter((item) => item.filesystem);
176
+ }
118
177
  // 获取磁盘分区信息(跨平台)
119
178
  async function getDiskInfo() {
120
- const platform = os.platform();
121
- if (platform === 'win32') {
122
- // Windows: 使用wmic
123
- const { stdout } = await execAsync('wmic logicaldisk get Caption,FileSystem,Size,FreeSpace');
124
- const lines = stdout.trim().split(/\r?\n/).filter(Boolean);
125
- const header = lines.shift();
126
- return lines.map(line => {
127
- const parts = line.trim().split(/\s+/);
128
- const [Caption, FileSystem, Size, FreeSpace] = parts;
129
- const total = parseInt(Size, 10) || 0;
130
- const free = parseInt(FreeSpace, 10) || 0;
131
- return {
132
- filesystem: Caption,
133
- mount: Caption + '\\',
134
- type: FileSystem,
135
- total,
136
- used: total - free,
137
- available: free
138
- };
139
- });
179
+ try {
180
+ const platform = os.platform();
181
+ if (platform === 'win32') {
182
+ // Windows: 先尝试 wmic,失败后回退到 PowerShell
183
+ try {
184
+ return await getDiskInfoWindowsByWmic();
185
+ }
186
+ catch (wmicError) {
187
+ try {
188
+ return await getDiskInfoWindowsByPowerShell();
189
+ }
190
+ catch (powerShellError) {
191
+ const wmicMessage = wmicError instanceof Error ? wmicError.message : String(wmicError);
192
+ const powerShellMessage = powerShellError instanceof Error ? powerShellError.message : String(powerShellError);
193
+ throw new Error(`wmic failed: ${wmicMessage}; PowerShell failed: ${powerShellMessage}`);
194
+ }
195
+ }
196
+ }
197
+ else {
198
+ // macOS/Linux: 使用df -kP
199
+ const { stdout } = await execAsync('df -kP');
200
+ const lines = stdout.trim().split(/\n/).filter(Boolean);
201
+ lines.shift(); // 去掉表头
202
+ return lines.map(line => {
203
+ const parts = line.replace(/\s+/g, ' ').split(' ');
204
+ // Filesystem 1024-blocks Used Available Capacity Mounted on
205
+ const [filesystem, blocks, used, available, capacity, ...mountArr] = parts;
206
+ const mount = mountArr.join(' ');
207
+ return {
208
+ filesystem,
209
+ mount,
210
+ type: '', // 跨平台简化,详细类型可用mount命令补充
211
+ total: parseInt(blocks, 10) * 1024,
212
+ used: parseInt(used, 10) * 1024,
213
+ available: parseInt(available, 10) * 1024
214
+ };
215
+ });
216
+ }
140
217
  }
141
- else {
142
- // macOS/Linux: 使用df -kP
143
- const { stdout } = await execAsync('df -kP');
144
- const lines = stdout.trim().split(/\n/).filter(Boolean);
145
- lines.shift(); // 去掉表头
146
- return lines.map(line => {
147
- const parts = line.replace(/\s+/g, ' ').split(' ');
148
- // Filesystem 1024-blocks Used Available Capacity Mounted on
149
- const [filesystem, blocks, used, available, capacity, ...mountArr] = parts;
150
- const mount = mountArr.join(' ');
151
- return {
152
- filesystem,
153
- mount,
154
- type: '', // 跨平台简化,详细类型可用mount命令补充
155
- total: parseInt(blocks, 10) * 1024,
156
- used: parseInt(used, 10) * 1024,
157
- available: parseInt(available, 10) * 1024
158
- };
159
- });
218
+ catch (error) {
219
+ const errorMessage = error instanceof Error ? error.message : String(error);
220
+ throw new McpError(ErrorCode.InternalError, `Failed to get disk info: ${errorMessage}`);
160
221
  }
161
222
  }
162
223
  class ComputerEnvServer {
@@ -207,31 +268,57 @@ class ComputerEnvServer {
207
268
  ],
208
269
  }));
209
270
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
271
+ const { name, arguments: args } = request.params;
210
272
  try {
211
- switch (request.params.name) {
273
+ switch (name) {
212
274
  case 'get_system_info':
213
- return { content: [{ type: 'text', text: JSON.stringify(getSystemInfo()) }] };
275
+ return {
276
+ content: [{ type: 'text', text: JSON.stringify(getSystemInfo()) }],
277
+ isError: false
278
+ };
214
279
  case 'get_common_dirs':
215
- return { content: [{ type: 'text', text: JSON.stringify(getCommonDirs()) }] };
280
+ return {
281
+ content: [{ type: 'text', text: JSON.stringify(getCommonDirs()) }],
282
+ isError: false
283
+ };
216
284
  case 'get_memory_info':
217
- return { content: [{ type: 'text', text: JSON.stringify(getMemoryInfo()) }] };
285
+ return {
286
+ content: [{ type: 'text', text: JSON.stringify(getMemoryInfo()) }],
287
+ isError: false
288
+ };
218
289
  case 'get_network_info':
219
- return { content: [{ type: 'text', text: JSON.stringify(getNetworkInfo()) }] };
290
+ return {
291
+ content: [{ type: 'text', text: JSON.stringify(getNetworkInfo()) }],
292
+ isError: false
293
+ };
220
294
  case 'get_disk_info':
221
- return { content: [{ type: 'text', text: JSON.stringify(await getDiskInfo()) }] };
295
+ return {
296
+ content: [{ type: 'text', text: JSON.stringify(await getDiskInfo()) }],
297
+ isError: false
298
+ };
222
299
  default:
223
- throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
300
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
224
301
  }
225
302
  }
226
303
  catch (error) {
227
- throw error;
304
+ if (error instanceof McpError) {
305
+ throw error;
306
+ }
307
+ const errorMessage = error instanceof Error ? error.message : String(error);
308
+ throw new McpError(ErrorCode.InternalError, `Error executing tool ${name}: ${errorMessage}`);
228
309
  }
229
310
  });
230
311
  }
231
312
  async run() {
232
- const transport = new StdioServerTransport();
233
- await this.server.connect(transport);
234
- console.error('Computer Env MCP server running on stdio');
313
+ try {
314
+ const transport = new StdioServerTransport();
315
+ await this.server.connect(transport);
316
+ console.error('Computer Env MCP server running on stdio');
317
+ }
318
+ catch (error) {
319
+ console.error('Failed to start server:', error);
320
+ process.exit(1);
321
+ }
235
322
  }
236
323
  }
237
324
  const server = new ComputerEnvServer();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@mcpcn/mcp-computer-env",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "获取用户电脑环境信息的MCP服务器",
5
- "packageManager": "pnpm@8.12.1",
5
+ "packageManager": "npm@10.9.0",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
@@ -26,7 +26,7 @@
26
26
  "start": "node dist/index.js",
27
27
  "dev": "tsc -w",
28
28
  "clean": "rm -rf build",
29
- "prepare": "pnpm clean && pnpm build"
29
+ "prepare": "npm run clean && npm run build"
30
30
  },
31
31
  "type": "module",
32
32
  "license": "MIT",