@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 +0 -0
- package/dist/index.js +150 -63
- package/package.json +3 -3
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
|
-
|
|
93
|
-
dirs.desktop
|
|
94
|
-
|
|
95
|
-
dirs.documents
|
|
96
|
-
|
|
97
|
-
dirs.downloads
|
|
98
|
-
|
|
99
|
-
dirs.music
|
|
100
|
-
|
|
101
|
-
dirs.pictures
|
|
102
|
-
|
|
103
|
-
dirs.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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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 (
|
|
273
|
+
switch (name) {
|
|
212
274
|
case 'get_system_info':
|
|
213
|
-
return {
|
|
275
|
+
return {
|
|
276
|
+
content: [{ type: 'text', text: JSON.stringify(getSystemInfo()) }],
|
|
277
|
+
isError: false
|
|
278
|
+
};
|
|
214
279
|
case 'get_common_dirs':
|
|
215
|
-
return {
|
|
280
|
+
return {
|
|
281
|
+
content: [{ type: 'text', text: JSON.stringify(getCommonDirs()) }],
|
|
282
|
+
isError: false
|
|
283
|
+
};
|
|
216
284
|
case 'get_memory_info':
|
|
217
|
-
return {
|
|
285
|
+
return {
|
|
286
|
+
content: [{ type: 'text', text: JSON.stringify(getMemoryInfo()) }],
|
|
287
|
+
isError: false
|
|
288
|
+
};
|
|
218
289
|
case 'get_network_info':
|
|
219
|
-
return {
|
|
290
|
+
return {
|
|
291
|
+
content: [{ type: 'text', text: JSON.stringify(getNetworkInfo()) }],
|
|
292
|
+
isError: false
|
|
293
|
+
};
|
|
220
294
|
case 'get_disk_info':
|
|
221
|
-
return {
|
|
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: ${
|
|
300
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
224
301
|
}
|
|
225
302
|
}
|
|
226
303
|
catch (error) {
|
|
227
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "获取用户电脑环境信息的MCP服务器",
|
|
5
|
-
"packageManager": "
|
|
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": "
|
|
29
|
+
"prepare": "npm run clean && npm run build"
|
|
30
30
|
},
|
|
31
31
|
"type": "module",
|
|
32
32
|
"license": "MIT",
|