@sanctuary-framework/mcp-server 1.1.3 → 1.1.5
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/cli.cjs +197 -6
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +198 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +25 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +26 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { argon2id } from 'hash-wasm';
|
|
|
12
12
|
import { hkdf } from '@noble/hashes/hkdf';
|
|
13
13
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
14
14
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
15
|
-
import {
|
|
15
|
+
import { existsSync, readFileSync, statSync, mkdirSync, writeFileSync, renameSync, chmodSync } from 'fs';
|
|
16
16
|
import { fileURLToPath } from 'url';
|
|
17
17
|
import { exec, execSync, spawn } from 'child_process';
|
|
18
18
|
import { createServer as createServer$2, get as get$1 } from 'http';
|
|
@@ -13354,7 +13354,7 @@ function renderDashboardV11Html(options = {}) {
|
|
|
13354
13354
|
streamUrl,
|
|
13355
13355
|
identityId,
|
|
13356
13356
|
fortressId
|
|
13357
|
-
});
|
|
13357
|
+
}).replace(/</g, "\\u003c");
|
|
13358
13358
|
const clientBlock = embedClient ? `<script type="module">${getClientScript()}</script>` : `<!-- client script omitted by render option -->`;
|
|
13359
13359
|
return `<!doctype html>
|
|
13360
13360
|
<html lang="en">
|
|
@@ -13385,7 +13385,7 @@ function renderDashboardV11Html(options = {}) {
|
|
|
13385
13385
|
<aside class="fortress" id="fortress"><p class="muted">Loading fortress column.</p></aside>
|
|
13386
13386
|
</div>
|
|
13387
13387
|
<div id="toast-host" aria-live="polite"></div>
|
|
13388
|
-
<script id="dashboard-config" type="application/json">${
|
|
13388
|
+
<script id="dashboard-config" type="application/json">${config}</script>
|
|
13389
13389
|
${clientBlock}
|
|
13390
13390
|
</body>
|
|
13391
13391
|
</html>`;
|
|
@@ -28580,8 +28580,69 @@ var init_hub = __esm({
|
|
|
28580
28580
|
init_api_router();
|
|
28581
28581
|
}
|
|
28582
28582
|
});
|
|
28583
|
+
function localAgentsFilePath(storagePath) {
|
|
28584
|
+
return join(storagePath, "state", "_hub", "local-agents.json");
|
|
28585
|
+
}
|
|
28586
|
+
function readPersistedLocalAgents(storagePath) {
|
|
28587
|
+
const filePath = localAgentsFilePath(storagePath);
|
|
28588
|
+
if (!existsSync(filePath)) return [];
|
|
28589
|
+
try {
|
|
28590
|
+
const raw = readFileSync(filePath, "utf8");
|
|
28591
|
+
const parsed = JSON.parse(raw);
|
|
28592
|
+
if (!parsed || !Array.isArray(parsed.agents)) return [];
|
|
28593
|
+
return parsed.agents;
|
|
28594
|
+
} catch {
|
|
28595
|
+
return [];
|
|
28596
|
+
}
|
|
28597
|
+
}
|
|
28598
|
+
function writePersistedLocalAgents(storagePath, agents) {
|
|
28599
|
+
const filePath = localAgentsFilePath(storagePath);
|
|
28600
|
+
const dir = dirname(filePath);
|
|
28601
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
28602
|
+
const payload = {
|
|
28603
|
+
version: PERSISTED_VERSION,
|
|
28604
|
+
agents
|
|
28605
|
+
};
|
|
28606
|
+
const tmpPath = `${filePath}.tmp`;
|
|
28607
|
+
writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}
|
|
28608
|
+
`, {
|
|
28609
|
+
mode: 384
|
|
28610
|
+
});
|
|
28611
|
+
renameSync(tmpPath, filePath);
|
|
28612
|
+
chmodSync(filePath, 384);
|
|
28613
|
+
}
|
|
28614
|
+
function upsertPersistedLocalAgent(storagePath, record) {
|
|
28615
|
+
const existing = readPersistedLocalAgents(storagePath);
|
|
28616
|
+
const idx = existing.findIndex((r) => r.agent_id === record.agent_id);
|
|
28617
|
+
let next;
|
|
28618
|
+
if (idx >= 0) {
|
|
28619
|
+
const prior = existing[idx];
|
|
28620
|
+
if (prior === void 0) {
|
|
28621
|
+
next = [...existing, record];
|
|
28622
|
+
} else {
|
|
28623
|
+
const updated = {
|
|
28624
|
+
...record,
|
|
28625
|
+
wrapped_at: prior.wrapped_at,
|
|
28626
|
+
last_activity_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
28627
|
+
};
|
|
28628
|
+
next = [...existing];
|
|
28629
|
+
next[idx] = updated;
|
|
28630
|
+
}
|
|
28631
|
+
} else {
|
|
28632
|
+
next = [...existing, record];
|
|
28633
|
+
}
|
|
28634
|
+
writePersistedLocalAgents(storagePath, next);
|
|
28635
|
+
return next;
|
|
28636
|
+
}
|
|
28637
|
+
var PERSISTED_VERSION;
|
|
28638
|
+
var init_agent_registry_persistence = __esm({
|
|
28639
|
+
"src/hub/agent-registry-persistence.ts"() {
|
|
28640
|
+
PERSISTED_VERSION = "1.1";
|
|
28641
|
+
}
|
|
28642
|
+
});
|
|
28583
28643
|
function buildV11Bindings(inputs) {
|
|
28584
|
-
const
|
|
28644
|
+
const seed = inputs.storagePath !== void 0 ? readPersistedLocalAgents(inputs.storagePath) : [];
|
|
28645
|
+
const registry = new InMemoryLocalAgentRegistry(seed);
|
|
28585
28646
|
const hubService = new HubService({
|
|
28586
28647
|
identityId: inputs.identityId,
|
|
28587
28648
|
fortressId: inputs.fortressId,
|
|
@@ -28619,6 +28680,7 @@ var init_wiring = __esm({
|
|
|
28619
28680
|
"src/dashboard/v1_1/wiring.ts"() {
|
|
28620
28681
|
init_hub();
|
|
28621
28682
|
init_errors4();
|
|
28683
|
+
init_agent_registry_persistence();
|
|
28622
28684
|
CapabilityErrorAgentController = class {
|
|
28623
28685
|
fail(action) {
|
|
28624
28686
|
throw new HubCapabilityError(
|
|
@@ -30651,7 +30713,12 @@ Refusing to start the cocoon while the reset-history marker is unreadable.`
|
|
|
30651
30713
|
buildV11Bindings({
|
|
30652
30714
|
identityId: embeddedHubIdentityId,
|
|
30653
30715
|
fortressId: fortressIdFromStoragePath(config.storage_path),
|
|
30654
|
-
auditLog
|
|
30716
|
+
auditLog,
|
|
30717
|
+
// v1.1.5 (Finding Z): rehydrate the hub agent registry from
|
|
30718
|
+
// `<storagePath>/state/_hub/local-agents.json` so the embedded
|
|
30719
|
+
// dashboard surfaces wraps performed by prior `sanctuary wrap`
|
|
30720
|
+
// invocations against this same fortress.
|
|
30721
|
+
storagePath: config.storage_path
|
|
30655
30722
|
})
|
|
30656
30723
|
);
|
|
30657
30724
|
await dashboard.start();
|
|
@@ -31294,6 +31361,7 @@ __export(cli_exports, {
|
|
|
31294
31361
|
PORT_FALLBACK_ATTEMPTS: () => PORT_FALLBACK_ATTEMPTS,
|
|
31295
31362
|
formatMcpServerCount: () => formatMcpServerCount,
|
|
31296
31363
|
formatWrapSuccess: () => formatWrapSuccess,
|
|
31364
|
+
formatWrapSuccessNoDashboard: () => formatWrapSuccessNoDashboard,
|
|
31297
31365
|
parseCocoonArgs: () => parseCocoonArgs,
|
|
31298
31366
|
parseWrapArgs: () => parseWrapArgs,
|
|
31299
31367
|
promoteFortressToStoragePath: () => promoteFortressToStoragePath,
|
|
@@ -31566,6 +31634,28 @@ async function runWrap(options, deps = {}) {
|
|
|
31566
31634
|
backupPath
|
|
31567
31635
|
);
|
|
31568
31636
|
if (!verifyOk) process.exit(1);
|
|
31637
|
+
try {
|
|
31638
|
+
upsertPersistedLocalAgent(
|
|
31639
|
+
storagePath,
|
|
31640
|
+
buildLocalAgentRecord({
|
|
31641
|
+
storagePath,
|
|
31642
|
+
platform: agentConfig.platform
|
|
31643
|
+
})
|
|
31644
|
+
);
|
|
31645
|
+
} catch (err) {
|
|
31646
|
+
console.error(
|
|
31647
|
+
` Note: v1.1 hub agent record not persisted (${err.message}). Re-run \`sanctuary wrap\` to retry, or check storage permissions on ${storagePath}.`
|
|
31648
|
+
);
|
|
31649
|
+
}
|
|
31650
|
+
if (options.noDashboard) {
|
|
31651
|
+
const toolName2 = toolNameFor(agentConfig.platform, agentConfig.servers);
|
|
31652
|
+
printWrapSuccessNoDashboard({
|
|
31653
|
+
toolName: toolName2,
|
|
31654
|
+
version: readPackageVersion(),
|
|
31655
|
+
toolCount: countUpstreamTools(upstreamServers),
|
|
31656
|
+
serverCount: upstreamServers.length});
|
|
31657
|
+
return;
|
|
31658
|
+
}
|
|
31569
31659
|
const authToken = generateAuthToken();
|
|
31570
31660
|
const startFn = deps.startDashboard ?? ((opts) => startDashboard({
|
|
31571
31661
|
port: opts.port,
|
|
@@ -31605,7 +31695,12 @@ async function runWrap(options, deps = {}) {
|
|
|
31605
31695
|
buildV11Bindings({
|
|
31606
31696
|
identityId: `fortress:${storagePath}`,
|
|
31607
31697
|
fortressId: fortressIdFromStoragePath(storagePath),
|
|
31608
|
-
auditLog: wrapAuditLog
|
|
31698
|
+
auditLog: wrapAuditLog,
|
|
31699
|
+
// v1.1.5 (Finding Z): rehydrate from the file the upsert
|
|
31700
|
+
// above just wrote, so the registry the wrap-auto dashboard
|
|
31701
|
+
// serves contains this wrap plus any prior wraps against the
|
|
31702
|
+
// same fortress.
|
|
31703
|
+
storagePath
|
|
31609
31704
|
})
|
|
31610
31705
|
);
|
|
31611
31706
|
dashboard.setV11LoopbackAutoAuth(true);
|
|
@@ -31745,6 +31840,32 @@ function formatWrapSuccess(info) {
|
|
|
31745
31840
|
function printWrapSuccess(info) {
|
|
31746
31841
|
console.error(formatWrapSuccess(info));
|
|
31747
31842
|
}
|
|
31843
|
+
function formatWrapSuccessNoDashboard(info) {
|
|
31844
|
+
const g = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
31845
|
+
const d = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
31846
|
+
const b = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
31847
|
+
const check = "\u2713";
|
|
31848
|
+
const lines = [];
|
|
31849
|
+
lines.push("");
|
|
31850
|
+
lines.push(
|
|
31851
|
+
` ${g(check)} Wrapped ${b(info.toolName)} with Sanctuary v${info.version}`
|
|
31852
|
+
);
|
|
31853
|
+
lines.push(
|
|
31854
|
+
` ${g(check)} ${info.toolCount} tools registered across ${info.serverCount} upstream server${info.serverCount !== 1 ? "s" : ""}`
|
|
31855
|
+
);
|
|
31856
|
+
lines.push(
|
|
31857
|
+
` ${d("Dashboard spawn skipped per --no-dashboard. Run `sanctuary dashboard` separately for a persistent dashboard.")}`
|
|
31858
|
+
);
|
|
31859
|
+
lines.push("");
|
|
31860
|
+
lines.push(
|
|
31861
|
+
` ${b("Your agent is protected.")} L1 Full / L2 Degraded (no TEE) / L3 Full / L4 Full.`
|
|
31862
|
+
);
|
|
31863
|
+
lines.push("");
|
|
31864
|
+
return lines.join("\n");
|
|
31865
|
+
}
|
|
31866
|
+
function printWrapSuccessNoDashboard(info) {
|
|
31867
|
+
console.error(formatWrapSuccessNoDashboard(info));
|
|
31868
|
+
}
|
|
31748
31869
|
async function verifyRewrittenConfig(configPath, backupPath) {
|
|
31749
31870
|
try {
|
|
31750
31871
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -31861,6 +31982,57 @@ function toolNameFor(platform4, _servers) {
|
|
|
31861
31982
|
return "your agent";
|
|
31862
31983
|
}
|
|
31863
31984
|
}
|
|
31985
|
+
function harnessKindForPlatform(platform4) {
|
|
31986
|
+
switch (platform4) {
|
|
31987
|
+
case "openclaw":
|
|
31988
|
+
return "openclaw";
|
|
31989
|
+
case "hermes":
|
|
31990
|
+
return "hermes";
|
|
31991
|
+
case "claude-code":
|
|
31992
|
+
return "claude_code";
|
|
31993
|
+
case "cursor":
|
|
31994
|
+
return "cursor";
|
|
31995
|
+
case "cline":
|
|
31996
|
+
return "cline";
|
|
31997
|
+
case "generic":
|
|
31998
|
+
return "generic_mcp";
|
|
31999
|
+
default: {
|
|
32000
|
+
return "other";
|
|
32001
|
+
}
|
|
32002
|
+
}
|
|
32003
|
+
}
|
|
32004
|
+
function buildLocalAgentRecord(input) {
|
|
32005
|
+
const harness = harnessKindForPlatform(input.platform);
|
|
32006
|
+
const fortressId = fortressIdFromStoragePath(input.storagePath);
|
|
32007
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
32008
|
+
return {
|
|
32009
|
+
version: "1.1",
|
|
32010
|
+
agent_id: `agent:${harness}:${fortressId}`,
|
|
32011
|
+
identity_id: `fortress:${input.storagePath}`,
|
|
32012
|
+
harness,
|
|
32013
|
+
model_provider: {
|
|
32014
|
+
vendor: "unknown",
|
|
32015
|
+
model_id: "unknown",
|
|
32016
|
+
runs_locally: false
|
|
32017
|
+
},
|
|
32018
|
+
policy_id: "unbound",
|
|
32019
|
+
status: "active",
|
|
32020
|
+
budget_summary: {
|
|
32021
|
+
last_refreshed_at: nowIso
|
|
32022
|
+
},
|
|
32023
|
+
last_activity_at: nowIso,
|
|
32024
|
+
wrapped_at: nowIso,
|
|
32025
|
+
capabilities: {
|
|
32026
|
+
can_pause: false,
|
|
32027
|
+
can_resume: false,
|
|
32028
|
+
can_restart: false,
|
|
32029
|
+
can_unwrap: true,
|
|
32030
|
+
can_lockdown: false,
|
|
32031
|
+
can_chat: false,
|
|
32032
|
+
can_change_template: false
|
|
32033
|
+
}
|
|
32034
|
+
};
|
|
32035
|
+
}
|
|
31864
32036
|
function countUpstreamTools(servers) {
|
|
31865
32037
|
return servers.length === 0 ? 0 : servers.length;
|
|
31866
32038
|
}
|
|
@@ -31921,6 +32093,9 @@ function parseWrapArgs(argv) {
|
|
|
31921
32093
|
case "--no-open":
|
|
31922
32094
|
options.noOpen = true;
|
|
31923
32095
|
break;
|
|
32096
|
+
case "--no-dashboard":
|
|
32097
|
+
options.noDashboard = true;
|
|
32098
|
+
break;
|
|
31924
32099
|
case "--fortress":
|
|
31925
32100
|
options.fortress = argv[++i];
|
|
31926
32101
|
break;
|
|
@@ -31961,6 +32136,11 @@ function printWrapHelp() {
|
|
|
31961
32136
|
--port <port> Preferred dashboard port (default: 3501)
|
|
31962
32137
|
--dry-run Show what would happen without making changes
|
|
31963
32138
|
--no-open Do not auto-open the dashboard in a browser
|
|
32139
|
+
--no-dashboard Do not spawn a per-call dashboard server. Wrap still
|
|
32140
|
+
persists the agent record so a separately-running
|
|
32141
|
+
\`sanctuary dashboard\` (or a later wrap) sees the
|
|
32142
|
+
harness. Use this for the clean operator setup
|
|
32143
|
+
(one persistent dashboard + many wraps).
|
|
31964
32144
|
--help, -h Show this help
|
|
31965
32145
|
|
|
31966
32146
|
What happens:
|
|
@@ -31978,6 +32158,7 @@ var init_cli2 = __esm({
|
|
|
31978
32158
|
init_passphrase();
|
|
31979
32159
|
init_dashboard2();
|
|
31980
32160
|
init_wiring();
|
|
32161
|
+
init_agent_registry_persistence();
|
|
31981
32162
|
init_filesystem();
|
|
31982
32163
|
init_key_derivation();
|
|
31983
32164
|
init_encoding();
|
|
@@ -35615,7 +35796,12 @@ Refusing to start the dashboard while the reset-history marker is unreadable.`
|
|
|
35615
35796
|
buildV11Bindings({
|
|
35616
35797
|
identityId: hubIdentityId,
|
|
35617
35798
|
fortressId: fortressIdFromStoragePath(config.storage_path),
|
|
35618
|
-
auditLog
|
|
35799
|
+
auditLog,
|
|
35800
|
+
// v1.1.5 (Finding Z): rehydrate the hub agent registry from
|
|
35801
|
+
// `<storagePath>/state/_hub/local-agents.json` so the standalone
|
|
35802
|
+
// dashboard surfaces wraps performed by prior `sanctuary wrap`
|
|
35803
|
+
// invocations against this same fortress.
|
|
35804
|
+
storagePath: config.storage_path
|
|
35619
35805
|
})
|
|
35620
35806
|
);
|
|
35621
35807
|
const hostIsLoopback = dashboardHost === "127.0.0.1" || dashboardHost === "::1" || dashboardHost === "localhost";
|
|
@@ -35645,6 +35831,10 @@ Refusing to start the dashboard while the reset-history marker is unreadable.`
|
|
|
35645
35831
|
console.error(`Sanctuary Dashboard v${SANCTUARY_VERSION} (standalone mode)`);
|
|
35646
35832
|
console.error(`Storage: ${config.storage_path}`);
|
|
35647
35833
|
console.error(`Identities loaded: ${loadResult.loaded}`);
|
|
35834
|
+
const persistedAgentsCount = readPersistedLocalAgents(
|
|
35835
|
+
config.storage_path
|
|
35836
|
+
).length;
|
|
35837
|
+
console.error(`Local agents loaded: ${persistedAgentsCount}`);
|
|
35648
35838
|
console.error(`Listening: http://${dashboardHost}:${dashboardPort}`);
|
|
35649
35839
|
if (loadResult.total > 0 && loadResult.loaded === 0) {
|
|
35650
35840
|
const service = keychainServiceFor(config.storage_path, homedir());
|
|
@@ -35703,6 +35893,7 @@ var init_dashboard_standalone = __esm({
|
|
|
35703
35893
|
init_recovery_key_disclosure();
|
|
35704
35894
|
init_discovery();
|
|
35705
35895
|
init_wiring();
|
|
35896
|
+
init_agent_registry_persistence();
|
|
35706
35897
|
}
|
|
35707
35898
|
});
|
|
35708
35899
|
|