@mandujs/mcp 0.9.10 → 0.9.12
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 +41 -41
- package/src/resources/handlers.ts +52 -0
- package/src/server.ts +2 -1
- package/src/tools/brain.ts +73 -2
package/package.json
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mandujs/mcp",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./src/index.ts",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mandu-mcp": "./src/index.ts"
|
|
9
|
-
},
|
|
10
|
-
"exports": {
|
|
11
|
-
".": "./src/index.ts"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"src/**/*"
|
|
15
|
-
],
|
|
16
|
-
"keywords": [
|
|
17
|
-
"mandu",
|
|
18
|
-
"mcp",
|
|
19
|
-
"model-context-protocol",
|
|
20
|
-
"ai",
|
|
21
|
-
"agent",
|
|
22
|
-
"code-generation"
|
|
23
|
-
],
|
|
24
|
-
"repository": {
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "https://github.com/konamgil/mandu.git",
|
|
27
|
-
"directory": "packages/mcp"
|
|
28
|
-
},
|
|
29
|
-
"author": "konamgil",
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"publishConfig": {
|
|
32
|
-
"access": "public"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@mandujs/core": "^0.9.
|
|
36
|
-
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
37
|
-
},
|
|
38
|
-
"engines": {
|
|
39
|
-
"bun": ">=1.0.0"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mandujs/mcp",
|
|
3
|
+
"version": "0.9.12",
|
|
4
|
+
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mandu-mcp": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src/**/*"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mandu",
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"ai",
|
|
21
|
+
"agent",
|
|
22
|
+
"code-generation"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/konamgil/mandu.git",
|
|
27
|
+
"directory": "packages/mcp"
|
|
28
|
+
},
|
|
29
|
+
"author": "konamgil",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@mandujs/core": "^0.9.12",
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"bun": ">=1.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { Resource } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
2
|
import {
|
|
3
3
|
loadManifest,
|
|
4
4
|
getTransactionStatus,
|
|
5
|
+
getWatcher,
|
|
5
6
|
type GeneratedMap,
|
|
6
7
|
type SpecLock,
|
|
7
8
|
} from "@mandujs/core";
|
|
@@ -39,6 +40,18 @@ export const resourceDefinitions: Resource[] = [
|
|
|
39
40
|
description: "Slot file content for a specific route",
|
|
40
41
|
mimeType: "text/typescript",
|
|
41
42
|
},
|
|
43
|
+
{
|
|
44
|
+
uri: "mandu://watch/warnings",
|
|
45
|
+
name: "Watch Warnings",
|
|
46
|
+
description: "Recent file watcher warnings (architecture rule violations)",
|
|
47
|
+
mimeType: "application/json",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
uri: "mandu://watch/status",
|
|
51
|
+
name: "Watch Status",
|
|
52
|
+
description: "File watcher status (active/inactive, uptime, rule count)",
|
|
53
|
+
mimeType: "application/json",
|
|
54
|
+
},
|
|
42
55
|
];
|
|
43
56
|
|
|
44
57
|
type ResourceHandler = (params: Record<string, string>) => Promise<unknown>;
|
|
@@ -172,5 +185,44 @@ export function resourceHandlers(
|
|
|
172
185
|
content,
|
|
173
186
|
};
|
|
174
187
|
},
|
|
188
|
+
|
|
189
|
+
"mandu://watch/warnings": async () => {
|
|
190
|
+
const watcher = getWatcher();
|
|
191
|
+
if (!watcher) {
|
|
192
|
+
return { active: false, warnings: [] };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const warnings = watcher.getRecentWarnings(50);
|
|
196
|
+
return {
|
|
197
|
+
active: true,
|
|
198
|
+
count: warnings.length,
|
|
199
|
+
warnings: warnings.map((w) => ({
|
|
200
|
+
ruleId: w.ruleId,
|
|
201
|
+
file: w.file,
|
|
202
|
+
message: w.message,
|
|
203
|
+
event: w.event,
|
|
204
|
+
timestamp: w.timestamp.toISOString(),
|
|
205
|
+
})),
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
"mandu://watch/status": async () => {
|
|
210
|
+
const watcher = getWatcher();
|
|
211
|
+
if (!watcher) {
|
|
212
|
+
return { active: false };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const status = watcher.getStatus();
|
|
216
|
+
return {
|
|
217
|
+
active: status.active,
|
|
218
|
+
rootDir: status.rootDir,
|
|
219
|
+
fileCount: status.fileCount,
|
|
220
|
+
warningCount: status.recentWarnings.length,
|
|
221
|
+
uptime: status.startedAt
|
|
222
|
+
? Math.floor((Date.now() - status.startedAt.getTime()) / 1000)
|
|
223
|
+
: 0,
|
|
224
|
+
startedAt: status.startedAt?.toISOString() || null,
|
|
225
|
+
};
|
|
226
|
+
},
|
|
175
227
|
};
|
|
176
228
|
}
|
package/src/server.ts
CHANGED
|
@@ -36,6 +36,7 @@ export class ManduMcpServer {
|
|
|
36
36
|
capabilities: {
|
|
37
37
|
tools: {},
|
|
38
38
|
resources: {},
|
|
39
|
+
logging: {},
|
|
39
40
|
},
|
|
40
41
|
}
|
|
41
42
|
);
|
|
@@ -68,7 +69,7 @@ export class ManduMcpServer {
|
|
|
68
69
|
...slotTools(this.projectRoot),
|
|
69
70
|
...hydrationTools(this.projectRoot),
|
|
70
71
|
...contractTools(this.projectRoot),
|
|
71
|
-
...brainTools(this.projectRoot),
|
|
72
|
+
...brainTools(this.projectRoot, this.server),
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
|
package/src/tools/brain.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
14
15
|
import {
|
|
15
16
|
loadManifest,
|
|
16
17
|
runGuardCheck,
|
|
@@ -69,6 +70,16 @@ export const brainToolDefinitions: Tool[] = [
|
|
|
69
70
|
required: [],
|
|
70
71
|
},
|
|
71
72
|
},
|
|
73
|
+
{
|
|
74
|
+
name: "mandu_watch_stop",
|
|
75
|
+
description:
|
|
76
|
+
"Stop file watching and clean up MCP notification subscriptions.",
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {},
|
|
80
|
+
required: [],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
72
83
|
// Architecture tools (v0.2)
|
|
73
84
|
{
|
|
74
85
|
name: "mandu_check_location",
|
|
@@ -126,7 +137,10 @@ export const brainToolDefinitions: Tool[] = [
|
|
|
126
137
|
},
|
|
127
138
|
];
|
|
128
139
|
|
|
129
|
-
|
|
140
|
+
/** Module-level unsubscribe handle for MCP warning notifications */
|
|
141
|
+
let mcpWarningUnsubscribe: (() => void) | null = null;
|
|
142
|
+
|
|
143
|
+
export function brainTools(projectRoot: string, server?: Server) {
|
|
130
144
|
const paths = getProjectPaths(projectRoot);
|
|
131
145
|
|
|
132
146
|
return {
|
|
@@ -221,11 +235,45 @@ export function brainTools(projectRoot: string) {
|
|
|
221
235
|
debounceMs,
|
|
222
236
|
});
|
|
223
237
|
|
|
238
|
+
// Register MCP notification handler
|
|
239
|
+
let notifications = false;
|
|
240
|
+
if (server) {
|
|
241
|
+
// Clean up previous subscription
|
|
242
|
+
if (mcpWarningUnsubscribe) {
|
|
243
|
+
mcpWarningUnsubscribe();
|
|
244
|
+
mcpWarningUnsubscribe = null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
mcpWarningUnsubscribe = watcher.onWarning((warning) => {
|
|
248
|
+
// Push logging message (Claude Code receives in real-time)
|
|
249
|
+
server.sendLoggingMessage({
|
|
250
|
+
level: "warning",
|
|
251
|
+
logger: "mandu-watch",
|
|
252
|
+
data: {
|
|
253
|
+
type: "watch_warning",
|
|
254
|
+
ruleId: warning.ruleId,
|
|
255
|
+
file: warning.file,
|
|
256
|
+
message: warning.message,
|
|
257
|
+
event: warning.event,
|
|
258
|
+
timestamp: warning.timestamp.toISOString(),
|
|
259
|
+
},
|
|
260
|
+
}).catch(() => {});
|
|
261
|
+
|
|
262
|
+
// Resource update notification
|
|
263
|
+
server.sendResourceUpdated({
|
|
264
|
+
uri: "mandu://watch/warnings",
|
|
265
|
+
}).catch(() => {});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
notifications = true;
|
|
269
|
+
}
|
|
270
|
+
|
|
224
271
|
const status = watcher.getStatus();
|
|
225
272
|
|
|
226
273
|
return {
|
|
227
274
|
success: true,
|
|
228
275
|
message: "Watch started successfully",
|
|
276
|
+
notifications: notifications ? "enabled" : "disabled",
|
|
229
277
|
status: {
|
|
230
278
|
active: status.active,
|
|
231
279
|
rootDir: status.rootDir,
|
|
@@ -239,7 +287,8 @@ export function brainTools(projectRoot: string) {
|
|
|
239
287
|
"CONTRACT_NAMING - Contract 파일 네이밍 규칙",
|
|
240
288
|
"FORBIDDEN_IMPORT - Generated 파일의 금지된 import 감지",
|
|
241
289
|
],
|
|
242
|
-
|
|
290
|
+
logFile: ".mandu/watch.log",
|
|
291
|
+
tip: "Run `tail -f .mandu/watch.log` in another terminal for real-time warnings.",
|
|
243
292
|
};
|
|
244
293
|
} catch (error) {
|
|
245
294
|
return {
|
|
@@ -288,6 +337,28 @@ export function brainTools(projectRoot: string) {
|
|
|
288
337
|
}
|
|
289
338
|
},
|
|
290
339
|
|
|
340
|
+
mandu_watch_stop: async () => {
|
|
341
|
+
try {
|
|
342
|
+
// Clean up MCP notification subscription
|
|
343
|
+
if (mcpWarningUnsubscribe) {
|
|
344
|
+
mcpWarningUnsubscribe();
|
|
345
|
+
mcpWarningUnsubscribe = null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
stopWatcher();
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
success: true,
|
|
352
|
+
message: "Watch stopped and notifications cleaned up",
|
|
353
|
+
};
|
|
354
|
+
} catch (error) {
|
|
355
|
+
return {
|
|
356
|
+
error: "Failed to stop watch",
|
|
357
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
|
|
291
362
|
// Architecture tools (v0.2)
|
|
292
363
|
mandu_check_location: async (args: Record<string, unknown>) => {
|
|
293
364
|
const { path: filePath, content } = args as {
|