mcp-squared 0.3.0 → 0.3.1
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.js +297 -211
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -405,7 +405,6 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
405
405
|
import { UnauthorizedError as UnauthorizedError4 } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
406
406
|
import { Client as Client4 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
407
407
|
import { StreamableHTTPClientTransport as StreamableHTTPClientTransport4 } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
408
|
-
import { VERSION as VERSION4 } from "@/version.js";
|
|
409
408
|
|
|
410
409
|
// src/cli/index.ts
|
|
411
410
|
function isValidSecurityProfile(value) {
|
|
@@ -1433,173 +1432,9 @@ function computeConfigHash(config) {
|
|
|
1433
1432
|
}
|
|
1434
1433
|
|
|
1435
1434
|
// src/daemon/proxy.ts
|
|
1435
|
+
init_paths();
|
|
1436
1436
|
import { spawn } from "child_process";
|
|
1437
1437
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1438
|
-
import { getDaemonSocketPath as getDaemonSocketPath2 } from "@/config/paths.js";
|
|
1439
|
-
import {
|
|
1440
|
-
loadLiveDaemonRegistry
|
|
1441
|
-
} from "@/daemon/registry.js";
|
|
1442
|
-
import { SocketClientTransport } from "@/daemon/transport.js";
|
|
1443
|
-
var DEFAULT_STARTUP_TIMEOUT_MS = 5000;
|
|
1444
|
-
var HEARTBEAT_INTERVAL_MS = 5000;
|
|
1445
|
-
function sleep(ms) {
|
|
1446
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1447
|
-
}
|
|
1448
|
-
async function waitForDaemon(timeoutMs, configHash) {
|
|
1449
|
-
const start = Date.now();
|
|
1450
|
-
while (Date.now() - start < timeoutMs) {
|
|
1451
|
-
const entry = await loadLiveDaemonRegistry(configHash);
|
|
1452
|
-
if (entry) {
|
|
1453
|
-
return entry;
|
|
1454
|
-
}
|
|
1455
|
-
await sleep(100);
|
|
1456
|
-
}
|
|
1457
|
-
return null;
|
|
1458
|
-
}
|
|
1459
|
-
function spawnDaemonProcess(sharedSecret) {
|
|
1460
|
-
const execPath = process.execPath;
|
|
1461
|
-
const scriptPath = process.argv[1];
|
|
1462
|
-
const args = scriptPath ? [scriptPath, "daemon"] : ["daemon"];
|
|
1463
|
-
const child = spawn(execPath, args, {
|
|
1464
|
-
detached: true,
|
|
1465
|
-
stdio: "ignore",
|
|
1466
|
-
env: {
|
|
1467
|
-
...process.env,
|
|
1468
|
-
...sharedSecret ? { MCP_SQUARED_DAEMON_SECRET: sharedSecret } : {}
|
|
1469
|
-
}
|
|
1470
|
-
});
|
|
1471
|
-
child.unref();
|
|
1472
|
-
}
|
|
1473
|
-
async function createProxyBridge(options) {
|
|
1474
|
-
const spawnDaemon = options.spawnDaemon ?? spawnDaemonProcess;
|
|
1475
|
-
let endpoint = options.endpoint;
|
|
1476
|
-
let sharedSecret = options.sharedSecret?.trim();
|
|
1477
|
-
let sessionId = null;
|
|
1478
|
-
let heartbeatTimer = null;
|
|
1479
|
-
let isOwner = false;
|
|
1480
|
-
let daemonClosed = false;
|
|
1481
|
-
let stdioClosed = false;
|
|
1482
|
-
const debug = options.debug ?? process.env["MCP_SQUARED_PROXY_DEBUG"] === "1";
|
|
1483
|
-
if (!endpoint) {
|
|
1484
|
-
const registry = await loadLiveDaemonRegistry(options.configHash);
|
|
1485
|
-
if (registry) {
|
|
1486
|
-
endpoint = registry.endpoint;
|
|
1487
|
-
sharedSecret ??= registry.sharedSecret;
|
|
1488
|
-
} else if (!options.noSpawn) {
|
|
1489
|
-
spawnDaemon(sharedSecret);
|
|
1490
|
-
const entry = await waitForDaemon(DEFAULT_STARTUP_TIMEOUT_MS, options.configHash);
|
|
1491
|
-
if (!entry) {
|
|
1492
|
-
throw new Error("Timed out waiting for daemon to start");
|
|
1493
|
-
}
|
|
1494
|
-
endpoint = entry.endpoint;
|
|
1495
|
-
sharedSecret ??= entry.sharedSecret;
|
|
1496
|
-
} else if (options.configHash) {
|
|
1497
|
-
endpoint = getDaemonSocketPath2(options.configHash);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
if (!endpoint) {
|
|
1501
|
-
throw new Error("Daemon endpoint not available");
|
|
1502
|
-
}
|
|
1503
|
-
const transportOptions = {
|
|
1504
|
-
endpoint
|
|
1505
|
-
};
|
|
1506
|
-
if (options.timeoutMs !== undefined) {
|
|
1507
|
-
transportOptions.timeoutMs = options.timeoutMs;
|
|
1508
|
-
}
|
|
1509
|
-
const daemonTransport = new SocketClientTransport(transportOptions);
|
|
1510
|
-
const stdioTransport = options.stdioTransport;
|
|
1511
|
-
const closeDaemon = async (sendGoodbye) => {
|
|
1512
|
-
if (daemonClosed) {
|
|
1513
|
-
return;
|
|
1514
|
-
}
|
|
1515
|
-
daemonClosed = true;
|
|
1516
|
-
if (sendGoodbye && sessionId) {
|
|
1517
|
-
await daemonTransport.sendControl({ type: "goodbye", sessionId }).catch(() => {});
|
|
1518
|
-
}
|
|
1519
|
-
await daemonTransport.close().catch(() => {});
|
|
1520
|
-
};
|
|
1521
|
-
daemonTransport.oncontrol = (message) => {
|
|
1522
|
-
switch (message.type) {
|
|
1523
|
-
case "helloAck":
|
|
1524
|
-
sessionId = message.sessionId;
|
|
1525
|
-
isOwner = message.isOwner;
|
|
1526
|
-
if (debug) {
|
|
1527
|
-
console.error(`[proxy] session ${message.sessionId} owner=${message.isOwner}`);
|
|
1528
|
-
}
|
|
1529
|
-
break;
|
|
1530
|
-
case "ownerChanged":
|
|
1531
|
-
isOwner = message.ownerSessionId === sessionId;
|
|
1532
|
-
if (debug) {
|
|
1533
|
-
console.error(`[proxy] owner changed: ${message.ownerSessionId} (isOwner=${isOwner})`);
|
|
1534
|
-
}
|
|
1535
|
-
break;
|
|
1536
|
-
}
|
|
1537
|
-
};
|
|
1538
|
-
daemonTransport.onmessage = (message) => {
|
|
1539
|
-
stdioTransport.send(message);
|
|
1540
|
-
};
|
|
1541
|
-
daemonTransport.onclose = () => {
|
|
1542
|
-
daemonClosed = true;
|
|
1543
|
-
if (heartbeatTimer) {
|
|
1544
|
-
clearInterval(heartbeatTimer);
|
|
1545
|
-
heartbeatTimer = null;
|
|
1546
|
-
}
|
|
1547
|
-
stdioTransport.close();
|
|
1548
|
-
};
|
|
1549
|
-
daemonTransport.onerror = (error) => {
|
|
1550
|
-
console.error(`Daemon transport error: ${error.message}`);
|
|
1551
|
-
};
|
|
1552
|
-
stdioTransport.onmessage = (message) => {
|
|
1553
|
-
daemonTransport.send(message);
|
|
1554
|
-
};
|
|
1555
|
-
stdioTransport.onclose = () => {
|
|
1556
|
-
stdioClosed = true;
|
|
1557
|
-
if (heartbeatTimer) {
|
|
1558
|
-
clearInterval(heartbeatTimer);
|
|
1559
|
-
heartbeatTimer = null;
|
|
1560
|
-
}
|
|
1561
|
-
closeDaemon(true);
|
|
1562
|
-
};
|
|
1563
|
-
stdioTransport.onerror = (error) => {
|
|
1564
|
-
console.error(`Stdio transport error: ${error.message}`);
|
|
1565
|
-
};
|
|
1566
|
-
await daemonTransport.start();
|
|
1567
|
-
const launcherHint = process.env["MCP_SQUARED_LAUNCHER"] ?? process.env["MCP_CLIENT_NAME"] ?? process.env["MCP_SQUARED_AGENT"];
|
|
1568
|
-
const clientId = launcherHint ? `${launcherHint}-${process.pid}` : `proxy-${process.pid}`;
|
|
1569
|
-
daemonTransport.sendControl({
|
|
1570
|
-
type: "hello",
|
|
1571
|
-
clientId,
|
|
1572
|
-
...sharedSecret ? { sharedSecret } : {}
|
|
1573
|
-
});
|
|
1574
|
-
heartbeatTimer = setInterval(() => {
|
|
1575
|
-
if (!sessionId) {
|
|
1576
|
-
return;
|
|
1577
|
-
}
|
|
1578
|
-
daemonTransport.sendControl({
|
|
1579
|
-
type: "heartbeat",
|
|
1580
|
-
sessionId
|
|
1581
|
-
});
|
|
1582
|
-
}, options.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS);
|
|
1583
|
-
await stdioTransport.start();
|
|
1584
|
-
return {
|
|
1585
|
-
stop: async () => {
|
|
1586
|
-
if (heartbeatTimer) {
|
|
1587
|
-
clearInterval(heartbeatTimer);
|
|
1588
|
-
heartbeatTimer = null;
|
|
1589
|
-
}
|
|
1590
|
-
await closeDaemon(true);
|
|
1591
|
-
if (!stdioClosed) {
|
|
1592
|
-
await stdioTransport.close();
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1596
|
-
}
|
|
1597
|
-
async function runProxy(options = {}) {
|
|
1598
|
-
return createProxyBridge({
|
|
1599
|
-
...options,
|
|
1600
|
-
stdioTransport: new StdioServerTransport
|
|
1601
|
-
});
|
|
1602
|
-
}
|
|
1603
1438
|
|
|
1604
1439
|
// src/daemon/registry.ts
|
|
1605
1440
|
init_paths();
|
|
@@ -1698,7 +1533,7 @@ async function isDaemonAlive(entry, timeoutMs = DEFAULT_CONNECT_TIMEOUT_MS2) {
|
|
|
1698
1533
|
}
|
|
1699
1534
|
return canConnect2(entry.endpoint, timeoutMs);
|
|
1700
1535
|
}
|
|
1701
|
-
async function
|
|
1536
|
+
async function loadLiveDaemonRegistry(configHash) {
|
|
1702
1537
|
const entry = readDaemonRegistry(configHash);
|
|
1703
1538
|
if (!entry) {
|
|
1704
1539
|
return null;
|
|
@@ -1711,20 +1546,8 @@ async function loadLiveDaemonRegistry2(configHash) {
|
|
|
1711
1546
|
return entry;
|
|
1712
1547
|
}
|
|
1713
1548
|
|
|
1714
|
-
// src/daemon/server.ts
|
|
1715
|
-
init_paths();
|
|
1716
|
-
import { randomUUID } from "crypto";
|
|
1717
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
1718
|
-
import {
|
|
1719
|
-
connect as connect3,
|
|
1720
|
-
createServer,
|
|
1721
|
-
isIPv4,
|
|
1722
|
-
isIPv6
|
|
1723
|
-
} from "net";
|
|
1724
|
-
import { dirname as dirname2 } from "path";
|
|
1725
|
-
import { VERSION } from "@/version.js";
|
|
1726
|
-
|
|
1727
1549
|
// src/daemon/transport.ts
|
|
1550
|
+
import { connect as connect3 } from "net";
|
|
1728
1551
|
var HEADER_LENGTH = 4;
|
|
1729
1552
|
function encodeFrame(message) {
|
|
1730
1553
|
const payload = Buffer.from(JSON.stringify(message), "utf8");
|
|
@@ -1822,10 +1645,275 @@ class SocketServerTransport extends BaseSocketTransport {
|
|
|
1822
1645
|
this.socket = socket;
|
|
1823
1646
|
}
|
|
1824
1647
|
}
|
|
1648
|
+
function isTcpEndpoint3(endpoint) {
|
|
1649
|
+
return endpoint.startsWith("tcp://");
|
|
1650
|
+
}
|
|
1651
|
+
function parseTcpEndpoint3(endpoint) {
|
|
1652
|
+
const url = new URL(endpoint);
|
|
1653
|
+
if (url.protocol !== "tcp:") {
|
|
1654
|
+
throw new Error(`Invalid TCP endpoint protocol: ${url.protocol}`);
|
|
1655
|
+
}
|
|
1656
|
+
const host = url.hostname;
|
|
1657
|
+
const port = Number.parseInt(url.port, 10);
|
|
1658
|
+
if (!host || Number.isNaN(port)) {
|
|
1659
|
+
throw new Error(`Invalid TCP endpoint: ${endpoint}`);
|
|
1660
|
+
}
|
|
1661
|
+
return { host, port };
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
class SocketClientTransport extends BaseSocketTransport {
|
|
1665
|
+
endpoint;
|
|
1666
|
+
timeoutMs;
|
|
1667
|
+
constructor(options) {
|
|
1668
|
+
super();
|
|
1669
|
+
this.endpoint = options.endpoint;
|
|
1670
|
+
this.timeoutMs = options.timeoutMs ?? 5000;
|
|
1671
|
+
}
|
|
1672
|
+
async start() {
|
|
1673
|
+
if (this.started) {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
await new Promise((resolve2, reject) => {
|
|
1677
|
+
const socket = isTcpEndpoint3(this.endpoint) ? connect3(parseTcpEndpoint3(this.endpoint)) : connect3(this.endpoint);
|
|
1678
|
+
this.socket = socket;
|
|
1679
|
+
const timeoutId = setTimeout(() => {
|
|
1680
|
+
socket.destroy();
|
|
1681
|
+
reject(new Error(`Connection timeout after ${this.timeoutMs}ms`));
|
|
1682
|
+
}, this.timeoutMs);
|
|
1683
|
+
socket.once("connect", () => {
|
|
1684
|
+
clearTimeout(timeoutId);
|
|
1685
|
+
this.started = true;
|
|
1686
|
+
this.attachHandlers();
|
|
1687
|
+
resolve2();
|
|
1688
|
+
});
|
|
1689
|
+
socket.once("error", (error) => {
|
|
1690
|
+
clearTimeout(timeoutId);
|
|
1691
|
+
reject(error);
|
|
1692
|
+
});
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
// src/daemon/proxy.ts
|
|
1698
|
+
var DEFAULT_STARTUP_TIMEOUT_MS = 5000;
|
|
1699
|
+
var HEARTBEAT_INTERVAL_MS = 5000;
|
|
1700
|
+
function sleep(ms) {
|
|
1701
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1702
|
+
}
|
|
1703
|
+
async function waitForDaemon(timeoutMs, configHash) {
|
|
1704
|
+
const start = Date.now();
|
|
1705
|
+
while (Date.now() - start < timeoutMs) {
|
|
1706
|
+
const entry = await loadLiveDaemonRegistry(configHash);
|
|
1707
|
+
if (entry) {
|
|
1708
|
+
return entry;
|
|
1709
|
+
}
|
|
1710
|
+
await sleep(100);
|
|
1711
|
+
}
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1714
|
+
function spawnDaemonProcess(sharedSecret) {
|
|
1715
|
+
const execPath = process.execPath;
|
|
1716
|
+
const scriptPath = process.argv[1];
|
|
1717
|
+
const args = scriptPath ? [scriptPath, "daemon"] : ["daemon"];
|
|
1718
|
+
const child = spawn(execPath, args, {
|
|
1719
|
+
detached: true,
|
|
1720
|
+
stdio: "ignore",
|
|
1721
|
+
env: {
|
|
1722
|
+
...process.env,
|
|
1723
|
+
...sharedSecret ? { MCP_SQUARED_DAEMON_SECRET: sharedSecret } : {}
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
child.unref();
|
|
1727
|
+
}
|
|
1728
|
+
async function createProxyBridge(options) {
|
|
1729
|
+
const spawnDaemon = options.spawnDaemon ?? spawnDaemonProcess;
|
|
1730
|
+
let endpoint = options.endpoint;
|
|
1731
|
+
let sharedSecret = options.sharedSecret?.trim();
|
|
1732
|
+
let sessionId = null;
|
|
1733
|
+
let heartbeatTimer = null;
|
|
1734
|
+
let isOwner = false;
|
|
1735
|
+
let daemonClosed = false;
|
|
1736
|
+
let stdioClosed = false;
|
|
1737
|
+
const debug = options.debug ?? process.env["MCP_SQUARED_PROXY_DEBUG"] === "1";
|
|
1738
|
+
if (!endpoint) {
|
|
1739
|
+
const registry = await loadLiveDaemonRegistry(options.configHash);
|
|
1740
|
+
if (registry) {
|
|
1741
|
+
endpoint = registry.endpoint;
|
|
1742
|
+
sharedSecret ??= registry.sharedSecret;
|
|
1743
|
+
} else if (!options.noSpawn) {
|
|
1744
|
+
spawnDaemon(sharedSecret);
|
|
1745
|
+
const entry = await waitForDaemon(DEFAULT_STARTUP_TIMEOUT_MS, options.configHash);
|
|
1746
|
+
if (!entry) {
|
|
1747
|
+
throw new Error("Timed out waiting for daemon to start");
|
|
1748
|
+
}
|
|
1749
|
+
endpoint = entry.endpoint;
|
|
1750
|
+
sharedSecret ??= entry.sharedSecret;
|
|
1751
|
+
} else if (options.configHash) {
|
|
1752
|
+
endpoint = getDaemonSocketPath(options.configHash);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
if (!endpoint) {
|
|
1756
|
+
throw new Error("Daemon endpoint not available");
|
|
1757
|
+
}
|
|
1758
|
+
const transportOptions = {
|
|
1759
|
+
endpoint
|
|
1760
|
+
};
|
|
1761
|
+
if (options.timeoutMs !== undefined) {
|
|
1762
|
+
transportOptions.timeoutMs = options.timeoutMs;
|
|
1763
|
+
}
|
|
1764
|
+
const daemonTransport = new SocketClientTransport(transportOptions);
|
|
1765
|
+
const stdioTransport = options.stdioTransport;
|
|
1766
|
+
const closeDaemon = async (sendGoodbye) => {
|
|
1767
|
+
if (daemonClosed) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
daemonClosed = true;
|
|
1771
|
+
if (sendGoodbye && sessionId) {
|
|
1772
|
+
await daemonTransport.sendControl({ type: "goodbye", sessionId }).catch(() => {});
|
|
1773
|
+
}
|
|
1774
|
+
await daemonTransport.close().catch(() => {});
|
|
1775
|
+
};
|
|
1776
|
+
daemonTransport.oncontrol = (message) => {
|
|
1777
|
+
switch (message.type) {
|
|
1778
|
+
case "helloAck":
|
|
1779
|
+
sessionId = message.sessionId;
|
|
1780
|
+
isOwner = message.isOwner;
|
|
1781
|
+
if (debug) {
|
|
1782
|
+
console.error(`[proxy] session ${message.sessionId} owner=${message.isOwner}`);
|
|
1783
|
+
}
|
|
1784
|
+
break;
|
|
1785
|
+
case "ownerChanged":
|
|
1786
|
+
isOwner = message.ownerSessionId === sessionId;
|
|
1787
|
+
if (debug) {
|
|
1788
|
+
console.error(`[proxy] owner changed: ${message.ownerSessionId} (isOwner=${isOwner})`);
|
|
1789
|
+
}
|
|
1790
|
+
break;
|
|
1791
|
+
}
|
|
1792
|
+
};
|
|
1793
|
+
daemonTransport.onmessage = (message) => {
|
|
1794
|
+
stdioTransport.send(message);
|
|
1795
|
+
};
|
|
1796
|
+
daemonTransport.onclose = () => {
|
|
1797
|
+
daemonClosed = true;
|
|
1798
|
+
if (heartbeatTimer) {
|
|
1799
|
+
clearInterval(heartbeatTimer);
|
|
1800
|
+
heartbeatTimer = null;
|
|
1801
|
+
}
|
|
1802
|
+
stdioTransport.close();
|
|
1803
|
+
};
|
|
1804
|
+
daemonTransport.onerror = (error) => {
|
|
1805
|
+
console.error(`Daemon transport error: ${error.message}`);
|
|
1806
|
+
};
|
|
1807
|
+
stdioTransport.onmessage = (message) => {
|
|
1808
|
+
daemonTransport.send(message);
|
|
1809
|
+
};
|
|
1810
|
+
stdioTransport.onclose = () => {
|
|
1811
|
+
stdioClosed = true;
|
|
1812
|
+
if (heartbeatTimer) {
|
|
1813
|
+
clearInterval(heartbeatTimer);
|
|
1814
|
+
heartbeatTimer = null;
|
|
1815
|
+
}
|
|
1816
|
+
closeDaemon(true);
|
|
1817
|
+
};
|
|
1818
|
+
stdioTransport.onerror = (error) => {
|
|
1819
|
+
console.error(`Stdio transport error: ${error.message}`);
|
|
1820
|
+
};
|
|
1821
|
+
await daemonTransport.start();
|
|
1822
|
+
const launcherHint = process.env["MCP_SQUARED_LAUNCHER"] ?? process.env["MCP_CLIENT_NAME"] ?? process.env["MCP_SQUARED_AGENT"];
|
|
1823
|
+
const clientId = launcherHint ? `${launcherHint}-${process.pid}` : `proxy-${process.pid}`;
|
|
1824
|
+
daemonTransport.sendControl({
|
|
1825
|
+
type: "hello",
|
|
1826
|
+
clientId,
|
|
1827
|
+
...sharedSecret ? { sharedSecret } : {}
|
|
1828
|
+
});
|
|
1829
|
+
heartbeatTimer = setInterval(() => {
|
|
1830
|
+
if (!sessionId) {
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
daemonTransport.sendControl({
|
|
1834
|
+
type: "heartbeat",
|
|
1835
|
+
sessionId
|
|
1836
|
+
});
|
|
1837
|
+
}, options.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS);
|
|
1838
|
+
await stdioTransport.start();
|
|
1839
|
+
return {
|
|
1840
|
+
stop: async () => {
|
|
1841
|
+
if (heartbeatTimer) {
|
|
1842
|
+
clearInterval(heartbeatTimer);
|
|
1843
|
+
heartbeatTimer = null;
|
|
1844
|
+
}
|
|
1845
|
+
await closeDaemon(true);
|
|
1846
|
+
if (!stdioClosed) {
|
|
1847
|
+
await stdioTransport.close();
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
async function runProxy(options = {}) {
|
|
1853
|
+
return createProxyBridge({
|
|
1854
|
+
...options,
|
|
1855
|
+
stdioTransport: new StdioServerTransport
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// src/daemon/server.ts
|
|
1860
|
+
init_paths();
|
|
1861
|
+
import { randomUUID } from "crypto";
|
|
1862
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
1863
|
+
import {
|
|
1864
|
+
connect as connect4,
|
|
1865
|
+
createServer,
|
|
1866
|
+
isIPv4,
|
|
1867
|
+
isIPv6
|
|
1868
|
+
} from "net";
|
|
1869
|
+
import { dirname as dirname2 } from "path";
|
|
1870
|
+
|
|
1871
|
+
// src/version.ts
|
|
1872
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1873
|
+
import { createRequire } from "module";
|
|
1874
|
+
function normalizeVersion(value) {
|
|
1875
|
+
if (typeof value !== "string") {
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
const trimmed = value.trim();
|
|
1879
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1880
|
+
}
|
|
1881
|
+
function readManifestFile(manifestUrl) {
|
|
1882
|
+
const raw = readFileSync3(manifestUrl, "utf8");
|
|
1883
|
+
return JSON.parse(raw);
|
|
1884
|
+
}
|
|
1885
|
+
function readBundledManifestFile() {
|
|
1886
|
+
const require2 = createRequire(import.meta.url);
|
|
1887
|
+
return require2("../package.json");
|
|
1888
|
+
}
|
|
1889
|
+
function resolveVersion(options = {}) {
|
|
1890
|
+
const readManifest = options.readManifest ?? readManifestFile;
|
|
1891
|
+
const manifestUrl = options.manifestUrl ?? new URL("../package.json", import.meta.url);
|
|
1892
|
+
try {
|
|
1893
|
+
const manifest = readManifest(manifestUrl);
|
|
1894
|
+
const manifestVersion = normalizeVersion(manifest.version);
|
|
1895
|
+
if (manifestVersion) {
|
|
1896
|
+
return manifestVersion;
|
|
1897
|
+
}
|
|
1898
|
+
} catch {}
|
|
1899
|
+
const envVersion = normalizeVersion((options.env ?? process.env)["npm_package_version"]);
|
|
1900
|
+
if (envVersion) {
|
|
1901
|
+
return envVersion;
|
|
1902
|
+
}
|
|
1903
|
+
const readBundledManifest = options.readBundledManifest ?? readBundledManifestFile;
|
|
1904
|
+
try {
|
|
1905
|
+
const bundledVersion = normalizeVersion(readBundledManifest().version);
|
|
1906
|
+
if (bundledVersion) {
|
|
1907
|
+
return bundledVersion;
|
|
1908
|
+
}
|
|
1909
|
+
} catch {}
|
|
1910
|
+
return normalizeVersion(options.fallbackVersion) ?? "0.0.0";
|
|
1911
|
+
}
|
|
1912
|
+
var VERSION = resolveVersion();
|
|
1825
1913
|
|
|
1826
1914
|
// src/daemon/server.ts
|
|
1827
1915
|
var DEFAULT_CONNECT_TIMEOUT_MS3 = 300;
|
|
1828
|
-
function
|
|
1916
|
+
function isTcpEndpoint4(endpoint) {
|
|
1829
1917
|
return endpoint.startsWith("tcp://");
|
|
1830
1918
|
}
|
|
1831
1919
|
function parseMappedIpv4Address(normalizedHost) {
|
|
@@ -1850,7 +1938,7 @@ function parseMappedIpv4Address(normalizedHost) {
|
|
|
1850
1938
|
}
|
|
1851
1939
|
return `${high >> 8 & 255}.${high & 255}.${low >> 8 & 255}.${low & 255}`;
|
|
1852
1940
|
}
|
|
1853
|
-
function
|
|
1941
|
+
function parseTcpEndpoint4(endpoint) {
|
|
1854
1942
|
const url = new URL(endpoint);
|
|
1855
1943
|
if (url.protocol !== "tcp:") {
|
|
1856
1944
|
throw new Error(`Invalid TCP endpoint protocol: ${url.protocol}`);
|
|
@@ -1898,7 +1986,7 @@ function formatTcpEndpoint(host, port) {
|
|
|
1898
1986
|
return `tcp://${normalized}:${port}`;
|
|
1899
1987
|
}
|
|
1900
1988
|
function assertLoopbackTcpEndpoint(endpoint) {
|
|
1901
|
-
const { host } =
|
|
1989
|
+
const { host } = parseTcpEndpoint4(endpoint);
|
|
1902
1990
|
if (!isLoopbackHost(host)) {
|
|
1903
1991
|
throw new Error(`Refusing non-loopback daemon TCP endpoint: ${endpoint}. Use localhost, 127.0.0.1, or ::1.`);
|
|
1904
1992
|
}
|
|
@@ -1907,7 +1995,7 @@ async function canConnect3(endpoint, timeoutMs = DEFAULT_CONNECT_TIMEOUT_MS3) {
|
|
|
1907
1995
|
return new Promise((resolve2) => {
|
|
1908
1996
|
let socket = null;
|
|
1909
1997
|
try {
|
|
1910
|
-
socket =
|
|
1998
|
+
socket = isTcpEndpoint4(endpoint) ? connect4(parseTcpEndpoint4(endpoint)) : connect4(endpoint);
|
|
1911
1999
|
} catch {
|
|
1912
2000
|
resolve2(false);
|
|
1913
2001
|
return;
|
|
@@ -1962,7 +2050,7 @@ class DaemonServer {
|
|
|
1962
2050
|
return;
|
|
1963
2051
|
}
|
|
1964
2052
|
ensureDaemonDir(this.configHash);
|
|
1965
|
-
const tcp =
|
|
2053
|
+
const tcp = isTcpEndpoint4(this.socketPath);
|
|
1966
2054
|
if (tcp) {
|
|
1967
2055
|
assertLoopbackTcpEndpoint(this.socketPath);
|
|
1968
2056
|
}
|
|
@@ -1970,7 +2058,7 @@ class DaemonServer {
|
|
|
1970
2058
|
mkdirSync3(dirname2(this.socketPath), { recursive: true });
|
|
1971
2059
|
}
|
|
1972
2060
|
if (tcp) {
|
|
1973
|
-
const port =
|
|
2061
|
+
const port = parseTcpEndpoint4(this.socketPath).port;
|
|
1974
2062
|
if (port > 0 && await canConnect3(this.socketPath)) {
|
|
1975
2063
|
throw new Error(`Daemon already running at ${this.socketPath}. Refusing to start another.`);
|
|
1976
2064
|
}
|
|
@@ -1990,7 +2078,7 @@ class DaemonServer {
|
|
|
1990
2078
|
await new Promise((resolve2, reject) => {
|
|
1991
2079
|
this.server?.once("error", (error) => reject(error));
|
|
1992
2080
|
if (tcp) {
|
|
1993
|
-
const { host, port } =
|
|
2081
|
+
const { host, port } = parseTcpEndpoint4(this.socketPath);
|
|
1994
2082
|
if (!host || Number.isNaN(port)) {
|
|
1995
2083
|
reject(new Error(`Invalid TCP endpoint: ${this.socketPath}`));
|
|
1996
2084
|
return;
|
|
@@ -3667,7 +3755,7 @@ function promptUser(question) {
|
|
|
3667
3755
|
}
|
|
3668
3756
|
|
|
3669
3757
|
// src/install/runner.ts
|
|
3670
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as
|
|
3758
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
3671
3759
|
import { dirname as dirname3 } from "path";
|
|
3672
3760
|
import { createInterface } from "readline";
|
|
3673
3761
|
import { parse as parseToml3, stringify as stringifyToml2 } from "smol-toml";
|
|
@@ -3987,7 +4075,7 @@ function performInstallation(options) {
|
|
|
3987
4075
|
if (existsSync7(path)) {
|
|
3988
4076
|
configExists = true;
|
|
3989
4077
|
try {
|
|
3990
|
-
const content =
|
|
4078
|
+
const content = readFileSync4(path, "utf-8");
|
|
3991
4079
|
existingConfig = isToml ? parseToml3(content) : JSON.parse(content);
|
|
3992
4080
|
} catch (error) {
|
|
3993
4081
|
return {
|
|
@@ -4404,7 +4492,6 @@ class OAuthCallbackServer {
|
|
|
4404
4492
|
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
4405
4493
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4406
4494
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4407
|
-
import { VERSION as VERSION2 } from "@/version.js";
|
|
4408
4495
|
|
|
4409
4496
|
// src/oauth/provider.ts
|
|
4410
4497
|
var DEFAULT_OAUTH_CALLBACK_PORT = 8089;
|
|
@@ -4575,7 +4662,7 @@ import {
|
|
|
4575
4662
|
chmodSync,
|
|
4576
4663
|
existsSync as existsSync8,
|
|
4577
4664
|
mkdirSync as mkdirSync5,
|
|
4578
|
-
readFileSync as
|
|
4665
|
+
readFileSync as readFileSync5,
|
|
4579
4666
|
unlinkSync as unlinkSync4,
|
|
4580
4667
|
writeFileSync as writeFileSync4
|
|
4581
4668
|
} from "fs";
|
|
@@ -4613,7 +4700,7 @@ class TokenStorage {
|
|
|
4613
4700
|
return;
|
|
4614
4701
|
}
|
|
4615
4702
|
try {
|
|
4616
|
-
const content =
|
|
4703
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
4617
4704
|
return JSON.parse(content);
|
|
4618
4705
|
} catch {
|
|
4619
4706
|
return;
|
|
@@ -4695,7 +4782,7 @@ class TokenStorage {
|
|
|
4695
4782
|
function getPreflightClientMetadata() {
|
|
4696
4783
|
return {
|
|
4697
4784
|
name: "mcp-squared-preflight",
|
|
4698
|
-
version:
|
|
4785
|
+
version: VERSION
|
|
4699
4786
|
};
|
|
4700
4787
|
}
|
|
4701
4788
|
async function performPreflightAuth(config) {
|
|
@@ -4800,7 +4887,6 @@ async function performInteractiveAuth(name, sseConfig, authProvider, callbackPor
|
|
|
4800
4887
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4801
4888
|
import { StdioServerTransport as StdioServerTransport2 } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4802
4889
|
import { z as z3 } from "zod";
|
|
4803
|
-
import { VERSION as VERSION3 } from "@/version.js";
|
|
4804
4890
|
|
|
4805
4891
|
// agent_safety_kit/policy/matchers.ts
|
|
4806
4892
|
var GLOB_SPECIALS = /[.+^${}()|[\]\\]/g;
|
|
@@ -5158,7 +5244,7 @@ class Guard {
|
|
|
5158
5244
|
}
|
|
5159
5245
|
}
|
|
5160
5246
|
// agent_safety_kit/policy/load.ts
|
|
5161
|
-
import { existsSync as existsSync9, readFileSync as
|
|
5247
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
5162
5248
|
import { resolve as resolve3 } from "path";
|
|
5163
5249
|
import { parse as parseYaml } from "yaml";
|
|
5164
5250
|
|
|
@@ -5221,7 +5307,7 @@ function load_policy(options = {}) {
|
|
|
5221
5307
|
if (!existsSync9(sourcePath)) {
|
|
5222
5308
|
throw new Error(`Agent safety policy file not found at ${sourcePath}`);
|
|
5223
5309
|
}
|
|
5224
|
-
const raw =
|
|
5310
|
+
const raw = readFileSync6(sourcePath, "utf8");
|
|
5225
5311
|
const parsed = parseYaml(raw);
|
|
5226
5312
|
const policy = AgentPolicySchema.parse(parsed);
|
|
5227
5313
|
const playbookName = options.playbook ?? envConfig.playbook;
|
|
@@ -5258,7 +5344,7 @@ class NullSink {
|
|
|
5258
5344
|
}
|
|
5259
5345
|
|
|
5260
5346
|
// agent_safety_kit/observability/sinks/otel.ts
|
|
5261
|
-
import { createRequire } from "module";
|
|
5347
|
+
import { createRequire as createRequire2 } from "module";
|
|
5262
5348
|
|
|
5263
5349
|
// agent_safety_kit/observability/sinks/base.ts
|
|
5264
5350
|
function compactAttributes(attributes) {
|
|
@@ -5275,7 +5361,7 @@ function compactAttributes(attributes) {
|
|
|
5275
5361
|
}
|
|
5276
5362
|
|
|
5277
5363
|
// agent_safety_kit/observability/sinks/otel.ts
|
|
5278
|
-
var require2 =
|
|
5364
|
+
var require2 = createRequire2(import.meta.url);
|
|
5279
5365
|
function loadOpenTelemetryApi() {
|
|
5280
5366
|
try {
|
|
5281
5367
|
return require2("@opentelemetry/api");
|
|
@@ -7154,10 +7240,10 @@ async function testUpstreamConnection(name, config, options = {}) {
|
|
|
7154
7240
|
// src/server/monitor-server.ts
|
|
7155
7241
|
import { existsSync as existsSync10, unlinkSync as unlinkSync5 } from "fs";
|
|
7156
7242
|
import { createServer as createServer3 } from "net";
|
|
7157
|
-
function
|
|
7243
|
+
function isTcpEndpoint5(endpoint) {
|
|
7158
7244
|
return endpoint.startsWith("tcp://");
|
|
7159
7245
|
}
|
|
7160
|
-
function
|
|
7246
|
+
function parseTcpEndpoint5(endpoint) {
|
|
7161
7247
|
let url;
|
|
7162
7248
|
try {
|
|
7163
7249
|
url = new URL(endpoint);
|
|
@@ -7197,7 +7283,7 @@ class MonitorServer {
|
|
|
7197
7283
|
if (this.isRunning) {
|
|
7198
7284
|
return;
|
|
7199
7285
|
}
|
|
7200
|
-
const tcp =
|
|
7286
|
+
const tcp = isTcpEndpoint5(this.socketPath);
|
|
7201
7287
|
if (!tcp && existsSync10(this.socketPath)) {
|
|
7202
7288
|
try {
|
|
7203
7289
|
unlinkSync5(this.socketPath);
|
|
@@ -7218,7 +7304,7 @@ class MonitorServer {
|
|
|
7218
7304
|
reject(error);
|
|
7219
7305
|
});
|
|
7220
7306
|
if (tcp) {
|
|
7221
|
-
const { host, port } =
|
|
7307
|
+
const { host, port } = parseTcpEndpoint5(this.socketPath);
|
|
7222
7308
|
server.listen({ host, port }, () => {
|
|
7223
7309
|
const address = server.address();
|
|
7224
7310
|
if (address && typeof address !== "string") {
|
|
@@ -7252,7 +7338,7 @@ class MonitorServer {
|
|
|
7252
7338
|
}
|
|
7253
7339
|
});
|
|
7254
7340
|
});
|
|
7255
|
-
if (!
|
|
7341
|
+
if (!isTcpEndpoint5(this.socketPath)) {
|
|
7256
7342
|
try {
|
|
7257
7343
|
if (existsSync10(this.socketPath)) {
|
|
7258
7344
|
unlinkSync5(this.socketPath);
|
|
@@ -7609,7 +7695,7 @@ class McpSquaredServer {
|
|
|
7609
7695
|
guard;
|
|
7610
7696
|
constructor(options = {}) {
|
|
7611
7697
|
const name = options.name ?? "mcp-squared";
|
|
7612
|
-
const version = options.version ??
|
|
7698
|
+
const version = options.version ?? VERSION;
|
|
7613
7699
|
this.serverName = name;
|
|
7614
7700
|
this.serverVersion = version;
|
|
7615
7701
|
if (options.cataloger) {
|
|
@@ -8186,7 +8272,7 @@ async function startServer() {
|
|
|
8186
8272
|
startedAt: Date.now(),
|
|
8187
8273
|
cwd: process.cwd(),
|
|
8188
8274
|
configPath,
|
|
8189
|
-
version:
|
|
8275
|
+
version: VERSION,
|
|
8190
8276
|
command: process.argv.join(" "),
|
|
8191
8277
|
role: "server",
|
|
8192
8278
|
...launcher ? { launcher } : {}
|
|
@@ -8413,7 +8499,7 @@ Callback URL: ${callbackServer.getCallbackUrl()}`);
|
|
|
8413
8499
|
});
|
|
8414
8500
|
const client = new Client4({
|
|
8415
8501
|
name: "mcp-squared-auth",
|
|
8416
|
-
version:
|
|
8502
|
+
version: VERSION
|
|
8417
8503
|
});
|
|
8418
8504
|
console.log(`
|
|
8419
8505
|
Connecting to server...`);
|
|
@@ -8476,7 +8562,7 @@ async function runMonitor(options) {
|
|
|
8476
8562
|
if (!socketPath) {
|
|
8477
8563
|
const { config, path: configPath } = await loadConfig();
|
|
8478
8564
|
const configHash = computeConfigHash(config);
|
|
8479
|
-
const daemonRegistry = await
|
|
8565
|
+
const daemonRegistry = await loadLiveDaemonRegistry(configHash);
|
|
8480
8566
|
if (!daemonRegistry) {
|
|
8481
8567
|
console.error("Error: No running shared MCP\xB2 daemon found for the active configuration.");
|
|
8482
8568
|
console.error("Start the daemon first:");
|
|
@@ -8690,7 +8776,7 @@ async function runDaemon(options) {
|
|
|
8690
8776
|
startedAt: Date.now(),
|
|
8691
8777
|
cwd: process.cwd(),
|
|
8692
8778
|
configPath,
|
|
8693
|
-
version:
|
|
8779
|
+
version: VERSION,
|
|
8694
8780
|
command: process.argv.join(" "),
|
|
8695
8781
|
role: "daemon",
|
|
8696
8782
|
...daemonLauncher ? { launcher: daemonLauncher } : {}
|
|
@@ -8743,7 +8829,7 @@ async function runProxyCommand(options) {
|
|
|
8743
8829
|
startedAt: Date.now(),
|
|
8744
8830
|
cwd: process.cwd(),
|
|
8745
8831
|
configPath,
|
|
8746
|
-
version:
|
|
8832
|
+
version: VERSION,
|
|
8747
8833
|
command: process.argv.join(" "),
|
|
8748
8834
|
role: "proxy",
|
|
8749
8835
|
...proxyLauncher ? { launcher: proxyLauncher } : {}
|
|
@@ -8818,7 +8904,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
8818
8904
|
process.exit(0);
|
|
8819
8905
|
}
|
|
8820
8906
|
if (args.version) {
|
|
8821
|
-
console.log(`MCP\xB2 v${
|
|
8907
|
+
console.log(`MCP\xB2 v${VERSION}`);
|
|
8822
8908
|
process.exit(0);
|
|
8823
8909
|
}
|
|
8824
8910
|
switch (args.mode) {
|
|
@@ -8888,5 +8974,5 @@ export {
|
|
|
8888
8974
|
main,
|
|
8889
8975
|
logSecurityProfile,
|
|
8890
8976
|
logSearchModeProfile,
|
|
8891
|
-
|
|
8977
|
+
VERSION
|
|
8892
8978
|
};
|