@akiojin/unity-mcp-server 2.45.4 → 2.46.0
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 +5 -4
- package/src/constants/offlineTools.js +19 -0
- package/src/core/codeIndex.js +63 -13
- package/src/core/server.js +255 -174
- package/src/core/stdioRpcServer.js +258 -0
- package/src/core/toolManifest.json +4436 -0
- package/src/core/workers/indexBuildWorker.js +301 -46
- package/src/handlers/script/CodeIndexBuildToolHandler.js +1 -1
- package/src/handlers/script/CodeIndexStatusToolHandler.js +1 -1
- package/src/handlers/script/CodeIndexUpdateToolHandler.js +1 -1
- package/src/handlers/script/ScriptPackagesListToolHandler.js +1 -1
- package/src/handlers/script/ScriptReadToolHandler.js +9 -2
- package/src/handlers/script/ScriptRefsFindToolHandler.js +131 -36
- package/src/handlers/script/ScriptSearchToolHandler.js +1 -1
- package/src/handlers/script/ScriptSymbolFindToolHandler.js +32 -33
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +18 -10
- package/src/handlers/system/SystemPingToolHandler.js +30 -17
- package/src/lsp/CSharpLspUtils.js +11 -50
package/src/core/server.js
CHANGED
|
@@ -5,27 +5,42 @@
|
|
|
5
5
|
* This module implements a deferred initialization pattern to ensure
|
|
6
6
|
* npx compatibility. The MCP transport connection is established FIRST,
|
|
7
7
|
* before loading handlers and other heavy dependencies, to avoid
|
|
8
|
-
*
|
|
8
|
+
* MCP client startup timeouts (NFR: startup <= 10s).
|
|
9
9
|
*
|
|
10
10
|
* Initialization order:
|
|
11
|
-
* 1.
|
|
12
|
-
* 2.
|
|
11
|
+
* 1. Stdio JSON-RPC listener (fast, no heavy deps)
|
|
12
|
+
* 2. Initialization handshake (must complete before timeout)
|
|
13
13
|
* 3. Handler loading (deferred, after connection)
|
|
14
14
|
* 4. Unity connection (deferred, non-blocking)
|
|
15
15
|
*/
|
|
16
|
-
import
|
|
17
|
-
import {
|
|
18
|
-
ListToolsRequestSchema,
|
|
19
|
-
CallToolRequestSchema,
|
|
20
|
-
SetLevelRequestSchema
|
|
21
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
22
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import { StdioRpcServer } from './stdioRpcServer.js';
|
|
23
18
|
|
|
24
19
|
// Deferred state - will be initialized after transport connection
|
|
25
20
|
let unityConnection = null;
|
|
26
21
|
let handlers = null;
|
|
27
22
|
let config = null;
|
|
28
23
|
let logger = null;
|
|
24
|
+
let initializationPromise = null;
|
|
25
|
+
|
|
26
|
+
let cachedToolManifest = null;
|
|
27
|
+
function readToolManifest() {
|
|
28
|
+
if (cachedToolManifest) return cachedToolManifest;
|
|
29
|
+
try {
|
|
30
|
+
const raw = fs.readFileSync(new URL('./toolManifest.json', import.meta.url), 'utf8');
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
const tools = Array.isArray(parsed)
|
|
33
|
+
? parsed
|
|
34
|
+
: Array.isArray(parsed?.tools)
|
|
35
|
+
? parsed.tools
|
|
36
|
+
: null;
|
|
37
|
+
if (tools && tools.every(t => t && typeof t === 'object' && typeof t.name === 'string')) {
|
|
38
|
+
cachedToolManifest = tools;
|
|
39
|
+
return tools;
|
|
40
|
+
}
|
|
41
|
+
} catch {}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
29
44
|
|
|
30
45
|
/**
|
|
31
46
|
* Lazily load handlers and dependencies
|
|
@@ -33,39 +48,51 @@ let logger = null;
|
|
|
33
48
|
*/
|
|
34
49
|
async function ensureInitialized() {
|
|
35
50
|
if (handlers !== null) return;
|
|
51
|
+
if (initializationPromise) {
|
|
52
|
+
await initializationPromise;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
initializationPromise = (async () => {
|
|
57
|
+
// Load config first (needed for logging)
|
|
58
|
+
const configModule = await import('./config.js');
|
|
59
|
+
config = configModule.config;
|
|
60
|
+
logger = configModule.logger;
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
// Load UnityConnection
|
|
63
|
+
const { UnityConnection } = await import('./unityConnection.js');
|
|
64
|
+
unityConnection = new UnityConnection();
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
// Load and create handlers
|
|
67
|
+
const { createHandlers } = await import('../handlers/index.js');
|
|
68
|
+
handlers = createHandlers(unityConnection);
|
|
49
69
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
// Set up Unity connection event handlers
|
|
71
|
+
unityConnection.on('connected', () => {
|
|
72
|
+
logger.info('Unity connection established');
|
|
73
|
+
});
|
|
54
74
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
75
|
+
unityConnection.on('disconnected', () => {
|
|
76
|
+
logger.info('Unity connection lost');
|
|
77
|
+
});
|
|
58
78
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
79
|
+
unityConnection.on('error', error => {
|
|
80
|
+
logger.error('Unity connection error:', error.message);
|
|
81
|
+
});
|
|
82
|
+
})();
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await initializationPromise;
|
|
86
|
+
} finally {
|
|
87
|
+
initializationPromise = null;
|
|
88
|
+
}
|
|
62
89
|
}
|
|
63
90
|
|
|
64
91
|
// Initialize server
|
|
65
92
|
export async function startServer(options = {}) {
|
|
66
93
|
try {
|
|
67
94
|
// Step 1: Load minimal config for server metadata
|
|
68
|
-
//
|
|
95
|
+
// (config import is lightweight; avoid importing the MCP TS SDK on startup)
|
|
69
96
|
const { config: serverConfig, logger: serverLogger } = await import('./config.js');
|
|
70
97
|
config = serverConfig;
|
|
71
98
|
logger = serverLogger;
|
|
@@ -77,47 +104,190 @@ export async function startServer(options = {}) {
|
|
|
77
104
|
stdioEnabled: options.stdioEnabled !== undefined ? options.stdioEnabled : true
|
|
78
105
|
};
|
|
79
106
|
|
|
80
|
-
// Step 2: Create MCP server
|
|
81
|
-
const server =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
// Step 2: Create a lightweight stdio MCP server (no TS SDK import)
|
|
108
|
+
const server =
|
|
109
|
+
runtimeConfig.stdioEnabled === false
|
|
110
|
+
? null
|
|
111
|
+
: new StdioRpcServer({
|
|
112
|
+
serverInfo: {
|
|
113
|
+
name: config.server.name,
|
|
114
|
+
version: config.server.version
|
|
115
|
+
},
|
|
116
|
+
capabilities: {
|
|
117
|
+
// Advertise tool support with listChanged enabled for future push updates
|
|
118
|
+
tools: { listChanged: true },
|
|
119
|
+
// Enable MCP logging capability for notifications/message
|
|
120
|
+
logging: {}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
let httpServerInstance;
|
|
125
|
+
|
|
126
|
+
// Defer expensive background work until after the client has completed
|
|
127
|
+
// initialization and received the initial tool list.
|
|
128
|
+
let mcpInitComplete = runtimeConfig.stdioEnabled === false;
|
|
129
|
+
let postInitRequested = runtimeConfig.stdioEnabled === false;
|
|
130
|
+
let postInitStarted = false;
|
|
131
|
+
|
|
132
|
+
const startPostInit = () => {
|
|
133
|
+
if (postInitStarted) return;
|
|
134
|
+
postInitStarted = true;
|
|
135
|
+
|
|
136
|
+
// Enable MCP logging notifications (REQ-4) after initialization handshake
|
|
137
|
+
if (runtimeConfig.stdioEnabled !== false) {
|
|
138
|
+
logger.setServer(server);
|
|
94
139
|
}
|
|
95
|
-
);
|
|
96
140
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
transport = new StdioServerTransport();
|
|
102
|
-
await server.connect(transport);
|
|
103
|
-
console.error(`[unity-mcp-server] MCP transport connected`);
|
|
141
|
+
// Start loading handlers in background so first request is faster
|
|
142
|
+
ensureInitialized().catch(err => {
|
|
143
|
+
console.error(`[unity-mcp-server] Background initialization failed: ${err.message}`);
|
|
144
|
+
});
|
|
104
145
|
|
|
105
|
-
//
|
|
106
|
-
|
|
146
|
+
// Optional HTTP transport (requires handlers)
|
|
147
|
+
if (runtimeConfig.http?.enabled) {
|
|
148
|
+
(async () => {
|
|
149
|
+
await ensureInitialized();
|
|
150
|
+
const { createHttpServer } = await import('./httpServer.js');
|
|
151
|
+
httpServerInstance = createHttpServer({
|
|
152
|
+
handlers,
|
|
153
|
+
host: runtimeConfig.http.host,
|
|
154
|
+
port: runtimeConfig.http.port,
|
|
155
|
+
telemetryEnabled: runtimeConfig.telemetry.enabled,
|
|
156
|
+
healthPath: runtimeConfig.http.healthPath,
|
|
157
|
+
allowedHosts: runtimeConfig.http.allowedHosts
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
await httpServerInstance.start();
|
|
161
|
+
} catch (err) {
|
|
162
|
+
logger.error(`HTTP server failed to start: ${err.message}`);
|
|
163
|
+
if (runtimeConfig.stdioEnabled === false) {
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
})();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Attempt to connect to Unity (deferred, non-blocking)
|
|
171
|
+
(async () => {
|
|
172
|
+
await ensureInitialized();
|
|
173
|
+
console.error(`[unity-mcp-server] Unity connection starting...`);
|
|
174
|
+
try {
|
|
175
|
+
await unityConnection.connect();
|
|
176
|
+
console.error(`[unity-mcp-server] Unity connection established`);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error(`[unity-mcp-server] Unity connection failed: ${error.message}`);
|
|
179
|
+
logger.error('Initial Unity connection failed:', error.message);
|
|
180
|
+
logger.info('Unity connection will retry automatically');
|
|
181
|
+
}
|
|
182
|
+
})();
|
|
183
|
+
|
|
184
|
+
// Best-effort: prepare and start persistent C# LSP process (non-blocking)
|
|
185
|
+
(async () => {
|
|
186
|
+
try {
|
|
187
|
+
const { LspProcessManager } = await import('../lsp/LspProcessManager.js');
|
|
188
|
+
const mgr = new LspProcessManager();
|
|
189
|
+
await mgr.ensureStarted();
|
|
190
|
+
// Attach graceful shutdown
|
|
191
|
+
const shutdown = async () => {
|
|
192
|
+
try {
|
|
193
|
+
await mgr.stop(3000);
|
|
194
|
+
} catch {}
|
|
195
|
+
};
|
|
196
|
+
process.on('SIGINT', shutdown);
|
|
197
|
+
process.on('SIGTERM', shutdown);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
logger.warning(`[startup] csharp-lsp start failed: ${e.message}`);
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
|
|
203
|
+
// Start periodic index watcher (incremental)
|
|
204
|
+
(async () => {
|
|
205
|
+
await ensureInitialized();
|
|
206
|
+
const { IndexWatcher } = await import('./indexWatcher.js');
|
|
207
|
+
const watcher = new IndexWatcher(unityConnection);
|
|
208
|
+
watcher.start();
|
|
209
|
+
const stopWatch = () => {
|
|
210
|
+
try {
|
|
211
|
+
watcher.stop();
|
|
212
|
+
} catch {}
|
|
213
|
+
};
|
|
214
|
+
process.on('SIGINT', stopWatch);
|
|
215
|
+
process.on('SIGTERM', stopWatch);
|
|
216
|
+
})();
|
|
217
|
+
|
|
218
|
+
// Auto-initialize code index if DB doesn't exist
|
|
219
|
+
(async () => {
|
|
220
|
+
await ensureInitialized();
|
|
221
|
+
try {
|
|
222
|
+
const { CodeIndex } = await import('./codeIndex.js');
|
|
223
|
+
const index = new CodeIndex(unityConnection);
|
|
224
|
+
const ready = await index.isReady();
|
|
225
|
+
|
|
226
|
+
if (!ready) {
|
|
227
|
+
if (index.disabled) {
|
|
228
|
+
logger.warning(
|
|
229
|
+
`[startup] Code index disabled: ${index.disableReason || 'SQLite native binding missing'}. Skipping auto-build.`
|
|
230
|
+
);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
logger.info('[startup] Code index DB not ready. Starting auto-build...');
|
|
234
|
+
const { CodeIndexBuildToolHandler } =
|
|
235
|
+
await import('../handlers/script/CodeIndexBuildToolHandler.js');
|
|
236
|
+
const builder = new CodeIndexBuildToolHandler(unityConnection);
|
|
237
|
+
const result = await builder.execute({});
|
|
238
|
+
|
|
239
|
+
if (result.success) {
|
|
240
|
+
logger.info(
|
|
241
|
+
`[startup] Code index auto-build started: jobId=${result.jobId}. Use code_index_status to check progress.`
|
|
242
|
+
);
|
|
243
|
+
} else {
|
|
244
|
+
logger.warning(`[startup] Code index auto-build failed: ${result.message}`);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
logger.info('[startup] Code index DB already exists. Skipping auto-build.');
|
|
248
|
+
}
|
|
249
|
+
} catch (e) {
|
|
250
|
+
logger.warning(`[startup] Code index auto-init failed: ${e.message}`);
|
|
251
|
+
}
|
|
252
|
+
})();
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const requestPostInit = () => {
|
|
256
|
+
postInitRequested = true;
|
|
257
|
+
if (mcpInitComplete) {
|
|
258
|
+
setImmediate(startPostInit);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// For stdio MCP, wait for notifications/initialized AND the initial tools/list
|
|
263
|
+
// to avoid blocking startup tool discovery in clients with short timeouts.
|
|
264
|
+
if (server) {
|
|
265
|
+
server.oninitialized = () => {
|
|
266
|
+
mcpInitComplete = true;
|
|
267
|
+
if (postInitRequested) {
|
|
268
|
+
setImmediate(startPostInit);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
107
271
|
}
|
|
108
272
|
|
|
109
|
-
// Step
|
|
273
|
+
// Step 3: Register request handlers (they will lazily load dependencies)
|
|
110
274
|
// Handle logging/setLevel request (REQ-6)
|
|
111
|
-
server
|
|
112
|
-
|
|
113
|
-
const { level } = request.params;
|
|
275
|
+
server?.setRequestHandler('logging/setLevel', async request => {
|
|
276
|
+
const { level } = request.params || {};
|
|
114
277
|
logger.setLevel(level);
|
|
115
278
|
logger.info(`Log level changed to: ${level}`);
|
|
116
279
|
return {};
|
|
117
280
|
});
|
|
118
281
|
|
|
119
282
|
// Handle tool listing
|
|
120
|
-
server
|
|
283
|
+
server?.setRequestHandler('tools/list', async () => {
|
|
284
|
+
const manifestTools = readToolManifest();
|
|
285
|
+
if (manifestTools) {
|
|
286
|
+
logger.info(`[MCP] Returning ${manifestTools.length} tool definitions`);
|
|
287
|
+
requestPostInit();
|
|
288
|
+
return { tools: manifestTools };
|
|
289
|
+
}
|
|
290
|
+
|
|
121
291
|
await ensureInitialized();
|
|
122
292
|
|
|
123
293
|
const tools = Array.from(handlers.values())
|
|
@@ -139,14 +309,15 @@ export async function startServer(options = {}) {
|
|
|
139
309
|
.filter(tool => tool !== null);
|
|
140
310
|
|
|
141
311
|
logger.info(`[MCP] Returning ${tools.length} tool definitions`);
|
|
312
|
+
requestPostInit();
|
|
142
313
|
return { tools };
|
|
143
314
|
});
|
|
144
315
|
|
|
145
316
|
// Handle tool execution
|
|
146
|
-
server
|
|
317
|
+
server?.setRequestHandler('tools/call', async request => {
|
|
147
318
|
await ensureInitialized();
|
|
148
319
|
|
|
149
|
-
const { name, arguments: args } = request.params;
|
|
320
|
+
const { name, arguments: args } = request.params || {};
|
|
150
321
|
const requestTime = Date.now();
|
|
151
322
|
|
|
152
323
|
logger.info(
|
|
@@ -239,124 +410,27 @@ export async function startServer(options = {}) {
|
|
|
239
410
|
}
|
|
240
411
|
});
|
|
241
412
|
|
|
413
|
+
// Step 4: Start stdio listener (critical for short client timeouts)
|
|
414
|
+
if (server) {
|
|
415
|
+
console.error(`[unity-mcp-server] MCP transport connecting...`);
|
|
416
|
+
await server.start();
|
|
417
|
+
console.error(`[unity-mcp-server] MCP transport connected`);
|
|
418
|
+
}
|
|
419
|
+
|
|
242
420
|
// Now safe to log after connection established
|
|
243
421
|
logger.info('MCP server started successfully');
|
|
244
422
|
|
|
245
|
-
//
|
|
246
|
-
// Start
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// Optional HTTP transport
|
|
252
|
-
let httpServerInstance;
|
|
253
|
-
if (runtimeConfig.http?.enabled) {
|
|
254
|
-
const { createHttpServer } = await import('./httpServer.js');
|
|
255
|
-
httpServerInstance = createHttpServer({
|
|
256
|
-
handlers,
|
|
257
|
-
host: runtimeConfig.http.host,
|
|
258
|
-
port: runtimeConfig.http.port,
|
|
259
|
-
telemetryEnabled: runtimeConfig.telemetry.enabled,
|
|
260
|
-
healthPath: runtimeConfig.http.healthPath
|
|
261
|
-
});
|
|
262
|
-
try {
|
|
263
|
-
await httpServerInstance.start();
|
|
264
|
-
} catch (err) {
|
|
265
|
-
logger.error(`HTTP server failed to start: ${err.message}`);
|
|
266
|
-
throw err;
|
|
267
|
-
}
|
|
423
|
+
// In HTTP-only mode (--no-stdio), there is no MCP tools/list handshake.
|
|
424
|
+
// Start background work immediately so the HTTP server can come up.
|
|
425
|
+
if (runtimeConfig.stdioEnabled === false) {
|
|
426
|
+
startPostInit();
|
|
268
427
|
}
|
|
269
428
|
|
|
270
|
-
// Attempt to connect to Unity (deferred, non-blocking)
|
|
271
|
-
(async () => {
|
|
272
|
-
await ensureInitialized();
|
|
273
|
-
console.error(`[unity-mcp-server] Unity connection starting...`);
|
|
274
|
-
try {
|
|
275
|
-
await unityConnection.connect();
|
|
276
|
-
console.error(`[unity-mcp-server] Unity connection established`);
|
|
277
|
-
} catch (error) {
|
|
278
|
-
console.error(`[unity-mcp-server] Unity connection failed: ${error.message}`);
|
|
279
|
-
logger.error('Initial Unity connection failed:', error.message);
|
|
280
|
-
logger.info('Unity connection will retry automatically');
|
|
281
|
-
}
|
|
282
|
-
})();
|
|
283
|
-
|
|
284
|
-
// Best-effort: prepare and start persistent C# LSP process (non-blocking)
|
|
285
|
-
(async () => {
|
|
286
|
-
try {
|
|
287
|
-
const { LspProcessManager } = await import('../lsp/LspProcessManager.js');
|
|
288
|
-
const mgr = new LspProcessManager();
|
|
289
|
-
await mgr.ensureStarted();
|
|
290
|
-
// Attach graceful shutdown
|
|
291
|
-
const shutdown = async () => {
|
|
292
|
-
try {
|
|
293
|
-
await mgr.stop(3000);
|
|
294
|
-
} catch {}
|
|
295
|
-
};
|
|
296
|
-
process.on('SIGINT', shutdown);
|
|
297
|
-
process.on('SIGTERM', shutdown);
|
|
298
|
-
} catch (e) {
|
|
299
|
-
logger.warning(`[startup] csharp-lsp start failed: ${e.message}`);
|
|
300
|
-
}
|
|
301
|
-
})();
|
|
302
|
-
|
|
303
|
-
// Start periodic index watcher (incremental)
|
|
304
|
-
(async () => {
|
|
305
|
-
await ensureInitialized();
|
|
306
|
-
const { IndexWatcher } = await import('./indexWatcher.js');
|
|
307
|
-
const watcher = new IndexWatcher(unityConnection);
|
|
308
|
-
watcher.start();
|
|
309
|
-
const stopWatch = () => {
|
|
310
|
-
try {
|
|
311
|
-
watcher.stop();
|
|
312
|
-
} catch {}
|
|
313
|
-
};
|
|
314
|
-
process.on('SIGINT', stopWatch);
|
|
315
|
-
process.on('SIGTERM', stopWatch);
|
|
316
|
-
})();
|
|
317
|
-
|
|
318
|
-
// Auto-initialize code index if DB doesn't exist
|
|
319
|
-
(async () => {
|
|
320
|
-
await ensureInitialized();
|
|
321
|
-
try {
|
|
322
|
-
const { CodeIndex } = await import('./codeIndex.js');
|
|
323
|
-
const index = new CodeIndex(unityConnection);
|
|
324
|
-
const ready = await index.isReady();
|
|
325
|
-
|
|
326
|
-
if (!ready) {
|
|
327
|
-
if (index.disabled) {
|
|
328
|
-
logger.warning(
|
|
329
|
-
`[startup] Code index disabled: ${index.disableReason || 'SQLite native binding missing'}. Skipping auto-build.`
|
|
330
|
-
);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
logger.info('[startup] Code index DB not ready. Starting auto-build...');
|
|
334
|
-
const { CodeIndexBuildToolHandler } = await import(
|
|
335
|
-
'../handlers/script/CodeIndexBuildToolHandler.js'
|
|
336
|
-
);
|
|
337
|
-
const builder = new CodeIndexBuildToolHandler(unityConnection);
|
|
338
|
-
const result = await builder.execute({});
|
|
339
|
-
|
|
340
|
-
if (result.success) {
|
|
341
|
-
logger.info(
|
|
342
|
-
`[startup] Code index auto-build started: jobId=${result.jobId}. Use code_index_status to check progress.`
|
|
343
|
-
);
|
|
344
|
-
} else {
|
|
345
|
-
logger.warning(`[startup] Code index auto-build failed: ${result.message}`);
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
logger.info('[startup] Code index DB already exists. Skipping auto-build.');
|
|
349
|
-
}
|
|
350
|
-
} catch (e) {
|
|
351
|
-
logger.warning(`[startup] Code index auto-init failed: ${e.message}`);
|
|
352
|
-
}
|
|
353
|
-
})();
|
|
354
|
-
|
|
355
429
|
// Handle shutdown
|
|
356
430
|
process.on('SIGINT', async () => {
|
|
357
431
|
logger.info('Shutting down...');
|
|
358
432
|
if (unityConnection) unityConnection.disconnect();
|
|
359
|
-
if (
|
|
433
|
+
if (server) await server.close();
|
|
360
434
|
if (httpServerInstance) await httpServerInstance.close();
|
|
361
435
|
process.exit(0);
|
|
362
436
|
});
|
|
@@ -364,7 +438,7 @@ export async function startServer(options = {}) {
|
|
|
364
438
|
process.on('SIGTERM', async () => {
|
|
365
439
|
logger.info('Shutting down...');
|
|
366
440
|
if (unityConnection) unityConnection.disconnect();
|
|
367
|
-
if (
|
|
441
|
+
if (server) await server.close();
|
|
368
442
|
if (httpServerInstance) await httpServerInstance.close();
|
|
369
443
|
process.exit(0);
|
|
370
444
|
});
|
|
@@ -380,9 +454,16 @@ export const main = startServer;
|
|
|
380
454
|
|
|
381
455
|
// Export for testing
|
|
382
456
|
export async function createServer(customConfig) {
|
|
383
|
-
// For testing,
|
|
384
|
-
const { config: defaultConfig } = await
|
|
457
|
+
// For testing, keep using the official MCP SDK to validate compatibility.
|
|
458
|
+
const [{ config: defaultConfig }, sdkServerModule, sdkTypesModule] = await Promise.all([
|
|
459
|
+
import('./config.js'),
|
|
460
|
+
import('@modelcontextprotocol/sdk/server/index.js'),
|
|
461
|
+
import('@modelcontextprotocol/sdk/types.js')
|
|
462
|
+
]);
|
|
463
|
+
|
|
385
464
|
const actualConfig = customConfig || defaultConfig;
|
|
465
|
+
const { Server } = sdkServerModule;
|
|
466
|
+
const { ListToolsRequestSchema, CallToolRequestSchema } = sdkTypesModule;
|
|
386
467
|
|
|
387
468
|
const { UnityConnection } = await import('./unityConnection.js');
|
|
388
469
|
const { createHandlers } = await import('../handlers/index.js');
|