@mandujs/mcp 0.9.15 → 0.9.17

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.9.15",
3
+ "version": "0.9.17",
4
4
  "description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@mandujs/core": "^0.9.15",
35
+ "@mandujs/core": "^0.9.17",
36
36
  "@modelcontextprotocol/sdk": "^1.25.3"
37
37
  },
38
38
  "engines": {
package/src/server.ts CHANGED
@@ -20,6 +20,7 @@ import { contractTools, contractToolDefinitions } from "./tools/contract.js";
20
20
  import { brainTools, brainToolDefinitions } from "./tools/brain.js";
21
21
  import { resourceHandlers, resourceDefinitions } from "./resources/handlers.js";
22
22
  import { findProjectRoot } from "./utils/project.js";
23
+ import { applyWarningInjection } from "./utils/withWarnings.js";
23
24
  import { ActivityMonitor } from "./activity-monitor.js";
24
25
  import { startWatcher } from "../../core/src/index.js";
25
26
 
@@ -64,7 +65,7 @@ export class ManduMcpServer {
64
65
  }
65
66
 
66
67
  private getAllToolHandlers(): Record<string, (args: Record<string, unknown>) => Promise<unknown>> {
67
- return {
68
+ const handlers = {
68
69
  ...specTools(this.projectRoot),
69
70
  ...generateTools(this.projectRoot),
70
71
  ...transactionTools(this.projectRoot),
@@ -75,6 +76,8 @@ export class ManduMcpServer {
75
76
  ...contractTools(this.projectRoot),
76
77
  ...brainTools(this.projectRoot, this.server, this.monitor),
77
78
  };
79
+
80
+ return applyWarningInjection(handlers);
78
81
  }
79
82
 
80
83
  private registerToolHandlers(): void {
@@ -221,10 +224,13 @@ export class ManduMcpServer {
221
224
  logger: "mandu-watch",
222
225
  data: {
223
226
  type: "watch_warning",
227
+ severity: warning.level || "warn",
224
228
  ruleId: warning.ruleId,
225
229
  file: warning.file,
226
230
  message: warning.message,
227
231
  event: warning.event,
232
+ agentAction: warning.agentAction || null,
233
+ agentCommand: warning.agentCommand || null,
228
234
  },
229
235
  }).catch(() => {});
230
236
  });
@@ -262,11 +262,14 @@ export function brainTools(projectRoot: string, server?: Server, monitor?: Activ
262
262
  logger: "mandu-watch",
263
263
  data: {
264
264
  type: "watch_warning",
265
+ severity: warning.level || "warn",
265
266
  ruleId: warning.ruleId,
266
267
  file: warning.file,
267
268
  message: warning.message,
268
269
  event: warning.event,
269
270
  timestamp: warning.timestamp.toISOString(),
271
+ agentAction: warning.agentAction || null,
272
+ agentCommand: warning.agentCommand || null,
270
273
  },
271
274
  }).catch(() => {});
272
275
 
@@ -318,8 +318,8 @@ export function hydrationTools(projectRoot: string) {
318
318
  };
319
319
  }
320
320
 
321
- // Create client slot file
322
- const clientModulePath = `spec/slots/${routeId}.client.ts`;
321
+ // Create client slot file in apps/web/components/ (not spec/slots/)
322
+ const clientModulePath = `apps/web/components/${routeId}.client.tsx`;
323
323
  const clientFilePath = path.join(projectRoot, clientModulePath);
324
324
 
325
325
  // Check if file already exists
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Watcher Warning Injection for Mutation Tools
3
+ *
4
+ * Mutation 도구(write_slot, add_route, generate 등) 실행 후
5
+ * watcher 경고를 자동으로 응답에 포함시킨다.
6
+ *
7
+ * MCP notification이 Claude Code에 전달되지 않는 문제를 해결.
8
+ */
9
+
10
+ import { getWatcher } from "../../../core/src/index.js";
11
+
12
+ const MUTATION_TOOLS = new Set([
13
+ "mandu_write_slot",
14
+ "mandu_add_route",
15
+ "mandu_update_route",
16
+ "mandu_delete_route",
17
+ "mandu_generate",
18
+ "mandu_build",
19
+ "mandu_commit",
20
+ "mandu_add_client_slot",
21
+ "mandu_set_hydration",
22
+ "mandu_create_contract",
23
+ "mandu_update_route_contract",
24
+ "mandu_sync_contract_slot",
25
+ ]);
26
+
27
+ /** watcher debounce(300ms) + 여유분 */
28
+ const WARNING_WAIT_MS = 400;
29
+
30
+ type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;
31
+
32
+ /**
33
+ * Mutation 도구 핸들러를 감싸서, 실행 후 발생한 watcher 경고를
34
+ * 응답 객체의 `_warnings` 필드에 자동 포함시킨다.
35
+ */
36
+ export function applyWarningInjection(
37
+ handlers: Record<string, ToolHandler>
38
+ ): Record<string, ToolHandler> {
39
+ const wrapped: Record<string, ToolHandler> = {};
40
+
41
+ for (const [name, handler] of Object.entries(handlers)) {
42
+ if (MUTATION_TOOLS.has(name)) {
43
+ wrapped[name] = wrapWithWarnings(handler);
44
+ } else {
45
+ wrapped[name] = handler;
46
+ }
47
+ }
48
+
49
+ return wrapped;
50
+ }
51
+
52
+ function wrapWithWarnings(handler: ToolHandler): ToolHandler {
53
+ return async (args: Record<string, unknown>) => {
54
+ const watcher = getWatcher();
55
+ const beforeCount = watcher?.getRecentWarnings(100).length ?? 0;
56
+
57
+ const result = await handler(args);
58
+
59
+ // watcher debounce 대기
60
+ await new Promise((resolve) => setTimeout(resolve, WARNING_WAIT_MS));
61
+
62
+ const allWarnings = watcher?.getRecentWarnings(100) ?? [];
63
+ const newWarnings = allWarnings.slice(beforeCount);
64
+
65
+ if (
66
+ newWarnings.length > 0 &&
67
+ typeof result === "object" &&
68
+ result !== null
69
+ ) {
70
+ return {
71
+ ...(result as Record<string, unknown>),
72
+ _warnings: newWarnings.map((w) => ({
73
+ ruleId: w.ruleId,
74
+ file: w.file,
75
+ message: w.message,
76
+ level: w.level ?? "warn",
77
+ })),
78
+ };
79
+ }
80
+
81
+ return result;
82
+ };
83
+ }