@mandujs/mcp 0.38.0 → 0.38.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandujs/mcp",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@mandujs/core": "^0.54.6",
37
+ "@mandujs/core": "^0.54.7",
38
38
  "@mandujs/ate": "^0.26.1",
39
39
  "@mandujs/skills": "^0.20.1",
40
40
  "@modelcontextprotocol/sdk": "^1.25.3"
@@ -1,13 +1,13 @@
1
1
  import type { Tool } from "@modelcontextprotocol/sdk/types.js";
2
2
  import { type ManduError } from "@mandujs/core/error";
3
- import {
4
- checkDirectory,
5
- getDefaultFsRoutesGuardPolicy,
6
- validateAndReport,
7
- loadManifest,
8
- runGuardCheck,
9
- runAutoCorrect,
10
- type GeneratedMap,
3
+ import {
4
+ checkDirectory,
5
+ getDefaultFsRoutesGuardPolicy,
6
+ validateAndReport,
7
+ loadManifest,
8
+ runGuardCheck,
9
+ runAutoCorrect,
10
+ type GeneratedMap,
11
11
  // Self-Healing Guard imports
12
12
  checkWithHealing,
13
13
  healAll,
@@ -15,19 +15,19 @@ import {
15
15
  // Follow-up E — type-aware lint bridge
16
16
  runTsgolint,
17
17
  type GuardConfig,
18
- type ViolationType,
19
- type GuardPreset,
20
- type Violation,
21
- } from "@mandujs/core";
22
- import { getProjectPaths, readJsonFile, readConfig } from "../utils/project.js";
23
- import fs from "fs/promises";
24
- import path from "path";
18
+ type ViolationType,
19
+ type GuardPreset,
20
+ type Violation,
21
+ } from "@mandujs/core";
22
+ import { getProjectPaths, readJsonFile, readConfig } from "../utils/project.js";
23
+ import fs from "fs/promises";
24
+ import path from "path";
25
25
 
26
26
  export const guardToolDefinitions: Tool[] = [
27
27
  {
28
- name: "mandu.guard.check",
29
- description:
30
- "Run the same architecture guard used by `mandu guard`, plus legacy spec/generated/slot checks. Set typeAware=true to additionally run `oxlint --type-aware` (tsgolint) and merge its results.",
28
+ name: "mandu.guard.check",
29
+ description:
30
+ "Run the same architecture guard used by `mandu guard`, plus legacy spec/generated/slot checks. Set typeAware=true to additionally run `oxlint --type-aware` (tsgolint) and merge its results.",
31
31
  annotations: {
32
32
  readOnlyHint: true,
33
33
  },
@@ -126,37 +126,37 @@ export const guardToolDefinitions: Tool[] = [
126
126
  },
127
127
  ];
128
128
 
129
- export function guardTools(projectRoot: string) {
130
- const paths = getProjectPaths(projectRoot);
131
-
132
- const pathExists = async (candidate: string): Promise<boolean> => {
133
- try {
134
- await fs.access(candidate);
135
- return true;
136
- } catch {
137
- return false;
138
- }
139
- };
140
-
141
- const summarizeArchitectureViolation = (violation: Violation) => ({
142
- ruleId: violation.ruleName,
143
- type: violation.type,
144
- file: path.relative(projectRoot, violation.filePath).replace(/\\/g, "/") || violation.filePath,
145
- line: violation.line,
146
- column: violation.column,
147
- message: violation.ruleDescription,
148
- suggestion: violation.suggestions[0],
149
- fromLayer: violation.fromLayer,
150
- toLayer: violation.toLayer,
151
- importStatement: violation.importStatement,
152
- });
153
-
154
- const summarizeLegacyViolation = (v: Awaited<ReturnType<typeof runGuardCheck>>["violations"][number]) => ({
155
- ruleId: v.ruleId,
156
- file: v.file,
157
- message: v.message,
158
- suggestion: v.suggestion,
159
- });
129
+ export function guardTools(projectRoot: string) {
130
+ const paths = getProjectPaths(projectRoot);
131
+
132
+ const pathExists = async (candidate: string): Promise<boolean> => {
133
+ try {
134
+ await fs.access(candidate);
135
+ return true;
136
+ } catch {
137
+ return false;
138
+ }
139
+ };
140
+
141
+ const summarizeArchitectureViolation = (violation: Violation) => ({
142
+ ruleId: violation.ruleName,
143
+ type: violation.type,
144
+ file: path.relative(projectRoot, violation.filePath).replace(/\\/g, "/") || violation.filePath,
145
+ line: violation.line,
146
+ column: violation.column,
147
+ message: violation.ruleDescription,
148
+ suggestion: violation.suggestions[0],
149
+ fromLayer: violation.fromLayer,
150
+ toLayer: violation.toLayer,
151
+ importStatement: violation.importStatement,
152
+ });
153
+
154
+ const summarizeLegacyViolation = (v: Awaited<ReturnType<typeof runGuardCheck>>["violations"][number]) => ({
155
+ ruleId: v.ruleId,
156
+ file: v.file,
157
+ message: v.message,
158
+ suggestion: v.suggestion,
159
+ });
160
160
 
161
161
  const handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
162
162
  "mandu.guard.check": async (args: Record<string, unknown>) => {
@@ -172,44 +172,44 @@ export function guardTools(projectRoot: string) {
172
172
  error: "Failed to load manifest",
173
173
  details: manifestResult.errors,
174
174
  };
175
- }
176
-
177
- const projectConfig = await validateAndReport(projectRoot);
178
- const guardConfigFromFile = (projectConfig?.guard ?? {}) as GuardConfig;
179
- const preset = guardConfigFromFile.preset ?? "mandu";
180
- const enableFsRoutes = await pathExists(paths.appDir);
181
-
182
- const architectureReport = await checkDirectory(
183
- {
184
- preset,
185
- srcDir: guardConfigFromFile.srcDir ?? "src",
186
- exclude: guardConfigFromFile.exclude,
187
- fsRoutes: getDefaultFsRoutesGuardPolicy(enableFsRoutes),
188
- },
189
- projectRoot
190
- );
191
- const architecturePassed = architectureReport.bySeverity.error === 0;
192
- const architectureViolations = architectureReport.violations.map(
193
- summarizeArchitectureViolation
194
- );
195
-
196
- // Run guard check
197
- const checkResult = await runGuardCheck(manifestResult.data, projectRoot);
175
+ }
176
+
177
+ const projectConfig = await validateAndReport(projectRoot);
178
+ const guardConfigFromFile = (projectConfig?.guard ?? {}) as GuardConfig;
179
+ const preset = guardConfigFromFile.preset ?? "mandu";
180
+ const enableFsRoutes = await pathExists(paths.appDir);
181
+
182
+ const architectureReport = await checkDirectory(
183
+ {
184
+ preset,
185
+ srcDir: guardConfigFromFile.srcDir ?? "src",
186
+ exclude: guardConfigFromFile.exclude,
187
+ fsRoutes: getDefaultFsRoutesGuardPolicy(enableFsRoutes),
188
+ },
189
+ projectRoot
190
+ );
191
+ const architecturePassed = architectureReport.bySeverity.error === 0;
192
+ const architectureViolations = architectureReport.violations.map(
193
+ summarizeArchitectureViolation
194
+ );
195
+
196
+ // Run guard check
197
+ const checkResult = await runGuardCheck(manifestResult.data, projectRoot);
198
198
 
199
199
  // Follow-up E — resolve type-aware defaulting from config, then
200
200
  // run the bridge when enabled. Result envelope is always included
201
201
  // in the tool response so MCP clients have a single stable shape.
202
- let rawProjectConfig: Awaited<ReturnType<typeof readConfig>> | undefined;
203
- try {
204
- rawProjectConfig = projectConfig ?? await readConfig(projectRoot);
205
- } catch {
206
- rawProjectConfig = projectConfig ?? undefined;
207
- }
208
- const typeAwareCfg = (
209
- rawProjectConfig?.guard as
210
- | { typeAware?: Record<string, unknown> }
211
- | undefined
212
- )?.typeAware;
202
+ let rawProjectConfig: Awaited<ReturnType<typeof readConfig>> | undefined;
203
+ try {
204
+ rawProjectConfig = projectConfig ?? await readConfig(projectRoot);
205
+ } catch {
206
+ rawProjectConfig = projectConfig ?? undefined;
207
+ }
208
+ const typeAwareCfg = (
209
+ rawProjectConfig?.guard as
210
+ | { typeAware?: Record<string, unknown> }
211
+ | undefined
212
+ )?.typeAware;
213
213
  const typeAwareEnabled =
214
214
  typeAwareArg !== undefined ? typeAwareArg : typeAwareCfg !== undefined;
215
215
 
@@ -229,40 +229,40 @@ export function guardTools(projectRoot: string) {
229
229
  skipped: bridge.skipped,
230
230
  summary: bridge.summary,
231
231
  violations: bridge.violations,
232
- };
233
- }
234
-
235
- const typeAwareViolations = typeAwareResponse
236
- ? typeAwareResponse.violations as Array<{ severity: string }>
237
- : [];
238
- const typeAwareErrorCount = typeAwareViolations.filter(
239
- (v) => v.severity === "error",
240
- ).length;
241
- const legacyViolations = checkResult.violations.map(summarizeLegacyViolation);
242
- const combinedViolations = [
243
- ...architectureViolations,
244
- ...legacyViolations,
245
- ];
246
- const allPassed = checkResult.passed && architecturePassed && typeAwareErrorCount === 0;
247
- const blockingViolationCount = combinedViolations.length + typeAwareErrorCount;
248
-
249
- if (allPassed) {
250
- return {
251
- passed: true,
252
- violations: [],
253
- message: "All guard checks passed",
254
- architecture: {
255
- passed: true,
256
- totalViolations: architectureReport.totalViolations,
257
- bySeverity: architectureReport.bySeverity,
258
- },
259
- legacy: {
260
- passed: true,
261
- violations: 0,
262
- },
263
- relatedSkills: ["mandu-guard-guide", "mandu-debug"],
264
- ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
265
- };
232
+ };
233
+ }
234
+
235
+ const typeAwareViolations = typeAwareResponse
236
+ ? typeAwareResponse.violations as Array<{ severity: string }>
237
+ : [];
238
+ const typeAwareErrorCount = typeAwareViolations.filter(
239
+ (v) => v.severity === "error",
240
+ ).length;
241
+ const legacyViolations = checkResult.violations.map(summarizeLegacyViolation);
242
+ const combinedViolations = [
243
+ ...architectureViolations,
244
+ ...legacyViolations,
245
+ ];
246
+ const allPassed = checkResult.passed && architecturePassed && typeAwareErrorCount === 0;
247
+ const blockingViolationCount = combinedViolations.length + typeAwareErrorCount;
248
+
249
+ if (allPassed) {
250
+ return {
251
+ passed: true,
252
+ violations: [],
253
+ message: "All guard checks passed",
254
+ architecture: {
255
+ passed: true,
256
+ totalViolations: architectureReport.totalViolations,
257
+ bySeverity: architectureReport.bySeverity,
258
+ },
259
+ legacy: {
260
+ passed: true,
261
+ violations: 0,
262
+ },
263
+ relatedSkills: ["mandu-guard-guide", "mandu-debug"],
264
+ ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
265
+ };
266
266
  }
267
267
 
268
268
  // If auto-correct requested and there are violations
@@ -273,54 +273,54 @@ export function guardTools(projectRoot: string) {
273
273
  projectRoot
274
274
  );
275
275
 
276
- return {
277
- passed:
278
- autoCorrectResult.fixed &&
279
- architecturePassed &&
280
- typeAwareErrorCount === 0,
281
- violations: [
282
- ...architectureViolations,
283
- ...autoCorrectResult.remainingViolations.map(summarizeLegacyViolation),
284
- ],
285
- autoCorrect: {
286
- attempted: true,
287
- fixed: autoCorrectResult.fixed,
276
+ return {
277
+ passed:
278
+ autoCorrectResult.fixed &&
279
+ architecturePassed &&
280
+ typeAwareErrorCount === 0,
281
+ violations: [
282
+ ...architectureViolations,
283
+ ...autoCorrectResult.remainingViolations.map(summarizeLegacyViolation),
284
+ ],
285
+ autoCorrect: {
286
+ attempted: true,
287
+ fixed: autoCorrectResult.fixed,
288
288
  steps: autoCorrectResult.steps,
289
289
  retriedCount: autoCorrectResult.retriedCount,
290
290
  rolledBack: autoCorrectResult.rolledBack,
291
- changeId: autoCorrectResult.changeId,
292
- },
293
- architecture: {
294
- passed: architecturePassed,
295
- totalViolations: architectureReport.totalViolations,
296
- bySeverity: architectureReport.bySeverity,
297
- violations: architectureViolations,
298
- },
299
- legacy: {
300
- passed: autoCorrectResult.fixed,
301
- violations: autoCorrectResult.remainingViolations.length,
302
- },
303
- ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
304
- };
305
- }
306
-
307
- return {
308
- passed: false,
309
- violations: combinedViolations,
310
- message: `Found ${blockingViolationCount} violation(s)`,
311
- architecture: {
312
- passed: architecturePassed,
313
- totalViolations: architectureReport.totalViolations,
314
- bySeverity: architectureReport.bySeverity,
315
- violations: architectureViolations,
316
- },
317
- legacy: {
318
- passed: checkResult.passed,
319
- violations: legacyViolations.length,
320
- },
321
- tip: "Use autoCorrect: true to attempt automatic fixes",
322
- relatedSkills: ["mandu-guard-guide", "mandu-debug"],
323
- ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
291
+ changeId: autoCorrectResult.changeId,
292
+ },
293
+ architecture: {
294
+ passed: architecturePassed,
295
+ totalViolations: architectureReport.totalViolations,
296
+ bySeverity: architectureReport.bySeverity,
297
+ violations: architectureViolations,
298
+ },
299
+ legacy: {
300
+ passed: autoCorrectResult.fixed,
301
+ violations: autoCorrectResult.remainingViolations.length,
302
+ },
303
+ ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
304
+ };
305
+ }
306
+
307
+ return {
308
+ passed: false,
309
+ violations: combinedViolations,
310
+ message: `Found ${blockingViolationCount} violation(s)`,
311
+ architecture: {
312
+ passed: architecturePassed,
313
+ totalViolations: architectureReport.totalViolations,
314
+ bySeverity: architectureReport.bySeverity,
315
+ violations: architectureViolations,
316
+ },
317
+ legacy: {
318
+ passed: checkResult.passed,
319
+ violations: legacyViolations.length,
320
+ },
321
+ tip: "Use autoCorrect: true to attempt automatic fixes",
322
+ relatedSkills: ["mandu-guard-guide", "mandu-debug"],
323
+ ...(typeAwareResponse ? { typeAware: typeAwareResponse } : {}),
324
324
  };
