computer_mcp 1.0.1 → 1.0.3
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/package.json +2 -2
- package/server.js +51 -27
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "computer_mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "MCP Streamable HTTP Server with file and command execution tools",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"computer-mcp": "
|
|
8
|
+
"computer-mcp": "server.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"server.js",
|
package/server.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
|
-
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
5
|
import express from "express";
|
|
7
6
|
import { randomUUID } from 'node:crypto';
|
|
8
7
|
import { registerBashTool } from './tools/bash.js';
|
|
@@ -10,27 +9,25 @@ import { registerFileTools } from './tools/file.js';
|
|
|
10
9
|
import { registerInteractiveBashTool } from './tools/interactive.js';
|
|
11
10
|
import { loadSkills, getSkillDetails } from './tools/skills.js';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
/** 每个 Streamable HTTP 会话需要独立的 McpServer(协议层与 transport 一对一) */
|
|
13
|
+
function createComputerMcpServer() {
|
|
14
|
+
const server = new McpServer(
|
|
15
|
+
{
|
|
16
|
+
name: 'computer-mcp-server',
|
|
17
|
+
version: '1.0.0'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
capabilities: {
|
|
21
|
+
logging: {},
|
|
22
|
+
tools: {}
|
|
23
|
+
}
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
);
|
|
25
|
+
);
|
|
26
|
+
registerInteractiveBashTool(server);
|
|
27
|
+
registerFileTools(server);
|
|
28
|
+
return server;
|
|
29
|
+
}
|
|
26
30
|
|
|
27
|
-
// 注册工具
|
|
28
|
-
registerInteractiveBashTool(server);
|
|
29
|
-
// registerBashTool(server);
|
|
30
|
-
registerFileTools(server);
|
|
31
|
-
|
|
32
|
-
// // 创建 Express 应用
|
|
33
|
-
// const app = createMcpExpressApp();
|
|
34
31
|
const app = express();
|
|
35
32
|
|
|
36
33
|
// 健康检查端点
|
|
@@ -109,26 +106,40 @@ app.get('/skills/:name', async (req, res) => {
|
|
|
109
106
|
}
|
|
110
107
|
});
|
|
111
108
|
|
|
112
|
-
//
|
|
113
|
-
const
|
|
109
|
+
// sessionId -> { transport, mcpServer }
|
|
110
|
+
const sessions = new Map();
|
|
114
111
|
|
|
115
112
|
// MCP 端点处理
|
|
116
113
|
app.all('/mcp', async (req, res) => {
|
|
117
114
|
try {
|
|
118
|
-
|
|
119
|
-
const sessionId =
|
|
120
|
-
|
|
115
|
+
const rawSessionId = req.headers['mcp-session-id'];
|
|
116
|
+
const sessionId = Array.isArray(rawSessionId)
|
|
117
|
+
? rawSessionId[rawSessionId.length - 1]
|
|
118
|
+
: rawSessionId;
|
|
119
|
+
|
|
120
|
+
let entry = sessionId ? sessions.get(sessionId) : undefined;
|
|
121
|
+
let transport = entry?.transport;
|
|
122
|
+
let mcpServer = entry?.mcpServer;
|
|
121
123
|
|
|
122
124
|
if (!transport) {
|
|
125
|
+
mcpServer = createComputerMcpServer();
|
|
123
126
|
transport = new StreamableHTTPServerTransport({
|
|
124
127
|
sessionIdGenerator: () => randomUUID(),
|
|
125
128
|
retryInterval: 2000, // 默认重试间隔用于 priming events
|
|
126
129
|
onsessioninitialized: id => {
|
|
127
130
|
console.log(`[${id}] Session initialized`);
|
|
128
|
-
|
|
131
|
+
sessions.set(id, { transport, mcpServer });
|
|
132
|
+
},
|
|
133
|
+
onsessionclosed: async id => {
|
|
134
|
+
sessions.delete(id);
|
|
135
|
+
try {
|
|
136
|
+
await mcpServer.close();
|
|
137
|
+
} catch (e) {
|
|
138
|
+
console.error('Error closing MCP server:', e);
|
|
139
|
+
}
|
|
129
140
|
}
|
|
130
141
|
});
|
|
131
|
-
await
|
|
142
|
+
await mcpServer.connect(transport);
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
await transport.handleRequest(req, res, req.body);
|
|
@@ -163,6 +174,19 @@ app.listen(PORT, error => {
|
|
|
163
174
|
// 处理服务器关闭
|
|
164
175
|
process.on('SIGINT', async () => {
|
|
165
176
|
console.log('Shutting down server...');
|
|
177
|
+
for (const [, { transport, mcpServer }] of sessions) {
|
|
178
|
+
try {
|
|
179
|
+
await mcpServer.close();
|
|
180
|
+
} catch (e) {
|
|
181
|
+
console.error(e);
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
await transport.close();
|
|
185
|
+
} catch (e) {
|
|
186
|
+
console.error(e);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
sessions.clear();
|
|
166
190
|
process.exit(0);
|
|
167
191
|
});
|
|
168
192
|
|