@leanmcp/core 0.3.8 → 0.3.9
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/dist/index.d.mts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +118 -0
- package/dist/index.mjs +118 -0
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -411,6 +411,7 @@ declare class MCPServer {
|
|
|
411
411
|
private options;
|
|
412
412
|
private initPromise;
|
|
413
413
|
private autoDiscovered;
|
|
414
|
+
private manifestWatcher;
|
|
414
415
|
constructor(options: MCPServerConstructorOptions);
|
|
415
416
|
/**
|
|
416
417
|
* Internal initialization - runs automatically in constructor
|
|
@@ -462,6 +463,14 @@ declare class MCPServer {
|
|
|
462
463
|
* Register a service instance with decorated methods
|
|
463
464
|
*/
|
|
464
465
|
registerService(instance: any): void;
|
|
466
|
+
/**
|
|
467
|
+
* Watch UI manifest for changes and reload resources dynamically
|
|
468
|
+
*/
|
|
469
|
+
private watchUIManifest;
|
|
470
|
+
/**
|
|
471
|
+
* Reload UI manifest and update resource registrations
|
|
472
|
+
*/
|
|
473
|
+
private reloadUIManifest;
|
|
465
474
|
/**
|
|
466
475
|
* Load UI manifest and auto-register resources for pre-built @UIApp components.
|
|
467
476
|
* The manifest is generated by `leanmcp dev` or `leanmcp start` commands.
|
|
@@ -511,6 +520,10 @@ declare class MCPServer {
|
|
|
511
520
|
} | undefined;
|
|
512
521
|
} | undefined;
|
|
513
522
|
}>;
|
|
523
|
+
/**
|
|
524
|
+
* Cleanup resources (call on server shutdown)
|
|
525
|
+
*/
|
|
526
|
+
cleanup(): Promise<void>;
|
|
514
527
|
}
|
|
515
528
|
declare class MCPServerRuntime {
|
|
516
529
|
private server;
|
package/dist/index.d.ts
CHANGED
|
@@ -411,6 +411,7 @@ declare class MCPServer {
|
|
|
411
411
|
private options;
|
|
412
412
|
private initPromise;
|
|
413
413
|
private autoDiscovered;
|
|
414
|
+
private manifestWatcher;
|
|
414
415
|
constructor(options: MCPServerConstructorOptions);
|
|
415
416
|
/**
|
|
416
417
|
* Internal initialization - runs automatically in constructor
|
|
@@ -462,6 +463,14 @@ declare class MCPServer {
|
|
|
462
463
|
* Register a service instance with decorated methods
|
|
463
464
|
*/
|
|
464
465
|
registerService(instance: any): void;
|
|
466
|
+
/**
|
|
467
|
+
* Watch UI manifest for changes and reload resources dynamically
|
|
468
|
+
*/
|
|
469
|
+
private watchUIManifest;
|
|
470
|
+
/**
|
|
471
|
+
* Reload UI manifest and update resource registrations
|
|
472
|
+
*/
|
|
473
|
+
private reloadUIManifest;
|
|
465
474
|
/**
|
|
466
475
|
* Load UI manifest and auto-register resources for pre-built @UIApp components.
|
|
467
476
|
* The manifest is generated by `leanmcp dev` or `leanmcp start` commands.
|
|
@@ -511,6 +520,10 @@ declare class MCPServer {
|
|
|
511
520
|
} | undefined;
|
|
512
521
|
} | undefined;
|
|
513
522
|
}>;
|
|
523
|
+
/**
|
|
524
|
+
* Cleanup resources (call on server shutdown)
|
|
525
|
+
*/
|
|
526
|
+
cleanup(): Promise<void>;
|
|
514
527
|
}
|
|
515
528
|
declare class MCPServerRuntime {
|
|
516
529
|
private server;
|
package/dist/index.js
CHANGED
|
@@ -990,6 +990,7 @@ var init_index = __esm({
|
|
|
990
990
|
options;
|
|
991
991
|
initPromise;
|
|
992
992
|
autoDiscovered = false;
|
|
993
|
+
manifestWatcher = null;
|
|
993
994
|
constructor(options) {
|
|
994
995
|
this.options = options;
|
|
995
996
|
this.logging = options.logging || false;
|
|
@@ -1023,6 +1024,7 @@ var init_index = __esm({
|
|
|
1023
1024
|
await this.autoDiscoverServices(options.mcpDir, options.serviceFactories);
|
|
1024
1025
|
}
|
|
1025
1026
|
await this.loadUIManifest();
|
|
1027
|
+
this.watchUIManifest();
|
|
1026
1028
|
}
|
|
1027
1029
|
/**
|
|
1028
1030
|
* Wait for initialization to complete
|
|
@@ -1420,6 +1422,113 @@ var init_index = __esm({
|
|
|
1420
1422
|
}
|
|
1421
1423
|
}
|
|
1422
1424
|
/**
|
|
1425
|
+
* Watch UI manifest for changes and reload resources dynamically
|
|
1426
|
+
*/
|
|
1427
|
+
watchUIManifest() {
|
|
1428
|
+
try {
|
|
1429
|
+
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1430
|
+
if (!import_fs.default.existsSync(manifestPath)) {
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (this.logging) {
|
|
1434
|
+
this.logger.debug(`Watching UI manifest: ${manifestPath}`);
|
|
1435
|
+
}
|
|
1436
|
+
import("chokidar").then(({ default: chokidar }) => {
|
|
1437
|
+
this.manifestWatcher = chokidar.watch(manifestPath, {
|
|
1438
|
+
ignoreInitial: true,
|
|
1439
|
+
persistent: true,
|
|
1440
|
+
awaitWriteFinish: {
|
|
1441
|
+
stabilityThreshold: 100,
|
|
1442
|
+
pollInterval: 50
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
1445
|
+
this.manifestWatcher.on("change", async () => {
|
|
1446
|
+
if (this.logging) {
|
|
1447
|
+
this.logger.debug("UI manifest changed, reloading resources");
|
|
1448
|
+
}
|
|
1449
|
+
await this.reloadUIManifest();
|
|
1450
|
+
});
|
|
1451
|
+
this.manifestWatcher.on("error", (error) => {
|
|
1452
|
+
if (this.logging) {
|
|
1453
|
+
this.logger.warn(`Manifest watcher error: ${error.message}`);
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
}).catch((error) => {
|
|
1457
|
+
if (this.logging) {
|
|
1458
|
+
this.logger.warn(`Failed to initialize manifest watcher: ${error.message}`);
|
|
1459
|
+
}
|
|
1460
|
+
});
|
|
1461
|
+
} catch (error) {
|
|
1462
|
+
if (this.logging) {
|
|
1463
|
+
this.logger.warn(`Failed to setup manifest watcher: ${error.message}`);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Reload UI manifest and update resource registrations
|
|
1469
|
+
*/
|
|
1470
|
+
async reloadUIManifest() {
|
|
1471
|
+
try {
|
|
1472
|
+
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1473
|
+
if (!import_fs.default.existsSync(manifestPath)) {
|
|
1474
|
+
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1475
|
+
for (const uri of uiResourceUris) {
|
|
1476
|
+
this.resources.delete(uri);
|
|
1477
|
+
if (this.logging) {
|
|
1478
|
+
this.logger.debug(`Removed UI resource: ${uri}`);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
const manifest = JSON.parse(import_fs.default.readFileSync(manifestPath, "utf-8"));
|
|
1484
|
+
const currentUIUris = new Set(Object.keys(manifest));
|
|
1485
|
+
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1486
|
+
for (const uri of registeredUIUris) {
|
|
1487
|
+
if (!currentUIUris.has(uri)) {
|
|
1488
|
+
this.resources.delete(uri);
|
|
1489
|
+
if (this.logging) {
|
|
1490
|
+
this.logger.debug(`Removed UI resource: ${uri}`);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
for (const [uri, htmlPath] of Object.entries(manifest)) {
|
|
1495
|
+
if (!import_fs.default.existsSync(htmlPath)) {
|
|
1496
|
+
if (this.logging) {
|
|
1497
|
+
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1498
|
+
}
|
|
1499
|
+
continue;
|
|
1500
|
+
}
|
|
1501
|
+
const wasRegistered = this.resources.has(uri);
|
|
1502
|
+
this.resources.set(uri, {
|
|
1503
|
+
uri,
|
|
1504
|
+
name: uri.replace("ui://", "").replace(/\//g, "-"),
|
|
1505
|
+
description: `Auto-generated UI resource from pre-built HTML`,
|
|
1506
|
+
mimeType: "text/html;profile=mcp-app",
|
|
1507
|
+
inputSchema: void 0,
|
|
1508
|
+
method: /* @__PURE__ */ __name(async () => {
|
|
1509
|
+
if (import_fs.default.existsSync(htmlPath)) {
|
|
1510
|
+
const html = import_fs.default.readFileSync(htmlPath, "utf-8");
|
|
1511
|
+
return {
|
|
1512
|
+
text: html
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
throw new Error(`UI HTML file not found: ${htmlPath}`);
|
|
1516
|
+
}, "method"),
|
|
1517
|
+
instance: null,
|
|
1518
|
+
propertyKey: "getUI"
|
|
1519
|
+
});
|
|
1520
|
+
if (this.logging) {
|
|
1521
|
+
const action = wasRegistered ? "Updated" : "Registered";
|
|
1522
|
+
this.logger.debug(`${action} UI resource: ${uri}`);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
if (this.logging) {
|
|
1527
|
+
this.logger.warn(`Failed to reload UI manifest: ${error.message}`);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1423
1532
|
* Load UI manifest and auto-register resources for pre-built @UIApp components.
|
|
1424
1533
|
* The manifest is generated by `leanmcp dev` or `leanmcp start` commands.
|
|
1425
1534
|
*/
|
|
@@ -1474,6 +1583,15 @@ var init_index = __esm({
|
|
|
1474
1583
|
this.server.waitForInit = () => this.waitForInit();
|
|
1475
1584
|
return this.server;
|
|
1476
1585
|
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Cleanup resources (call on server shutdown)
|
|
1588
|
+
*/
|
|
1589
|
+
async cleanup() {
|
|
1590
|
+
if (this.manifestWatcher) {
|
|
1591
|
+
await this.manifestWatcher.close();
|
|
1592
|
+
this.manifestWatcher = null;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1477
1595
|
};
|
|
1478
1596
|
MCPServerRuntime = class {
|
|
1479
1597
|
static {
|
package/dist/index.mjs
CHANGED
|
@@ -887,6 +887,7 @@ var MCPServer = class {
|
|
|
887
887
|
options;
|
|
888
888
|
initPromise;
|
|
889
889
|
autoDiscovered = false;
|
|
890
|
+
manifestWatcher = null;
|
|
890
891
|
constructor(options) {
|
|
891
892
|
this.options = options;
|
|
892
893
|
this.logging = options.logging || false;
|
|
@@ -920,6 +921,7 @@ var MCPServer = class {
|
|
|
920
921
|
await this.autoDiscoverServices(options.mcpDir, options.serviceFactories);
|
|
921
922
|
}
|
|
922
923
|
await this.loadUIManifest();
|
|
924
|
+
this.watchUIManifest();
|
|
923
925
|
}
|
|
924
926
|
/**
|
|
925
927
|
* Wait for initialization to complete
|
|
@@ -1317,6 +1319,113 @@ var MCPServer = class {
|
|
|
1317
1319
|
}
|
|
1318
1320
|
}
|
|
1319
1321
|
/**
|
|
1322
|
+
* Watch UI manifest for changes and reload resources dynamically
|
|
1323
|
+
*/
|
|
1324
|
+
watchUIManifest() {
|
|
1325
|
+
try {
|
|
1326
|
+
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1327
|
+
if (!fs.existsSync(manifestPath)) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
if (this.logging) {
|
|
1331
|
+
this.logger.debug(`Watching UI manifest: ${manifestPath}`);
|
|
1332
|
+
}
|
|
1333
|
+
import("chokidar").then(({ default: chokidar }) => {
|
|
1334
|
+
this.manifestWatcher = chokidar.watch(manifestPath, {
|
|
1335
|
+
ignoreInitial: true,
|
|
1336
|
+
persistent: true,
|
|
1337
|
+
awaitWriteFinish: {
|
|
1338
|
+
stabilityThreshold: 100,
|
|
1339
|
+
pollInterval: 50
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1342
|
+
this.manifestWatcher.on("change", async () => {
|
|
1343
|
+
if (this.logging) {
|
|
1344
|
+
this.logger.debug("UI manifest changed, reloading resources");
|
|
1345
|
+
}
|
|
1346
|
+
await this.reloadUIManifest();
|
|
1347
|
+
});
|
|
1348
|
+
this.manifestWatcher.on("error", (error) => {
|
|
1349
|
+
if (this.logging) {
|
|
1350
|
+
this.logger.warn(`Manifest watcher error: ${error.message}`);
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
}).catch((error) => {
|
|
1354
|
+
if (this.logging) {
|
|
1355
|
+
this.logger.warn(`Failed to initialize manifest watcher: ${error.message}`);
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
if (this.logging) {
|
|
1360
|
+
this.logger.warn(`Failed to setup manifest watcher: ${error.message}`);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Reload UI manifest and update resource registrations
|
|
1366
|
+
*/
|
|
1367
|
+
async reloadUIManifest() {
|
|
1368
|
+
try {
|
|
1369
|
+
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1370
|
+
if (!fs.existsSync(manifestPath)) {
|
|
1371
|
+
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1372
|
+
for (const uri of uiResourceUris) {
|
|
1373
|
+
this.resources.delete(uri);
|
|
1374
|
+
if (this.logging) {
|
|
1375
|
+
this.logger.debug(`Removed UI resource: ${uri}`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
1381
|
+
const currentUIUris = new Set(Object.keys(manifest));
|
|
1382
|
+
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1383
|
+
for (const uri of registeredUIUris) {
|
|
1384
|
+
if (!currentUIUris.has(uri)) {
|
|
1385
|
+
this.resources.delete(uri);
|
|
1386
|
+
if (this.logging) {
|
|
1387
|
+
this.logger.debug(`Removed UI resource: ${uri}`);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
for (const [uri, htmlPath] of Object.entries(manifest)) {
|
|
1392
|
+
if (!fs.existsSync(htmlPath)) {
|
|
1393
|
+
if (this.logging) {
|
|
1394
|
+
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1395
|
+
}
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
const wasRegistered = this.resources.has(uri);
|
|
1399
|
+
this.resources.set(uri, {
|
|
1400
|
+
uri,
|
|
1401
|
+
name: uri.replace("ui://", "").replace(/\//g, "-"),
|
|
1402
|
+
description: `Auto-generated UI resource from pre-built HTML`,
|
|
1403
|
+
mimeType: "text/html;profile=mcp-app",
|
|
1404
|
+
inputSchema: void 0,
|
|
1405
|
+
method: /* @__PURE__ */ __name(async () => {
|
|
1406
|
+
if (fs.existsSync(htmlPath)) {
|
|
1407
|
+
const html = fs.readFileSync(htmlPath, "utf-8");
|
|
1408
|
+
return {
|
|
1409
|
+
text: html
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
throw new Error(`UI HTML file not found: ${htmlPath}`);
|
|
1413
|
+
}, "method"),
|
|
1414
|
+
instance: null,
|
|
1415
|
+
propertyKey: "getUI"
|
|
1416
|
+
});
|
|
1417
|
+
if (this.logging) {
|
|
1418
|
+
const action = wasRegistered ? "Updated" : "Registered";
|
|
1419
|
+
this.logger.debug(`${action} UI resource: ${uri}`);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
} catch (error) {
|
|
1423
|
+
if (this.logging) {
|
|
1424
|
+
this.logger.warn(`Failed to reload UI manifest: ${error.message}`);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1320
1429
|
* Load UI manifest and auto-register resources for pre-built @UIApp components.
|
|
1321
1430
|
* The manifest is generated by `leanmcp dev` or `leanmcp start` commands.
|
|
1322
1431
|
*/
|
|
@@ -1371,6 +1480,15 @@ var MCPServer = class {
|
|
|
1371
1480
|
this.server.waitForInit = () => this.waitForInit();
|
|
1372
1481
|
return this.server;
|
|
1373
1482
|
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Cleanup resources (call on server shutdown)
|
|
1485
|
+
*/
|
|
1486
|
+
async cleanup() {
|
|
1487
|
+
if (this.manifestWatcher) {
|
|
1488
|
+
await this.manifestWatcher.close();
|
|
1489
|
+
this.manifestWatcher = null;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1374
1492
|
};
|
|
1375
1493
|
var MCPServerRuntime = class {
|
|
1376
1494
|
static {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leanmcp/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Core library implementing decorators, reflection, and MCP runtime server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
28
28
|
"ajv": "^8.12.0",
|
|
29
|
+
"chokidar": "^4.0.0",
|
|
29
30
|
"dotenv": "^16.3.1",
|
|
30
31
|
"reflect-metadata": "^0.2.1"
|
|
31
32
|
},
|