@mandujs/mcp 0.20.1 → 0.20.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.
- package/package.json +3 -3
- package/src/server.ts +90 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mandujs/mcp",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@mandujs/core": "^0.
|
|
37
|
+
"@mandujs/core": "^0.25.0",
|
|
38
38
|
"@mandujs/ate": "^0.19.1",
|
|
39
|
-
"@mandujs/skills": "^
|
|
39
|
+
"@mandujs/skills": "^5.0.0",
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
package/src/server.ts
CHANGED
|
@@ -58,6 +58,54 @@ import { type McpProfile, isValidProfile } from "./profiles.js";
|
|
|
58
58
|
*/
|
|
59
59
|
const MCP_VERSION = "0.12.0";
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Phase 17 — heap heartbeat interval (ms). Every tick we log
|
|
63
|
+
* `Bun.memoryUsage()` + RSS / heapUsed / external + uptime so operators
|
|
64
|
+
* tailing stderr can spot runaway growth without hooking a debugger.
|
|
65
|
+
*
|
|
66
|
+
* 5 minutes strikes a balance between "noisy enough to catch slow leaks"
|
|
67
|
+
* and "not spammy enough to drown the log" (288 lines/day). Override
|
|
68
|
+
* with `MANDU_MCP_HEAP_INTERVAL_MS` when running under stress tests.
|
|
69
|
+
*/
|
|
70
|
+
const DEFAULT_HEAP_LOG_INTERVAL_MS = 5 * 60 * 1000;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Emit a single heap-usage line to stderr. Called once on startup and
|
|
74
|
+
* again on every heartbeat tick.
|
|
75
|
+
*
|
|
76
|
+
* Format is plain KV — easy to grep / pipe through `awk`:
|
|
77
|
+
*
|
|
78
|
+
* [MCP heap] rss=142MB heapUsed=56MB heapTotal=80MB external=3MB uptime=310s
|
|
79
|
+
*
|
|
80
|
+
* Uses `Bun.memoryUsage()` when available (returns RSS in bytes + JSC
|
|
81
|
+
* gauges); falls back to `process.memoryUsage()` on Node test runners.
|
|
82
|
+
* Errors are swallowed — a memory probe must never take down the server.
|
|
83
|
+
*/
|
|
84
|
+
export function logMcpHeapUsage(label: string = "heap"): void {
|
|
85
|
+
try {
|
|
86
|
+
const mem = process.memoryUsage();
|
|
87
|
+
const bunGlobal = (globalThis as { Bun?: { memoryUsage?: () => Record<string, number> } }).Bun;
|
|
88
|
+
let rss = mem.rss;
|
|
89
|
+
let external = mem.external;
|
|
90
|
+
if (bunGlobal?.memoryUsage) {
|
|
91
|
+
try {
|
|
92
|
+
const bunMem = bunGlobal.memoryUsage();
|
|
93
|
+
if (typeof bunMem.rss === "number") rss = bunMem.rss;
|
|
94
|
+
if (typeof bunMem.external === "number") external = bunMem.external;
|
|
95
|
+
} catch {
|
|
96
|
+
// fall back to process.memoryUsage values
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const mb = (n: number) => `${Math.round(n / 1024 / 1024)}MB`;
|
|
100
|
+
const uptime = Math.round(process.uptime());
|
|
101
|
+
console.error(
|
|
102
|
+
`[MCP ${label}] rss=${mb(rss)} heapUsed=${mb(mem.heapUsed)} heapTotal=${mb(mem.heapTotal)} external=${mb(external)} uptime=${uptime}s`,
|
|
103
|
+
);
|
|
104
|
+
} catch {
|
|
105
|
+
// best-effort — never propagate
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
61
109
|
/**
|
|
62
110
|
* ManduMcpServer v2
|
|
63
111
|
*
|
|
@@ -71,6 +119,11 @@ export class ManduMcpServer {
|
|
|
71
119
|
private configWatcher?: McpConfigWatcher;
|
|
72
120
|
private toolExecutor: ToolExecutor;
|
|
73
121
|
private profile: McpProfile;
|
|
122
|
+
/**
|
|
123
|
+
* Phase 17 — 5-minute heap-usage heartbeat. Lazily started in `run()`
|
|
124
|
+
* and cleared by `stop()`. Disabled with `MANDU_MCP_HEAP_INTERVAL_MS=0`.
|
|
125
|
+
*/
|
|
126
|
+
private heapLogTimer: ReturnType<typeof setInterval> | null = null;
|
|
74
127
|
|
|
75
128
|
constructor(projectRoot: string) {
|
|
76
129
|
this.projectRoot = projectRoot;
|
|
@@ -344,6 +397,37 @@ export class ManduMcpServer {
|
|
|
344
397
|
console.error(` Project: ${this.projectRoot}`);
|
|
345
398
|
console.error(` Profile: ${this.profile}`);
|
|
346
399
|
console.error(` Tools: ${summary.total} (${summary.categories.join(", ")})`);
|
|
400
|
+
|
|
401
|
+
// Phase 17 — start the heap heartbeat. Startup line is tagged
|
|
402
|
+
// `startup` so operators can anchor before/after diffs to it.
|
|
403
|
+
logMcpHeapUsage("startup");
|
|
404
|
+
this.startHeapHeartbeat();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Phase 17 — configure the heap-usage heartbeat. Reads
|
|
409
|
+
* `MANDU_MCP_HEAP_INTERVAL_MS` for override (`0` = disabled).
|
|
410
|
+
* Idempotent: repeat calls replace the previous timer.
|
|
411
|
+
*/
|
|
412
|
+
private startHeapHeartbeat(): void {
|
|
413
|
+
if (this.heapLogTimer) {
|
|
414
|
+
clearInterval(this.heapLogTimer);
|
|
415
|
+
this.heapLogTimer = null;
|
|
416
|
+
}
|
|
417
|
+
const raw = process.env.MANDU_MCP_HEAP_INTERVAL_MS;
|
|
418
|
+
let intervalMs = DEFAULT_HEAP_LOG_INTERVAL_MS;
|
|
419
|
+
if (raw !== undefined) {
|
|
420
|
+
const parsed = Number(raw);
|
|
421
|
+
if (Number.isFinite(parsed) && parsed >= 0) intervalMs = parsed;
|
|
422
|
+
}
|
|
423
|
+
if (intervalMs === 0) return; // explicitly disabled
|
|
424
|
+
this.heapLogTimer = setInterval(() => logMcpHeapUsage("heartbeat"), intervalMs);
|
|
425
|
+
// `unref()` so the heartbeat never keeps the event loop alive on its
|
|
426
|
+
// own — `stop()` must actively clear it, but a forgotten stop should
|
|
427
|
+
// not hang the process.
|
|
428
|
+
if (typeof this.heapLogTimer.unref === "function") {
|
|
429
|
+
this.heapLogTimer.unref();
|
|
430
|
+
}
|
|
347
431
|
}
|
|
348
432
|
|
|
349
433
|
/**
|
|
@@ -353,6 +437,12 @@ export class ManduMcpServer {
|
|
|
353
437
|
// 설정 감시 중지
|
|
354
438
|
this.configWatcher?.stop();
|
|
355
439
|
|
|
440
|
+
// Phase 17 — stop the heap heartbeat. Safe to call when never started.
|
|
441
|
+
if (this.heapLogTimer) {
|
|
442
|
+
clearInterval(this.heapLogTimer);
|
|
443
|
+
this.heapLogTimer = null;
|
|
444
|
+
}
|
|
445
|
+
|
|
356
446
|
// 로깅 해제
|
|
357
447
|
teardownMcpLogging();
|
|
358
448
|
|