325
325
  },
326
326
 
@@ -11,9 +11,9 @@ import { mcpToolRegistry } from "../registry/mcp-tool-registry.js";
11
11
  import { moduleToPlugins } from "../adapters/tool-adapter.js";
12
12
  import { type McpProfile, getProfileCategories } from "../profiles.js";
13
13
 
14
- // 도구 모듈 export
15
- export { agentTools, agentToolDefinitions } from "./agent.js";
16
- export { specTools, specToolDefinitions } from "./spec.js";
14
+ // 도구 모듈 export
15
+ export { agentTools, agentToolDefinitions } from "./agent.js";
16
+ export { specTools, specToolDefinitions } from "./spec.js";
17
17
  export { generateTools, generateToolDefinitions } from "./generate.js";
18
18
  export { transactionTools, transactionToolDefinitions } from "./transaction.js";
19
19
  export { historyTools, historyToolDefinitions } from "./history.js";
@@ -86,9 +86,9 @@ export {
86
86
  extractContractToolDefinitions,
87
87
  } from "./extract-contract.js";
88
88
 
89
- // 도구 모듈 import (등록용)
90
- import { agentTools, agentToolDefinitions } from "./agent.js";
91
- import { specTools, specToolDefinitions } from "./spec.js";
89
+ // 도구 모듈 import (등록용)
90
+ import { agentTools, agentToolDefinitions } from "./agent.js";
91
+ import { specTools, specToolDefinitions } from "./spec.js";
92
92
  import { generateTools, generateToolDefinitions } from "./generate.js";
