computer_mcp 1.0.2 → 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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/server.js +51 -24
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "computer_mcp",
3
- "version": "1.0.2",
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": "./server.js"
8
+ "computer-mcp": "server.js"
9
9
  },
10
10
  "files": [
11
11
  "server.js",
package/server.js CHANGED
@@ -9,24 +9,24 @@ import { registerFileTools } from './tools/file.js';
9
9
  import { registerInteractiveBashTool } from './tools/interactive.js';
10
10
  import { loadSkills, getSkillDetails } from './tools/skills.js';
11
11
 
12
- // 创建 MCP 服务器
13
- const server = new McpServer(
14
- {
15
- name: 'computer-mcp-server',
16
- version: '1.0.0'
17
- },
18
- {
19
- capabilities: {
20
- logging: {},
21
- tools: {}
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
+ }
22
24
  }
23
- }
24
- );
25
-
26
- // 注册工具
27
- registerInteractiveBashTool(server);
28
- // registerBashTool(server);
29
- registerFileTools(server);
25
+ );
26
+ registerInteractiveBashTool(server);
27
+ registerFileTools(server);
28
+ return server;
29
+ }
30
30
 
31
31
  const app = express();
32
32
 
@@ -106,26 +106,40 @@ app.get('/skills/:name', async (req, res) => {
106
106
  }
107
107
  });
108
108
 
109
- // 管理传输层的 Map
110
- const transports = new Map();
109
+ // sessionId -> { transport, mcpServer }
110
+ const sessions = new Map();
111
111
 
112
112
  // MCP 端点处理
113
113
  app.all('/mcp', async (req, res) => {
114
114
  try {
115
- // 重用现有传输层或创建新的
116
- const sessionId = req.headers['mcp-session-id'];
117
- let transport = sessionId ? transports.get(sessionId) : undefined;
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;
118
123
 
119
124
  if (!transport) {
125
+ mcpServer = createComputerMcpServer();
120
126
  transport = new StreamableHTTPServerTransport({
121
127
  sessionIdGenerator: () => randomUUID(),
122
128
  retryInterval: 2000, // 默认重试间隔用于 priming events
123
129
  onsessioninitialized: id => {
124
130
  console.log(`[${id}] Session initialized`);
125
- transports.set(id, transport);
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
+ }
126
140
  }
127
141
  });
128
- await server.connect(transport);
142
+ await mcpServer.connect(transport);
129
143
  }
130
144
 
131
145
  await transport.handleRequest(req, res, req.body);
@@ -160,6 +174,19 @@ app.listen(PORT, error => {
160
174
  // 处理服务器关闭
161
175
  process.on('SIGINT', async () => {
162
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();
163
190
  process.exit(0);
164
191
  });
165
192