@mandujs/mcp 0.9.17 → 0.9.19

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.17",
3
+ "version": "0.9.19",
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.17",
35
+ "@mandujs/core": "^0.9.25",
36
36
  "@modelcontextprotocol/sdk": "^1.25.3"
37
37
  },
38
38
  "engines": {
@@ -1,231 +1,231 @@
1
- /**
2
- * Mandu Activity Monitor
3
- *
4
- * Real-time terminal dashboard for MCP server activity.
5
- * Opens automatically when the MCP server starts.
6
- * Shows all tool calls, watch events, errors, and agent behavior.
7
- */
8
-
9
- import fs from "fs";
10
- import path from "path";
11
- import { spawn, type ChildProcess } from "child_process";
12
-
13
- const TOOL_ICONS: Record<string, string> = {
14
- // Spec
15
- mandu_list_routes: "SPEC",
16
- mandu_get_route: "SPEC",
17
- mandu_add_route: "SPEC+",
18
- mandu_update_route: "SPEC~",
19
- mandu_delete_route: "SPEC-",
20
- mandu_validate_spec: "SPEC?",
21
- // Generate
22
- mandu_generate: "GEN",
23
- mandu_generate_status: "GEN?",
24
- // Guard
25
- mandu_guard_check: "GUARD",
26
- // Slot
27
- mandu_read_slot: "SLOT",
28
- mandu_write_slot: "SLOT~",
29
- mandu_validate_slot: "SLOT?",
30
- // Contract
31
- mandu_list_contracts: "CONTRACT",
32
- mandu_get_contract: "CONTRACT",
33
- mandu_create_contract: "CONTRACT+",
34
- mandu_validate_contracts: "CONTRACT?",
35
- mandu_sync_contract_slot: "SYNC",
36
- mandu_generate_openapi: "OPENAPI",
37
- mandu_update_route_contract: "CONTRACT~",
38
- // Transaction
39
- mandu_begin: "TX-BEGIN",
40
- mandu_commit: "TX-COMMIT",
41
- mandu_rollback: "TX-ROLLBACK",
42
- mandu_tx_status: "TX?",
43
- // History
44
- mandu_list_history: "HISTORY",
45
- mandu_get_snapshot: "SNAPSHOT",
46
- mandu_prune_history: "PRUNE",
47
- // Brain
48
- mandu_doctor: "DOCTOR",
49
- mandu_watch_start: "WATCH+",
50
- mandu_watch_status: "WATCH?",
51
- mandu_watch_stop: "WATCH-",
52
- mandu_check_location: "ARCH?",
53
- mandu_check_import: "IMPORT?",
54
- mandu_get_architecture: "ARCH",
55
- // Build
56
- mandu_build: "BUILD",
57
- mandu_build_status: "BUILD?",
58
- mandu_list_islands: "ISLAND",
59
- mandu_set_hydration: "HYDRA~",
60
- mandu_add_client_slot: "CLIENT+",
61
- // Error
62
- mandu_analyze_error: "ERROR",
63
- };
64
-
65
- function getTime(): string {
66
- return new Date().toLocaleTimeString("ko-KR", { hour12: false });
67
- }
68
-
69
- function summarizeArgs(args: Record<string, unknown> | null | undefined): string {
70
- if (!args || Object.keys(args).length === 0) return "";
71
- const entries = Object.entries(args)
72
- .filter(([_, v]) => v !== undefined && v !== null)
73
- .map(([k, v]) => {
74
- const val = typeof v === "string"
75
- ? (v.length > 40 ? v.slice(0, 40) + "..." : v)
76
- : JSON.stringify(v);
77
- return `${k}=${val}`;
78
- });
79
- return entries.length > 0 ? ` (${entries.join(", ")})` : "";
80
- }
81
-
82
- function summarizeResult(result: unknown): string {
83
- if (!result || typeof result !== "object") return "";
84
- const obj = result as Record<string, unknown>;
85
-
86
- // Common patterns
87
- if (obj.error) return ` >> ERROR: ${obj.error}`;
88
- if (obj.success === true) return obj.message ? ` >> ${obj.message}` : " >> OK";
89
- if (obj.success === false) return ` >> FAILED: ${obj.message || "unknown"}`;
90
- if (Array.isArray(obj.routes)) return ` >> ${obj.routes.length} routes`;
91
- if (obj.passed === true) return obj.message ? ` >> ${obj.message}` : " >> PASSED";
92
- if (obj.passed === false) return ` >> FAILED (${(obj.violations as unknown[])?.length || 0} violations)`;
93
- if (obj.valid === true) return obj.message ? ` >> ${obj.message}` : " >> VALID";
94
- if (obj.valid === false) return ` >> INVALID (${(obj.violations as unknown[])?.length || 0} violations)`;
95
- if (obj.generated) return " >> Generated";
96
- if (obj.status) return ` >> ${JSON.stringify(obj.status).slice(0, 60)}`;
97
-
98
- return "";
99
- }
100
-
101
- export class ActivityMonitor {
102
- private logFile: string;
103
- private logStream: fs.WriteStream | null = null;
104
- private tailProcess: ChildProcess | null = null;
105
- private projectRoot: string;
106
- private callCount = 0;
107
-
108
- constructor(projectRoot: string) {
109
- this.projectRoot = projectRoot;
110
- const manduDir = path.join(projectRoot, ".mandu");
111
- if (!fs.existsSync(manduDir)) {
112
- fs.mkdirSync(manduDir, { recursive: true });
113
- }
114
- this.logFile = path.join(manduDir, "activity.log");
115
- }
116
-
117
- start(): void {
118
- // Create/overwrite log file
119
- this.logStream = fs.createWriteStream(this.logFile, { flags: "w" });
120
-
121
- const time = getTime();
122
- const header =
123
- `\n` +
124
- ` ╔══════════════════════════════════════════════╗\n` +
125
- ` ║ MANDU MCP Activity Monitor ║\n` +
126
- ` ║ ║\n` +
127
- ` ║ ${time} ║\n` +
128
- ` ║ ${this.projectRoot.slice(-40).padEnd(40)} ║\n` +
129
- ` ╚══════════════════════════════════════════════╝\n\n`;
130
-
131
- this.logStream.write(header);
132
-
133
- // Auto-open terminal
134
- this.openTerminal();
135
- }
136
-
137
- stop(): void {
138
- if (this.tailProcess) {
139
- this.tailProcess.kill();
140
- this.tailProcess = null;
141
- }
142
- if (this.logStream) {
143
- this.logStream.end();
144
- this.logStream = null;
145
- }
146
- }
147
-
148
- /**
149
- * Log a tool call (invocation)
150
- */
151
- logTool(
152
- name: string,
153
- args?: Record<string, unknown> | null,
154
- _result?: unknown,
155
- error?: string,
156
- ): void {
157
- this.callCount++;
158
- const time = getTime();
159
- const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
160
- const argsStr = summarizeArgs(args);
161
-
162
- let line: string;
163
- if (error) {
164
- line = `${time} ✗ [${tag}]${argsStr}\n ERROR: ${error}\n`;
165
- } else {
166
- line = `${time} → [${tag}]${argsStr}\n`;
167
- }
168
-
169
- this.write(line);
170
- }
171
-
172
- /**
173
- * Log a tool result
174
- */
175
- logResult(name: string, result: unknown): void {
176
- const time = getTime();
177
- const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
178
- const summary = summarizeResult(result);
179
-
180
- if (summary) {
181
- this.write(`${time} ✓ [${tag}]${summary}\n`);
182
- }
183
- }
184
-
185
- /**
186
- * Log a watch event (called from watcher)
187
- */
188
- logWatch(level: string, ruleId: string, file: string, message: string): void {
189
- const time = getTime();
190
- const icon = level === "info" ? "ℹ" : "⚠";
191
- this.write(`${time} ${icon} [WATCH:${ruleId}] ${file}\n ${message}\n`);
192
- }
193
-
194
- /**
195
- * Log a custom event
196
- */
197
- logEvent(category: string, message: string): void {
198
- const time = getTime();
199
- this.write(`${time} [${category}] ${message}\n`);
200
- }
201
-
202
- private write(text: string): void {
203
- if (this.logStream) {
204
- this.logStream.write(text);
205
- }
206
- }
207
-
208
- private openTerminal(): void {
209
- try {
210
- if (process.platform === "win32") {
211
- this.tailProcess = spawn("cmd", [
212
- "/c", "start",
213
- "Mandu Activity Monitor",
214
- "powershell", "-NoExit", "-Command",
215
- `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; Get-Content '${this.logFile}' -Wait -Encoding UTF8`,
216
- ], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
217
- } else if (process.platform === "darwin") {
218
- this.tailProcess = spawn("osascript", [
219
- "-e", `tell application "Terminal" to do script "tail -f '${this.logFile}'"`,
220
- ], { detached: true, stdio: "ignore" });
221
- } else {
222
- this.tailProcess = spawn("x-terminal-emulator", [
223
- "-e", `tail -f '${this.logFile}'`,
224
- ], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
225
- }
226
- this.tailProcess?.unref();
227
- } catch {
228
- // Terminal auto-open failed silently
229
- }
230
- }
231
- }
1
+ /**
2
+ * Mandu Activity Monitor
3
+ *
4
+ * Real-time terminal dashboard for MCP server activity.
5
+ * Opens automatically when the MCP server starts.
6
+ * Shows all tool calls, watch events, errors, and agent behavior.
7
+ */
8
+
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import { spawn, type ChildProcess } from "child_process";
12
+
13
+ const TOOL_ICONS: Record<string, string> = {
14
+ // Spec
15
+ mandu_list_routes: "SPEC",
16
+ mandu_get_route: "SPEC",
17
+ mandu_add_route: "SPEC+",
18
+ mandu_update_route: "SPEC~",
19
+ mandu_delete_route: "SPEC-",
20
+ mandu_validate_spec: "SPEC?",
21
+ // Generate
22
+ mandu_generate: "GEN",
23
+ mandu_generate_status: "GEN?",
24
+ // Guard
25
+ mandu_guard_check: "GUARD",
26
+ // Slot
27
+ mandu_read_slot: "SLOT",
28
+ mandu_write_slot: "SLOT~",
29
+ mandu_validate_slot: "SLOT?",
30
+ // Contract
31
+ mandu_list_contracts: "CONTRACT",
32
+ mandu_get_contract: "CONTRACT",
33
+ mandu_create_contract: "CONTRACT+",
34
+ mandu_validate_contracts: "CONTRACT?",
35
+ mandu_sync_contract_slot: "SYNC",
36
+ mandu_generate_openapi: "OPENAPI",
37
+ mandu_update_route_contract: "CONTRACT~",
38
+ // Transaction
39
+ mandu_begin: "TX-BEGIN",
40
+ mandu_commit: "TX-COMMIT",
41
+ mandu_rollback: "TX-ROLLBACK",
42
+ mandu_tx_status: "TX?",
43
+ // History
44
+ mandu_list_history: "HISTORY",
45
+ mandu_get_snapshot: "SNAPSHOT",
46
+ mandu_prune_history: "PRUNE",
47
+ // Brain
48
+ mandu_doctor: "DOCTOR",
49
+ mandu_watch_start: "WATCH+",
50
+ mandu_watch_status: "WATCH?",
51
+ mandu_watch_stop: "WATCH-",
52
+ mandu_check_location: "ARCH?",
53
+ mandu_check_import: "IMPORT?",
54
+ mandu_get_architecture: "ARCH",
55
+ // Build
56
+ mandu_build: "BUILD",
57
+ mandu_build_status: "BUILD?",
58
+ mandu_list_islands: "ISLAND",
59
+ mandu_set_hydration: "HYDRA~",
60
+ mandu_add_client_slot: "CLIENT+",
61
+ // Error
62
+ mandu_analyze_error: "ERROR",
63
+ };
64
+
65
+ function getTime(): string {
66
+ return new Date().toLocaleTimeString("ko-KR", { hour12: false });
67
+ }
68
+
69
+ function summarizeArgs(args: Record<string, unknown> | null | undefined): string {
70
+ if (!args || Object.keys(args).length === 0) return "";
71
+ const entries = Object.entries(args)
72
+ .filter(([_, v]) => v !== undefined && v !== null)
73
+ .map(([k, v]) => {
74
+ const val = typeof v === "string"
75
+ ? (v.length > 40 ? v.slice(0, 40) + "..." : v)
76
+ : JSON.stringify(v);
77
+ return `${k}=${val}`;
78
+ });
79
+ return entries.length > 0 ? ` (${entries.join(", ")})` : "";
80
+ }
81
+
82
+ function summarizeResult(result: unknown): string {
83
+ if (!result || typeof result !== "object") return "";
84
+ const obj = result as Record<string, unknown>;
85
+
86
+ // Common patterns
87
+ if (obj.error) return ` >> ERROR: ${obj.error}`;
88
+ if (obj.success === true) return obj.message ? ` >> ${obj.message}` : " >> OK";
89
+ if (obj.success === false) return ` >> FAILED: ${obj.message || "unknown"}`;
90
+ if (Array.isArray(obj.routes)) return ` >> ${obj.routes.length} routes`;
91
+ if (obj.passed === true) return obj.message ? ` >> ${obj.message}` : " >> PASSED";
92
+ if (obj.passed === false) return ` >> FAILED (${(obj.violations as unknown[])?.length || 0} violations)`;
93
+ if (obj.valid === true) return obj.message ? ` >> ${obj.message}` : " >> VALID";
94
+ if (obj.valid === false) return ` >> INVALID (${(obj.violations as unknown[])?.length || 0} violations)`;
95
+ if (obj.generated) return " >> Generated";
96
+ if (obj.status) return ` >> ${JSON.stringify(obj.status).slice(0, 60)}`;
97
+
98
+ return "";
99
+ }
100
+
101
+ export class ActivityMonitor {
102
+ private logFile: string;
103
+ private logStream: fs.WriteStream | null = null;
104
+ private tailProcess: ChildProcess | null = null;
105
+ private projectRoot: string;
106
+ private callCount = 0;
107
+
108
+ constructor(projectRoot: string) {
109
+ this.projectRoot = projectRoot;
110
+ const manduDir = path.join(projectRoot, ".mandu");
111
+ if (!fs.existsSync(manduDir)) {
112
+ fs.mkdirSync(manduDir, { recursive: true });
113
+ }
114
+ this.logFile = path.join(manduDir, "activity.log");
115
+ }
116
+
117
+ start(): void {
118
+ // Create/overwrite log file
119
+ this.logStream = fs.createWriteStream(this.logFile, { flags: "w" });
120
+
121
+ const time = getTime();
122
+ const header =
123
+ `\n` +
124
+ ` ╔══════════════════════════════════════════════╗\n` +
125
+ ` ║ MANDU MCP Activity Monitor ║\n` +
126
+ ` ║ ║\n` +
127
+ ` ║ ${time} ║\n` +
128
+ ` ║ ${this.projectRoot.slice(-40).padEnd(40)} ║\n` +
129
+ ` ╚══════════════════════════════════════════════╝\n\n`;
130
+
131
+ this.logStream.write(header);
132
+
133
+ // Auto-open terminal
134
+ this.openTerminal();
135
+ }
136
+
137
+ stop(): void {
138
+ if (this.tailProcess) {
139
+ this.tailProcess.kill();
140
+ this.tailProcess = null;
141
+ }
142
+ if (this.logStream) {
143
+ this.logStream.end();
144
+ this.logStream = null;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Log a tool call (invocation)
150
+ */
151
+ logTool(
152
+ name: string,
153
+ args?: Record<string, unknown> | null,
154
+ _result?: unknown,
155
+ error?: string,
156
+ ): void {
157
+ this.callCount++;
158
+ const time = getTime();
159
+ const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
160
+ const argsStr = summarizeArgs(args);
161
+
162
+ let line: string;
163
+ if (error) {
164
+ line = `${time} ✗ [${tag}]${argsStr}\n ERROR: ${error}\n`;
165
+ } else {
166
+ line = `${time} → [${tag}]${argsStr}\n`;
167
+ }
168
+
169
+ this.write(line);
170
+ }
171
+
172
+ /**
173
+ * Log a tool result
174
+ */
175
+ logResult(name: string, result: unknown): void {
176
+ const time = getTime();
177
+ const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
178
+ const summary = summarizeResult(result);
179
+
180
+ if (summary) {
181
+ this.write(`${time} ✓ [${tag}]${summary}\n`);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Log a watch event (called from watcher)
187
+ */
188
+ logWatch(level: string, ruleId: string, file: string, message: string): void {
189
+ const time = getTime();
190
+ const icon = level === "info" ? "ℹ" : "⚠";
191
+ this.write(`${time} ${icon} [WATCH:${ruleId}] ${file}\n ${message}\n`);
192
+ }
193
+
194
+ /**
195
+ * Log a custom event
196
+ */
197
+ logEvent(category: string, message: string): void {
198
+ const time = getTime();
199
+ this.write(`${time} [${category}] ${message}\n`);
200
+ }
201
+
202
+ private write(text: string): void {
203
+ if (this.logStream) {
204
+ this.logStream.write(text);
205
+ }
206
+ }
207
+
208
+ private openTerminal(): void {
209
+ try {
210
+ if (process.platform === "win32") {
211
+ this.tailProcess = spawn("cmd", [
212
+ "/c", "start",
213
+ "Mandu Activity Monitor",
214
+ "powershell", "-NoExit", "-Command",
215
+ `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; Get-Content '${this.logFile}' -Wait -Encoding UTF8`,
216
+ ], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
217
+ } else if (process.platform === "darwin") {
218
+ this.tailProcess = spawn("osascript", [
219
+ "-e", `tell application "Terminal" to do script "tail -f '${this.logFile}'"`,
220
+ ], { detached: true, stdio: "ignore" });
221
+ } else {
222
+ this.tailProcess = spawn("x-terminal-emulator", [
223
+ "-e", `tail -f '${this.logFile}'`,
224
+ ], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
225
+ }
226
+ this.tailProcess?.unref();
227
+ } catch {
228
+ // Terminal auto-open failed silently
229
+ }
230
+ }
231
+ }
package/src/server.ts CHANGED
@@ -18,6 +18,7 @@ import { slotTools, slotToolDefinitions } from "./tools/slot.js";
18
18
  import { hydrationTools, hydrationToolDefinitions } from "./tools/hydration.js";
19
19
  import { contractTools, contractToolDefinitions } from "./tools/contract.js";
20
20
  import { brainTools, brainToolDefinitions } from "./tools/brain.js";
21
+ import { runtimeTools, runtimeToolDefinitions } from "./tools/runtime.js";
21
22
  import { resourceHandlers, resourceDefinitions } from "./resources/handlers.js";
22
23
  import { findProjectRoot } from "./utils/project.js";
23
24
  import { applyWarningInjection } from "./utils/withWarnings.js";
@@ -61,6 +62,7 @@ export class ManduMcpServer {
61
62
  ...hydrationToolDefinitions,
62
63
  ...contractToolDefinitions,
63
64
  ...brainToolDefinitions,
65
+ ...runtimeToolDefinitions,
64
66
  ];
65
67
  }
66
68
 
@@ -75,6 +77,7 @@ export class ManduMcpServer {
75
77
  ...hydrationTools(this.projectRoot),
76
78
  ...contractTools(this.projectRoot),
77
79
  ...brainTools(this.projectRoot, this.server, this.monitor),
80
+ ...runtimeTools(this.projectRoot),
78
81
  };
79
82
 
80
83
  return applyWarningInjection(handlers);
@@ -7,3 +7,4 @@ export { slotTools, slotToolDefinitions } from "./slot.js";
7
7
  export { hydrationTools, hydrationToolDefinitions } from "./hydration.js";
8
8
  export { contractTools, contractToolDefinitions } from "./contract.js";
9
9
  export { brainTools, brainToolDefinitions } from "./brain.js";
10
+ export { runtimeTools, runtimeToolDefinitions } from "./runtime.js";