93
93
  import { transactionTools, transactionToolDefinitions } from "./transaction.js";
94
94
  import { historyTools, historyToolDefinitions } from "./history.js";
@@ -164,10 +164,10 @@ import {
164
164
  /**
165
165
  * 도구 모듈 정보
166
166
  */
167
- export interface ToolModule {
168
- category: string;
169
- definitions: Tool[];
170
- handlers: (
167
+ export interface ToolModule {
168
+ category: string;
169
+ definitions: Tool[];
170
+ handlers: (
171
171
  projectRoot: string,
172
172
  server?: Server,
173
173
  monitor?: ActivityMonitor
@@ -190,9 +190,9 @@ export interface ToolModule {
190
190
  /**
191
191
  * 빌트인 도구 모듈 목록
192
192
  */
193
- export const TOOL_MODULES: ToolModule[] = [
194
- { category: "agent", definitions: agentToolDefinitions, handlers: agentTools },
195
- { category: "spec", definitions: specToolDefinitions, handlers: specTools },
193
+ export const TOOL_MODULES: ToolModule[] = [
194
+ { category: "agent", definitions: agentToolDefinitions, handlers: agentTools },
195
+ { category: "spec", definitions: specToolDefinitions, handlers: specTools },
196
196
  { category: "generate", definitions: generateToolDefinitions, handlers: generateTools },
197
197
  { category: "transaction", definitions: transactionToolDefinitions, handlers: transactionTools },
198
198
  { category: "history", definitions: historyToolDefinitions, handlers: historyTools },
@@ -203,18 +203,18 @@ export const TOOL_MODULES: ToolModule[] = [
203
203
  { category: "slot", definitions: slotToolDefinitions, handlers: slotTools },
204
204
  { category: "hydration", definitions: hydrationToolDefinitions, handlers: hydrationTools },
205
205
  { category: "contract", definitions: contractToolDefinitions, handlers: contractTools },
206
- { category: "brain", definitions: brainToolDefinitions, handlers: brainTools, requiresServer: true },
206
+ { category: "brain", definitions: brainToolDefinitions, handlers: brainTools, requiresServer: true },
207
207
  { category: "runtime", definitions: runtimeToolDefinitions, handlers: runtimeTools },
208
208
  { category: "seo", definitions: seoToolDefinitions, handlers: seoTools },
209
- { category: "project", definitions: projectToolDefinitions, handlers: projectTools, requiresServer: true },
209
+ { category: "project", definitions: projectToolDefinitions, handlers: projectTools, requiresServer: true },
210
210
  // ate + ate-run accept an optional Server so notifications/progress
211
211
  // can flow (issue #238). `acceptsServer: true` forwards the server
212
212
  // when available but still registers when it isn't — callers that
213
213
  // boot without an MCP transport get progress no-oped silently.
214
- { category: "ate", definitions: ateToolDefinitions, handlers: ateTools, acceptsServer: true },
215
- { category: "ate-phase5", definitions: atePhase5ToolDefinitions, handlers: createAtePhase5Handlers },
214
+ { category: "ate", definitions: ateToolDefinitions, handlers: ateTools, acceptsServer: true },
215
+ { category: "ate-phase5", definitions: atePhase5ToolDefinitions, handlers: createAtePhase5Handlers },
216
216
  { category: "ate-context", definitions: ateContextToolDefinitions, handlers: ateContextTools },
217
- { category: "ate-run", definitions: ateRunToolDefinitions, handlers: ateRunTools, acceptsServer: true },
217
+ { category: "ate-run", definitions: ateRunToolDefinitions, handlers: ateRunTools, acceptsServer: true },
218
218
  { category: "ate-flakes", definitions: ateFlakesToolDefinitions, handlers: ateFlakesTools },
219
219
  { category: "ate-prompt", definitions: atePromptToolDefinitions, handlers: atePromptTools },
220
220
  { category: "ate-exemplar", definitions: ateExemplarToolDefinitions, handlers: ateExemplarTools },
@@ -285,41 +285,41 @@ export const TOOL_MODULES: ToolModule[] = [
285
285
  definitions: extractContractToolDefinitions,
286
286
  handlers: extractContractTools,
287
287
  },
288
- ];
289
-
290
- export function validateBuiltinToolModules(
291
- modules: readonly ToolModule[] = TOOL_MODULES
292
- ): string[] {
293
- const issues: string[] = [];
294
- const categories = new Set<string>();
295
- const toolNames = new Map<string, string>();
296
-
297
- for (const module of modules) {
298
- if (categories.has(module.category)) {
299
- issues.push(`duplicate tool category: ${module.category}`);
300
- }
301
- categories.add(module.category);
302
-
303
- if (module.definitions.length === 0) {
304
- issues.push(`tool category has no definitions: ${module.category}`);
305
- }
306
-
307
- for (const definition of module.definitions) {
308
- const previousCategory = toolNames.get(definition.name);
309
- if (previousCategory) {
310
- issues.push(
311
- `duplicate tool definition: ${definition.name} in ${previousCategory} and ${module.category}`
312
- );
313
- }
314
- toolNames.set(definition.name, module.category);
315
- }
316
- }
317
-
318
- return issues;
319
- }
320
-
321
- /**
322
- * 빌트인 도구들을 레지스트리에 등록
288
+ ];
289
+
290
+ export function validateBuiltinToolModules(
291
+ modules: readonly ToolModule[] = TOOL_MODULES
292
+ ): string[] {
293
+ const issues: string[] = [];
294
+ const categories = new Set<string>();
295
+ const toolNames = new Map<string, string>();
296
+
297
+ for (const module of modules) {
298
+ if (categories.has(module.category)) {
299
+ issues.push(`duplicate tool category: ${module.category}`);
300
+ }
301
+ categories.add(module.category);
302
+
303
+ if (module.definitions.length === 0) {
304
+ issues.push(`tool category has no definitions: ${module.category}`);
305
+ }
306
+
307
+ for (const definition of module.definitions) {
308
+ const previousCategory = toolNames.get(definition.name);
309
+ if (previousCategory) {
310
+ issues.push(
311
+ `duplicate tool definition: ${definition.name} in ${previousCategory} and ${module.category}`
312
+ );
313
+ }
314
+ toolNames.set(definition.name, module.category);
315
+ }
316
+ }
317
+
318
+ return issues;
319
+ }
320
+
321
+ /**
322
+ * 빌트인 도구들을 레지스트리에 등록
323
323
  *
324
324
  * @param projectRoot - 프로젝트 루트 경로
325
325
  * @param server - MCP Server 인스턴스 (선택, brain/project 도구에 필요)
@@ -340,15 +340,15 @@ export function registerBuiltinTools(
340
340
  monitor?: ActivityMonitor,
341
341
  options?: { profile?: McpProfile }
342
342
  ): void {
343
- const allowedCategories = options?.profile
344
- ? getProfileCategories(options.profile)
345
- : null;
346
- const definitionIssues = validateBuiltinToolModules();
347
- if (definitionIssues.length > 0) {
348
- throw new Error(`Invalid MCP tool module registry:\n${definitionIssues.join("\n")}`);
349
- }
350
-
351
- for (const module of TOOL_MODULES) {
343
+ const allowedCategories = options?.profile
344
+ ? getProfileCategories(options.profile)
345
+ : null;
346
+ const definitionIssues = validateBuiltinToolModules();
347
+ if (definitionIssues.length > 0) {
348
+ throw new Error(`Invalid MCP tool module registry:\n${definitionIssues.join("\n")}`);
349
+ }
350
+
351
+ for (const module of TOOL_MODULES) {
352
352
  // Profile filtering: skip categories not in the allowed list
353
353
  if (allowedCategories && !allowedCategories.includes(module.category)) {
354
354
  continue;
@@ -359,13 +359,13 @@ export function registerBuiltinTools(
359
359
  continue;
360
360
  }
361
361
 
362
- try {
363
- let handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>>;
364
- if (module.requiresServer) {
365
- handlers = module.handlers(projectRoot, server, monitor);
366
- } else if (module.acceptsServer) {
367
- // Forward the Server when available; fall back to just projectRoot.
368
- handlers = server
362
+ try {
363
+ let handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>>;
364
+ if (module.requiresServer) {
365
+ handlers = module.handlers(projectRoot, server, monitor);
366
+ } else if (module.acceptsServer) {
367
+ // Forward the Server when available; fall back to just projectRoot.
368
+ handlers = server
369
369
  ? module.handlers(projectRoot, server)
370
370
  : module.handlers(projectRoot);
371
371
  } else {