@akiojin/unity-mcp-server 5.2.1 → 5.3.2

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 (28) hide show
  1. package/README.md +1 -0
  2. package/package.json +28 -40
  3. package/src/core/codeIndex.js +54 -7
  4. package/src/core/config.js +15 -1
  5. package/src/core/httpServer.js +30 -6
  6. package/src/core/indexBuildWorkerPool.js +57 -3
  7. package/src/core/indexWatcher.js +10 -4
  8. package/src/core/projectInfo.js +34 -12
  9. package/src/core/server.js +58 -27
  10. package/src/core/toolManifest.json +145 -629
  11. package/src/handlers/addressables/AddressablesAnalyzeToolHandler.js +14 -6
  12. package/src/handlers/addressables/AddressablesBuildToolHandler.js +6 -3
  13. package/src/handlers/addressables/AddressablesManageToolHandler.js +6 -3
  14. package/src/handlers/input/InputSystemControlToolHandler.js +1 -1
  15. package/src/handlers/input/InputTouchToolHandler.js +7 -3
  16. package/src/handlers/package/PackageManagerToolHandler.js +6 -3
  17. package/src/handlers/script/CodeIndexStatusToolHandler.js +37 -1
  18. package/src/handlers/script/CodeIndexUpdateToolHandler.js +1 -1
  19. package/src/handlers/script/ScriptEditSnippetToolHandler.js +1 -2
  20. package/src/handlers/script/ScriptEditStructuredToolHandler.js +6 -1
  21. package/src/handlers/script/ScriptRefactorRenameToolHandler.js +3 -1
  22. package/src/handlers/script/ScriptRefsFindToolHandler.js +22 -4
  23. package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +6 -1
  24. package/src/handlers/script/ScriptSymbolsGetToolHandler.js +1 -1
  25. package/src/lsp/CSharpLspUtils.js +11 -3
  26. package/src/lsp/LspProcessManager.js +24 -5
  27. package/src/lsp/LspRpcClient.js +115 -23
  28. package/src/lsp/LspRpcClientSingleton.js +79 -2
@@ -23,6 +23,14 @@ let config = null;
23
23
  let logger = null;
24
24
  let initializationPromise = null;
25
25
 
26
+ const fallbackLogger = {
27
+ info() {},
28
+ warn() {},
29
+ error() {},
30
+ debug() {},
31
+ setServer() {}
32
+ };
33
+
26
34
  let cachedToolManifest = null;
27
35
  function readToolManifest() {
28
36
  if (cachedToolManifest) return cachedToolManifest;
@@ -46,7 +54,7 @@ function readToolManifest() {
46
54
  * Lazily load handlers and dependencies
47
55
  * Called after MCP transport is connected
48
56
  */
49
- async function ensureInitialized() {
57
+ async function ensureInitialized(deps = {}) {
50
58
  if (handlers !== null) return;
51
59
  if (initializationPromise) {
52
60
  await initializationPromise;
@@ -55,17 +63,23 @@ async function ensureInitialized() {
55
63
 
56
64
  initializationPromise = (async () => {
57
65
  // Load config first (needed for logging)
58
- const configModule = await import('./config.js');
66
+ const configModule = deps.config
67
+ ? { config: deps.config, logger: deps.logger }
68
+ : await import('./config.js');
59
69
  config = configModule.config;
60
- logger = configModule.logger;
70
+ logger = configModule.logger ?? deps.logger ?? fallbackLogger;
61
71
 
62
72
  // Load UnityConnection
63
- const { UnityConnection } = await import('./unityConnection.js');
64
- unityConnection = new UnityConnection();
73
+ const UnityConnectionClass = deps.UnityConnection
74
+ ? deps.UnityConnection
75
+ : (await import('./unityConnection.js')).UnityConnection;
76
+ unityConnection = deps.unityConnectionInstance || new UnityConnectionClass();
65
77
 
66
78
  // Load and create handlers
67
- const { createHandlers } = await import('../handlers/index.js');
68
- handlers = createHandlers(unityConnection);
79
+ const createHandlersFn = deps.createHandlers
80
+ ? deps.createHandlers
81
+ : (await import('../handlers/index.js')).createHandlers;
82
+ handlers = createHandlersFn(unityConnection);
69
83
 
70
84
  // Set up Unity connection event handlers
71
85
  unityConnection.on('connected', () => {
@@ -91,6 +105,7 @@ async function ensureInitialized() {
91
105
  // Initialize server
92
106
  export async function startServer(options = {}) {
93
107
  try {
108
+ const deps = options.deps || {};
94
109
  // MCP stdio transport requires stdout to stay clean (JSON-RPC only).
95
110
  // Guard against accidental console.log usage breaking the protocol.
96
111
  if (options.stdioEnabled !== false && process.env.UNITY_MCP_ALLOW_STDOUT !== '1') {
@@ -99,9 +114,12 @@ export async function startServer(options = {}) {
99
114
 
100
115
  // Step 1: Load minimal config for server metadata
101
116
  // (config import is lightweight; avoid importing the MCP TS SDK on startup)
102
- const { config: serverConfig, logger: serverLogger } = await import('./config.js');
117
+ const configModule = deps.config
118
+ ? { config: deps.config, logger: deps.logger }
119
+ : await import('./config.js');
120
+ const { config: serverConfig, logger: serverLogger } = configModule;
103
121
  config = serverConfig;
104
- logger = serverLogger;
122
+ logger = serverLogger ?? deps.logger ?? fallbackLogger;
105
123
 
106
124
  const runtimeConfig = {
107
125
  ...config,
@@ -114,7 +132,7 @@ export async function startServer(options = {}) {
114
132
  const server =
115
133
  runtimeConfig.stdioEnabled === false
116
134
  ? null
117
- : new StdioRpcServer({
135
+ : new (deps.StdioRpcServer || StdioRpcServer)({
118
136
  serverInfo: {
119
137
  name: config.server.name,
120
138
  version: config.server.version
@@ -145,15 +163,17 @@ export async function startServer(options = {}) {
145
163
  }
146
164
 
147
165
  // Start loading handlers in background so first request is faster
148
- ensureInitialized().catch(err => {
166
+ ensureInitialized(deps).catch(err => {
149
167
  console.error(`[unity-mcp-server] Background initialization failed: ${err.message}`);
150
168
  });
151
169
 
152
170
  // Optional HTTP transport (requires handlers)
153
171
  if (runtimeConfig.http?.enabled) {
154
172
  (async () => {
155
- await ensureInitialized();
156
- const { createHttpServer } = await import('./httpServer.js');
173
+ await ensureInitialized(deps);
174
+ const createHttpServer = deps.createHttpServer
175
+ ? deps.createHttpServer
176
+ : (await import('./httpServer.js')).createHttpServer;
157
177
  httpServerInstance = createHttpServer({
158
178
  handlers,
159
179
  host: runtimeConfig.http.host,
@@ -175,7 +195,7 @@ export async function startServer(options = {}) {
175
195
 
176
196
  // Attempt to connect to Unity (deferred, non-blocking)
177
197
  (async () => {
178
- await ensureInitialized();
198
+ await ensureInitialized(deps);
179
199
  console.error(`[unity-mcp-server] Unity connection starting...`);
180
200
  try {
181
201
  await unityConnection.connect();
@@ -190,8 +210,10 @@ export async function startServer(options = {}) {
190
210
  // Best-effort: prepare and start persistent C# LSP process (non-blocking)
191
211
  (async () => {
192
212
  try {
193
- const { LspProcessManager } = await import('../lsp/LspProcessManager.js');
194
- const mgr = new LspProcessManager();
213
+ const LspProcessManagerClass = deps.LspProcessManager
214
+ ? deps.LspProcessManager
215
+ : (await import('../lsp/LspProcessManager.js')).LspProcessManager;
216
+ const mgr = new LspProcessManagerClass();
195
217
  await mgr.ensureStarted();
196
218
  // Attach graceful shutdown
197
219
  const shutdown = async () => {
@@ -208,9 +230,14 @@ export async function startServer(options = {}) {
208
230
 
209
231
  // Start periodic index watcher (incremental)
210
232
  (async () => {
211
- await ensureInitialized();
212
- const { IndexWatcher } = await import('./indexWatcher.js');
213
- const watcher = new IndexWatcher(unityConnection);
233
+ if (process.env.NODE_ENV === 'test') {
234
+ return;
235
+ }
236
+ await ensureInitialized(deps);
237
+ const IndexWatcherClass = deps.IndexWatcher
238
+ ? deps.IndexWatcher
239
+ : (await import('./indexWatcher.js')).IndexWatcher;
240
+ const watcher = new IndexWatcherClass(unityConnection);
214
241
  watcher.start();
215
242
  const stopWatch = () => {
216
243
  try {
@@ -223,10 +250,12 @@ export async function startServer(options = {}) {
223
250
 
224
251
  // Auto-initialize code index if DB doesn't exist
225
252
  (async () => {
226
- await ensureInitialized();
253
+ await ensureInitialized(deps);
227
254
  try {
228
- const { CodeIndex } = await import('./codeIndex.js');
229
- const index = new CodeIndex(unityConnection);
255
+ const CodeIndexClass = deps.CodeIndex
256
+ ? deps.CodeIndex
257
+ : (await import('./codeIndex.js')).CodeIndex;
258
+ const index = new CodeIndexClass(unityConnection);
230
259
  const ready = await index.isReady();
231
260
 
232
261
  if (!ready) {
@@ -237,9 +266,11 @@ export async function startServer(options = {}) {
237
266
  return;
238
267
  }
239
268
  logger.info('[startup] Code index DB not ready. Starting auto-build...');
240
- const { CodeIndexBuildToolHandler } =
241
- await import('../handlers/script/CodeIndexBuildToolHandler.js');
242
- const builder = new CodeIndexBuildToolHandler(unityConnection);
269
+ const CodeIndexBuildToolHandlerClass = deps.CodeIndexBuildToolHandler
270
+ ? deps.CodeIndexBuildToolHandler
271
+ : (await import('../handlers/script/CodeIndexBuildToolHandler.js'))
272
+ .CodeIndexBuildToolHandler;
273
+ const builder = new CodeIndexBuildToolHandlerClass(unityConnection);
243
274
  const result = await builder.execute({});
244
275
 
245
276
  if (result.success) {
@@ -294,7 +325,7 @@ export async function startServer(options = {}) {
294
325
  return { tools: manifestTools };
295
326
  }
296
327
 
297
- await ensureInitialized();
328
+ await ensureInitialized(deps);
298
329
 
299
330
  const tools = Array.from(handlers.values())
300
331
  .map((handler, index) => {
@@ -321,7 +352,7 @@ export async function startServer(options = {}) {
321
352
 
322
353
  // Handle tool execution
323
354
  server?.setRequestHandler('tools/call', async request => {
324
- await ensureInitialized();
355
+ await ensureInitialized(deps);
325
356
 
326
357
  const { name, arguments: args } = request.params || {};
327
358
  const requestTime = Date.now();