enigma-memory 0.1.18 → 0.1.22
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/README.md +76 -24
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +1923 -285
- package/apps/desktop/electron-main.cjs +217 -0
- package/apps/desktop/package.json +12 -0
- package/apps/desktop/src/app.js +264 -7
- package/apps/desktop/src/index.html +3514 -1373
- package/apps/desktop/src/launch-electron.mjs +51 -0
- package/apps/desktop/src/server.mjs +2914 -0
- package/apps/desktop/src/styles.css +2972 -260
- package/apps/desktop/src/zk-browser-prove.mjs +53 -0
- package/apps/desktop/src/zk-state.mjs +1789 -0
- package/apps/gateway/bin/enigma-gateway.mjs +102 -5
- package/apps/gateway/src/server.mjs +271 -8
- package/apps/ios/EnigmaCore/Package.swift +12 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
- package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
- package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
- package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
- package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
- package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
- package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
- package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
- package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
- package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
- package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
- package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
- package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
- package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
- package/apps/native-host/README.md +19 -8
- package/apps/native-host/bin/enigma-native-host.mjs +229 -13
- package/apps/relay/bin/enigma-relay.mjs +103 -5
- package/apps/relay/src/federation-runtime.mjs +618 -0
- package/apps/relay/src/server.mjs +310 -9
- package/apps/verifier/bin/enigma-verify.mjs +327 -11
- package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/vk_bytes.json +32 -0
- package/cortex-v3/proving-assets.json +64 -0
- package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
- package/cortex-v3/zk/action-transition-vk.json +119 -0
- package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
- package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
- package/cortex-v3/zk/intent-witness.mjs +365 -0
- package/cortex-v3/zk/intent-witness.test.mjs +485 -0
- package/cortex-v3/zk/proving-assets.mjs +203 -0
- package/cortex-v3/zk/sale-witness.mjs +783 -0
- package/cortex-v3/zk/sale-witness.test.mjs +784 -0
- package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
- package/cortex-v3/zk/settlement-evidence.mjs +722 -0
- package/cortex-v3/zk/setup-intent.mjs +688 -0
- package/cortex-v3/zk/setup-sale.mjs +666 -0
- package/cortex-v3/zk/setup.mjs +594 -0
- package/cortex-v3/zk/witness.mjs +184 -0
- package/cortex-v3/zk/zk-codec.mjs +232 -0
- package/cortex-v3/zk/zk-codec.test.mjs +293 -0
- package/cortex-v3/zk/zk-settle.mjs +370 -0
- package/cortex-v3/zk/zk-tree.mjs +256 -0
- package/cortex-v3/zk/zk-tree.test.mjs +419 -0
- package/deploy/docker-compose.local-production-simulation.yml +36 -0
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +15 -11
- package/docs/developer-ecosystem.md +15 -13
- package/docs/enigma-memory-ready-conformance.md +11 -9
- package/docs/install-anywhere.md +61 -28
- package/docs/installers-and-desktop.md +8 -7
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-claim-boundaries.md +320 -318
- package/examples/01-quickstart-agent/index.mjs +49 -0
- package/examples/01_agent_memory_quickstart.mjs +57 -0
- package/examples/02-multi-agent-swarm/index.mjs +57 -0
- package/examples/02_cross_model_passport.mjs +64 -0
- package/examples/03-langchain-memory/index.mjs +41 -0
- package/examples/03_poseidon_commitment_verification.mjs +71 -0
- package/examples/04-python-trading-agent/trader.py +49 -0
- package/examples/README.md +27 -0
- package/examples/ci/github-actions.yml +7 -2
- package/package.json +142 -11
- package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
- package/packages/connectors/src/index.js +196 -4
- package/packages/connectors/swarm-router.mjs +168 -0
- package/packages/core/src/index.js +248 -1
- package/packages/core/src/version.mjs +7 -0
- package/packages/dev-tools/package.json +19 -0
- package/packages/dev-tools/src/index.js +4 -0
- package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
- package/packages/dev-tools/src/swarm-simulator.js +101 -0
- package/packages/dev-tools/src/vault-inspector.js +114 -0
- package/packages/dev-tools/src/vector-benchmark.js +100 -0
- package/packages/developer-platform/src/access-credentials.js +341 -0
- package/packages/developer-platform/src/http.js +132 -0
- package/packages/developer-platform/src/index.js +4 -0
- package/packages/developer-platform/src/usage-http.js +60 -0
- package/packages/developer-platform/src/usage.js +295 -0
- package/packages/enclave-runtime/attestation.mjs +159 -0
- package/packages/enclave-runtime/index.mjs +47 -0
- package/packages/enclave-runtime/session-manager.mjs +253 -0
- package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
- package/packages/enigma-reflex/package.json +14 -0
- package/packages/enigma-reflex/src/index.js +204 -0
- package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
- package/packages/enigma-reflex/training/requirements.txt +8 -0
- package/packages/enigma-reflex/training/train.py +314 -0
- package/packages/enigma-weave/LICENSE +22 -0
- package/packages/enigma-weave/UPSTREAM.json +21 -0
- package/packages/enigma-weave/package.json +14 -0
- package/packages/enigma-weave/src/index.js +286 -0
- package/packages/hosted-cloud/src/index.js +80 -5
- package/packages/importers/src/index.js +432 -0
- package/packages/inference-runtime/src/browser.js +401 -0
- package/packages/inference-runtime/src/chat.js +265 -0
- package/packages/inference-runtime/src/code.js +407 -0
- package/packages/inference-runtime/src/contracts.js +162 -0
- package/packages/inference-runtime/src/http.js +232 -0
- package/packages/inference-runtime/src/image.js +186 -0
- package/packages/inference-runtime/src/index.js +10 -0
- package/packages/inference-runtime/src/model-router.js +320 -0
- package/packages/inference-runtime/src/platform.js +125 -0
- package/packages/inference-runtime/src/privacy.js +400 -0
- package/packages/inference-runtime/src/video.js +253 -0
- package/packages/mcp-server/README.md +22 -6
- package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
- package/packages/mcp-server/src/index.js +1418 -105
- package/packages/mcp-server/src/oauth.js +561 -0
- package/packages/mcp-server/src/private-handoff.js +84 -0
- package/packages/mcp-server/src/remote-http.js +273 -0
- package/packages/mcp-server/src/remote-policy.js +72 -0
- package/packages/mcp-server/swarm-bridge.mjs +361 -0
- package/packages/mesh/index.d.ts +283 -0
- package/packages/mesh/package.json +23 -0
- package/packages/mesh/src/crypto.js +189 -0
- package/packages/mesh/src/federation-packets.js +353 -0
- package/packages/mesh/src/gossip.js +311 -0
- package/packages/mesh/src/index.js +6 -0
- package/packages/mesh/src/protocol.js +255 -0
- package/packages/mesh/src/router.js +279 -0
- package/packages/mesh/src/transport.js +306 -0
- package/packages/passport/src/index.js +426 -1
- package/packages/private-economy/src/credits-http.js +100 -0
- package/packages/private-economy/src/credits.js +447 -0
- package/packages/private-economy/src/index.js +5 -0
- package/packages/private-economy/src/payments-http.js +120 -0
- package/packages/private-economy/src/payments.js +509 -0
- package/packages/private-economy/src/x402.js +346 -0
- package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
- package/packages/rag/index.d.ts +182 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
- package/packages/rag/package.json +27 -0
- package/packages/rag/src/blinded-search.js +109 -0
- package/packages/rag/src/bm25.js +169 -0
- package/packages/rag/src/embeddings.js +459 -0
- package/packages/rag/src/hybrid.js +76 -0
- package/packages/rag/src/index.js +38 -0
- package/packages/rag/src/reranker.js +61 -0
- package/packages/rag/src/research.js +107 -0
- package/packages/rag/src/vector-store.js +430 -0
- package/packages/rag/src/verify-model-artifacts.mjs +4 -0
- package/packages/sdk/index.d.ts +760 -0
- package/packages/sdk/package.json +33 -0
- package/packages/sdk/python/README.md +24 -0
- package/packages/sdk/python/enigma_sdk.py +250 -0
- package/packages/sdk/python/pyproject.toml +34 -0
- package/packages/sdk/python/requirements.txt +1 -0
- package/packages/sdk/python/setup.py +20 -0
- package/packages/sdk/src/federation/capability-grant.js +389 -0
- package/packages/sdk/src/federation/federation-router.js +360 -0
- package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
- package/packages/sdk/src/federation/index.js +3 -0
- package/packages/sdk/src/index.js +1796 -0
- package/packages/sdk/src/intelligence/contradiction.js +337 -0
- package/packages/sdk/src/intelligence/decision-engine.js +155 -0
- package/packages/sdk/src/intelligence/index.js +4 -0
- package/packages/sdk/src/intelligence/ontology.js +122 -0
- package/packages/sdk/src/intelligence/temporal.js +123 -0
- package/packages/sdk/src/market-client.js +142 -0
- package/packages/sdk/src/mesh-client.js +110 -0
- package/packages/sdk/src/middleware/index.js +3 -0
- package/packages/sdk/src/middleware/langchain.js +159 -0
- package/packages/sdk/src/middleware/llamaindex.js +101 -0
- package/packages/sdk/src/middleware/vercel-ai.js +112 -0
- package/packages/sdk/src/rag-client.js +85 -0
- package/packages/sdk/src/swarm-orchestrator.js +260 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
- package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
- package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
- package/packages/snapcompact/index.d.ts +284 -0
- package/packages/snapcompact/package.json +25 -0
- package/packages/snapcompact/src/index.js +716 -0
- package/packages/storage/PACKAGE_CONTRACT.md +1 -1
- package/packages/terminal-console/animations.mjs +240 -0
- package/packages/terminal-console/auto-anchor.mjs +220 -0
- package/packages/terminal-console/banner.mjs +91 -0
- package/packages/terminal-console/commands.mjs +459 -0
- package/packages/terminal-console/delegation.mjs +152 -0
- package/packages/terminal-console/index.mjs +5 -0
- package/packages/terminal-console/outbox.mjs +143 -0
- package/packages/terminal-console/phantom-bridge.mjs +637 -0
- package/packages/terminal-console/repl.mjs +136 -0
- package/packages/terminal-console/signer-store.mjs +130 -0
- package/packages/terminal-console/solana-rpc.mjs +214 -0
- package/packages/terminal-console/solana-transport.mjs +189 -0
- package/packages/terminal-tui/dashboard.mjs +214 -0
- package/packages/terminal-tui/index.mjs +28 -0
- package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
- package/packages/terminal-tui/telemetry-hud.mjs +137 -0
- package/packages/vault/index.d.ts +449 -0
- package/packages/vault/package.json +27 -0
- package/packages/vault/src/e2ee.mjs +393 -0
- package/packages/vault/src/enclave.js +481 -0
- package/packages/vault/src/erasure.js +207 -0
- package/packages/vault/src/index.js +1018 -155
- package/packages/vault/src/persistence.js +307 -0
- package/packages/vault/src/poseidon.js +354 -0
- package/packages/vault/src/receipt.js +459 -0
- package/scripts/benchmark-optical-context.mjs +166 -0
- package/scripts/bootstrap-enigma.mjs +502 -0
- package/scripts/build-edge-backend-workers.mjs +20 -5
- package/scripts/build-goal-completion-audit.mjs +72 -25
- package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
- package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +41 -21
- package/scripts/build-operator-evidence-starter.mjs +59 -1
- package/scripts/build-production-backend-env-kit.mjs +2 -0
- package/scripts/build-production-unblocker.mjs +3 -0
- package/scripts/check.mjs +17 -3
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +65 -109
- package/scripts/release-provenance.mjs +6 -0
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/scan-secrets.mjs +1 -0
- package/scripts/simulate-production-env.mjs +7 -2
- package/scripts/validate-hosted-backend-live.mjs +112 -1
- package/specs/antibody-pack-v1.schema.json +95 -0
- package/specs/antigen-envelope-v1.schema.json +81 -0
- package/specs/boundary-manifest-v1.schema.json +35 -35
- package/specs/capsule-v1.schema.json +55 -55
- package/specs/claim-boundary-manifest-v1.schema.json +22 -22
- package/specs/claim-ledger-v1.schema.json +291 -0
- package/specs/context-passport-v1.schema.json +59 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -26
- package/specs/evidence-packet-v1.schema.json +177 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
- package/specs/immune-scan-report-v1.schema.json +112 -0
- package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
- package/specs/memory-atom-v1.schema.json +59 -0
- package/specs/memory-event-v1.schema.json +42 -42
- package/specs/passport-v1.schema.json +50 -50
- package/specs/proof-of-non-use-v1.schema.json +65 -0
- package/specs/quarantine-record-v1.schema.json +126 -0
- package/specs/receipt-v1.schema.json +61 -61
- package/specs/state-checkpoint-v1.schema.json +37 -37
- package/specs/trust-bundle-v1.schema.json +56 -56
- package/specs/trust-card-v1.schema.json +119 -0
- package/docs/proof-network-launch-plan.md +0 -421
- package/packages/metering/PACKAGE_CONTRACT.md +0 -20
- package/scripts/build-ai-orchestration-plan.mjs +0 -248
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHmac, randomBytes } from 'node:crypto';
|
|
2
|
+
import { access, readFile } from 'node:fs/promises';
|
|
3
|
+
import { ENIGMA_VERSION } from '../../core/src/version.mjs';
|
|
2
4
|
import { createInterface } from 'node:readline';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import {
|
|
7
|
+
createVault,
|
|
8
|
+
remember,
|
|
9
|
+
recall,
|
|
10
|
+
deleteMemory,
|
|
11
|
+
exportBundle,
|
|
12
|
+
importBundle,
|
|
13
|
+
rotateContentKey,
|
|
14
|
+
sealContentKeyEpoch,
|
|
15
|
+
resetVaultContentKeys,
|
|
16
|
+
SimulatedEnclaveProvider,
|
|
17
|
+
AttestationVerifier,
|
|
18
|
+
createPoseidonCommitment,
|
|
19
|
+
verifyPoseidonCommitment,
|
|
20
|
+
} from '../../vault/src/index.js';
|
|
21
|
+
import {
|
|
22
|
+
readJsonFileWithRevision,
|
|
23
|
+
withBundleFileLock,
|
|
24
|
+
writeJsonFileAtomic,
|
|
25
|
+
} from '../../vault/src/persistence.js';
|
|
5
26
|
import { createPassport, compileContextPack } from '../../passport/src/index.js';
|
|
6
27
|
import { verifyBundle } from '../../../apps/verifier/bin/enigma-verify.mjs';
|
|
7
28
|
import { aggregateUsageEvents, createUsageEvent } from '../../metering/src/index.js';
|
|
@@ -13,11 +34,126 @@ import {
|
|
|
13
34
|
createSettlementBatch,
|
|
14
35
|
verifyServiceSettlementReceipt,
|
|
15
36
|
} from '../../settlement/src/index.js';
|
|
37
|
+
import {
|
|
38
|
+
assertImmuneIngressPublicSafe,
|
|
39
|
+
createImmuneIngressReport,
|
|
40
|
+
} from '../../importers/src/index.js';
|
|
41
|
+
import {
|
|
42
|
+
enigma_cluster_memories as routeClusterMemories,
|
|
43
|
+
enigma_graph_query as routeGraphQuery,
|
|
44
|
+
enigma_swarm_register_agent as routeSwarmRegisterAgent,
|
|
45
|
+
enigma_swarm_sync as routeSwarmSync,
|
|
46
|
+
} from '../../connectors/swarm-router.mjs';
|
|
47
|
+
import {
|
|
48
|
+
DEFAULT_DESKTOP_ORIGIN,
|
|
49
|
+
PRIVATE_SESSION_RESOURCE_URI,
|
|
50
|
+
createPrivateSessionHttpUrl,
|
|
51
|
+
createPrivateSessionProtocolUrl,
|
|
52
|
+
validateLoopbackDesktopOrigin,
|
|
53
|
+
validatePrivateHandoffIntent,
|
|
54
|
+
validatePrivateHandoffModel,
|
|
55
|
+
} from './private-handoff.js';
|
|
56
|
+
import { assertRemoteToolPolicyCoverage, remoteToolPolicy, requiredScopesForMcpPayload } from './remote-policy.js';
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const defaultEnclave = new SimulatedEnclaveProvider({ simulationLabel: 'enigma_mcp_runtime' });
|
|
16
60
|
|
|
17
61
|
const DEFAULT_BUNDLE = '.enigma/bundle.json';
|
|
18
62
|
const JSONRPC_VERSION = '2.0';
|
|
19
63
|
const MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
20
|
-
const SERVER_INFO = Object.freeze({ name: 'enigma-mcp-server', version:
|
|
64
|
+
const SERVER_INFO = Object.freeze({ name: 'enigma-mcp-server', version: ENIGMA_VERSION });
|
|
65
|
+
const UNLOCKED_VAULT_CACHE_LIMIT = 8;
|
|
66
|
+
const unlockedVaultCache = new Map();
|
|
67
|
+
const cacheAuthenticationKey = randomBytes(32);
|
|
68
|
+
let configuredCheckpointProvider = null;
|
|
69
|
+
let configuredInferenceRuntime = null;
|
|
70
|
+
let configuredX402Client = null;
|
|
71
|
+
const REMOTE_SECURE_VAULT = Symbol('enigma.remote_secure_vault');
|
|
72
|
+
|
|
73
|
+
function enigmaDesktopOrigin() {
|
|
74
|
+
return validateLoopbackDesktopOrigin(process.env.ENIGMA_DESKTOP_URL || DEFAULT_DESKTOP_ORIGIN);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function privateSessionUrl(input = {}) {
|
|
78
|
+
return process.env.ENIGMA_DESKTOP_URL
|
|
79
|
+
? createPrivateSessionHttpUrl(input, enigmaDesktopOrigin())
|
|
80
|
+
: createPrivateSessionProtocolUrl(input);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function rejectSensitiveHandoffIntent(intent) {
|
|
84
|
+
try {
|
|
85
|
+
validatePrivateHandoffIntent(intent);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw invalidParams(error.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function configureVaultCheckpointProvider(provider = null) {
|
|
92
|
+
if (provider !== null && (typeof provider?.load !== 'function' || typeof provider?.advance !== 'function')) {
|
|
93
|
+
throw new TypeError('checkpoint provider requires load and advance functions');
|
|
94
|
+
}
|
|
95
|
+
configuredCheckpointProvider = provider;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function configureMcpInferenceRuntime(runtime = null) {
|
|
99
|
+
const hasChat = typeof runtime?.chat?.complete === 'function';
|
|
100
|
+
const hasImages = typeof runtime?.images?.generate === 'function';
|
|
101
|
+
if (runtime !== null && !hasChat && !hasImages) {
|
|
102
|
+
throw new TypeError('MCP inference runtime requires chat.complete() or images.generate()');
|
|
103
|
+
}
|
|
104
|
+
configuredInferenceRuntime = runtime;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function configureMcpX402Client(client = null) {
|
|
108
|
+
if (client !== null && typeof client !== 'function') throw new TypeError('MCP x402 client must be a function');
|
|
109
|
+
configuredX402Client = client;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function credentialCacheTag(credentials) {
|
|
113
|
+
return createHmac('sha256', cacheAuthenticationKey)
|
|
114
|
+
.update(credentials.passphrase ?? (credentials.insecureDevMode ? 'insecure-dev' : 'missing'))
|
|
115
|
+
.digest('hex');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function zeroizeCachedVault(entry) {
|
|
119
|
+
const vault = entry?.vault;
|
|
120
|
+
if (!vault) return;
|
|
121
|
+
for (const epoch of vault.keyEpochs?.values?.() ?? []) epoch.key?.fill?.(0);
|
|
122
|
+
vault.addressKey?.fill?.(0);
|
|
123
|
+
for (const record of vault.memories?.values?.() ?? []) {
|
|
124
|
+
if (Object.prototype.hasOwnProperty.call(record, 'plaintext')) delete record.plaintext;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function invalidateCachedVault(path) {
|
|
129
|
+
const key = resolve(String(path));
|
|
130
|
+
const prior = unlockedVaultCache.get(key);
|
|
131
|
+
unlockedVaultCache.delete(key);
|
|
132
|
+
zeroizeCachedVault(prior);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function cacheUnlockedVault(path, entry) {
|
|
136
|
+
const key = resolve(String(path));
|
|
137
|
+
const prior = unlockedVaultCache.get(key);
|
|
138
|
+
if (prior && prior.vault !== entry.vault) zeroizeCachedVault(prior);
|
|
139
|
+
unlockedVaultCache.delete(key);
|
|
140
|
+
unlockedVaultCache.set(key, entry);
|
|
141
|
+
while (unlockedVaultCache.size > UNLOCKED_VAULT_CACHE_LIMIT) {
|
|
142
|
+
const oldestKey = unlockedVaultCache.keys().next().value;
|
|
143
|
+
const oldest = unlockedVaultCache.get(oldestKey);
|
|
144
|
+
unlockedVaultCache.delete(oldestKey);
|
|
145
|
+
zeroizeCachedVault(oldest);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function clearUnlockedVaultCache() {
|
|
149
|
+
for (const entry of unlockedVaultCache.values()) zeroizeCachedVault(entry);
|
|
150
|
+
unlockedVaultCache.clear();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
process.once('exit', () => {
|
|
154
|
+
clearUnlockedVaultCache();
|
|
155
|
+
cacheAuthenticationKey.fill(0);
|
|
156
|
+
});
|
|
21
157
|
const JSON_RPC_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
22
158
|
const JSON_RPC_ERROR = Object.freeze({
|
|
23
159
|
INVALID_REQUEST: -32600,
|
|
@@ -121,28 +257,131 @@ function optionalObjectArray(object, key, context) {
|
|
|
121
257
|
}
|
|
122
258
|
}
|
|
123
259
|
|
|
260
|
+
function optionalIntegerRange(object, key, context, minimum, maximum) {
|
|
261
|
+
if (object[key] === undefined) return;
|
|
262
|
+
if (!Number.isInteger(object[key]) || object[key] < minimum || object[key] > maximum) {
|
|
263
|
+
throw invalidParams(`${context} ${key} must be an integer from ${minimum} through ${maximum}.`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function optionalPermissionMask(object, key, context) {
|
|
268
|
+
const value = object[key];
|
|
269
|
+
if (value === undefined) return;
|
|
270
|
+
const validNumber = Number.isInteger(value) && value >= 0 && value <= 63;
|
|
271
|
+
const validString = typeof value === 'string';
|
|
272
|
+
const validArray = Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
273
|
+
if (!validNumber && !validString && !validArray) {
|
|
274
|
+
throw invalidParams(`${context} ${key} must be a permission bitmask, string, or array of strings.`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function maximumStringLength(object, key, context, maximum) {
|
|
279
|
+
if (typeof object[key] === 'string' && object[key].length > maximum) {
|
|
280
|
+
throw invalidParams(`${context} ${key} exceeds ${maximum} characters.`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function validateCompletionMessages(messages, context) {
|
|
285
|
+
if (!Array.isArray(messages) || messages.length < 1 || messages.length > 128) {
|
|
286
|
+
throw invalidParams(`${context} messages must contain one through 128 messages.`);
|
|
287
|
+
}
|
|
288
|
+
for (const [index, message] of messages.entries()) {
|
|
289
|
+
if (!isPlainObject(message)) throw invalidParams(`${context} messages[${index}] must be an object.`);
|
|
290
|
+
rejectAdditionalProperties(message, new Set(['role', 'content']), `${context} messages[${index}]`);
|
|
291
|
+
requireString(message, 'role', `${context} messages[${index}]`);
|
|
292
|
+
requireString(message, 'content', `${context} messages[${index}]`);
|
|
293
|
+
if (!['system', 'user', 'assistant', 'tool'].includes(message.role)) {
|
|
294
|
+
throw invalidParams(`${context} messages[${index}].role is invalid.`);
|
|
295
|
+
}
|
|
296
|
+
if (message.content.length > 100_000) throw invalidParams(`${context} messages[${index}].content exceeds 100000 characters.`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
124
300
|
function validateToolArguments(name, args) {
|
|
125
301
|
if (!isPlainObject(args)) throw invalidParams('tools/call arguments must be an object.');
|
|
126
302
|
switch (name) {
|
|
303
|
+
case 'enigma_private_handoff_health':
|
|
304
|
+
case 'enigma_routing_contract':
|
|
305
|
+
rejectAdditionalProperties(args, new Set(), name);
|
|
306
|
+
return args;
|
|
307
|
+
case 'enigma_complete':
|
|
308
|
+
rejectAdditionalProperties(args, new Set(['messages', 'model', 'privacy_mode', 'temperature', 'max_tokens', 'reasoning_effort', 'web_search', 'require_private_route']), name);
|
|
309
|
+
validateCompletionMessages(args.messages, name);
|
|
310
|
+
optionalString(args, 'model', name);
|
|
311
|
+
maximumStringLength(args, 'model', name, 160);
|
|
312
|
+
optionalString(args, 'privacy_mode', name);
|
|
313
|
+
if (args.privacy_mode !== undefined && !['off', 'smart', 'full'].includes(args.privacy_mode)) throw invalidParams(`${name} privacy_mode must be off, smart, or full.`);
|
|
314
|
+
optionalNonNegativeNumber(args, 'temperature', name);
|
|
315
|
+
if (args.temperature !== undefined && args.temperature > 2) throw invalidParams(`${name} temperature must not exceed 2.`);
|
|
316
|
+
optionalIntegerRange(args, 'max_tokens', name, 1, 131072);
|
|
317
|
+
optionalString(args, 'reasoning_effort', name);
|
|
318
|
+
if (args.reasoning_effort !== undefined && !['none', 'low', 'medium', 'high'].includes(args.reasoning_effort)) throw invalidParams(`${name} reasoning_effort is invalid.`);
|
|
319
|
+
optionalBoolean(args, 'web_search', name);
|
|
320
|
+
optionalBoolean(args, 'require_private_route', name);
|
|
321
|
+
return args;
|
|
322
|
+
case 'enigma_generate_image':
|
|
323
|
+
rejectAdditionalProperties(args, new Set(['prompt', 'model', 'negative_prompt', 'width', 'height', 'steps', 'cfg_scale', 'variants', 'format', 'seed']), name);
|
|
324
|
+
requireString(args, 'prompt', name);
|
|
325
|
+
requireString(args, 'model', name);
|
|
326
|
+
optionalString(args, 'negative_prompt', name);
|
|
327
|
+
maximumStringLength(args, 'prompt', name, 16000);
|
|
328
|
+
maximumStringLength(args, 'model', name, 160);
|
|
329
|
+
maximumStringLength(args, 'negative_prompt', name, 8000);
|
|
330
|
+
optionalIntegerRange(args, 'width', name, 256, 2048);
|
|
331
|
+
optionalIntegerRange(args, 'height', name, 256, 2048);
|
|
332
|
+
optionalIntegerRange(args, 'steps', name, 1, 100);
|
|
333
|
+
optionalNonNegativeNumber(args, 'cfg_scale', name);
|
|
334
|
+
if (args.cfg_scale !== undefined && (args.cfg_scale < 1 || args.cfg_scale > 30)) throw invalidParams(`${name} cfg_scale must be from 1 through 30.`);
|
|
335
|
+
optionalIntegerRange(args, 'variants', name, 1, 4);
|
|
336
|
+
optionalString(args, 'format', name);
|
|
337
|
+
if (args.format !== undefined && !['png', 'jpeg', 'webp'].includes(args.format)) throw invalidParams(`${name} format must be png, jpeg, or webp.`);
|
|
338
|
+
optionalIntegerRange(args, 'seed', name, 0, 2147483647);
|
|
339
|
+
return args;
|
|
340
|
+
case 'enigma_x402_execute':
|
|
341
|
+
rejectAdditionalProperties(args, new Set(['url', 'method', 'headers', 'body', 'max_response_bytes']), name);
|
|
342
|
+
requireString(args, 'url', name);
|
|
343
|
+
maximumStringLength(args, 'url', name, 4096);
|
|
344
|
+
optionalString(args, 'method', name);
|
|
345
|
+
if (args.method !== undefined && !['GET', 'POST'].includes(args.method)) throw invalidParams(`${name} method must be GET or POST.`);
|
|
346
|
+
optionalPlainObject(args, 'headers', name);
|
|
347
|
+
for (const [header, value] of Object.entries(args.headers || {})) {
|
|
348
|
+
if (!['accept', 'content-type', 'idempotency-key'].includes(header.toLowerCase()) || typeof value !== 'string' || value.length > 4096) {
|
|
349
|
+
throw invalidParams(`${name} contains a forbidden or invalid request header.`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (args.body !== undefined && typeof args.body !== 'string' && !isPlainObject(args.body)) throw invalidParams(`${name} body must be a string or object.`);
|
|
353
|
+
optionalIntegerRange(args, 'max_response_bytes', name, 1024, 1048576);
|
|
354
|
+
return args;
|
|
355
|
+
case 'enigma_start_private_session':
|
|
356
|
+
rejectAdditionalProperties(args, new Set(['intent', 'model']), name);
|
|
357
|
+
optionalString(args, 'intent', name);
|
|
358
|
+
optionalString(args, 'model', name);
|
|
359
|
+
rejectSensitiveHandoffIntent(args.intent);
|
|
360
|
+
try { validatePrivateHandoffModel(args.model); } catch (error) { throw invalidParams(error.message); }
|
|
361
|
+
return args;
|
|
127
362
|
case 'enigma_init':
|
|
128
|
-
rejectAdditionalProperties(args, new Set(['bundlePath', 'tenant_id', 'subject_id', 'actor_id', 'policy_id']), name);
|
|
363
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'tenant_id', 'subject_id', 'actor_id', 'policy_id', 'insecureDevMode']), name);
|
|
129
364
|
optionalString(args, 'bundlePath', name);
|
|
365
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
130
366
|
optionalString(args, 'tenant_id', name);
|
|
131
367
|
optionalString(args, 'subject_id', name);
|
|
132
368
|
optionalString(args, 'actor_id', name);
|
|
133
369
|
optionalString(args, 'policy_id', name);
|
|
134
370
|
return args;
|
|
135
371
|
case 'enigma_remember':
|
|
136
|
-
rejectAdditionalProperties(args, new Set(['bundlePath', 'text', 'purpose', 'tags', 'metadata']), name);
|
|
372
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'text', 'purpose', 'tags', 'metadata', 'insecureDevMode']), name);
|
|
137
373
|
optionalString(args, 'bundlePath', name);
|
|
374
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
138
375
|
requireString(args, 'text', name);
|
|
139
376
|
optionalString(args, 'purpose', name);
|
|
140
377
|
optionalStringArray(args, 'tags', name);
|
|
141
378
|
optionalPlainObject(args, 'metadata', name);
|
|
142
379
|
return args;
|
|
143
380
|
case 'enigma_search':
|
|
144
|
-
rejectAdditionalProperties(args, new Set(['bundlePath', 'query', 'memory_addr', 'purpose', 'limit']), name);
|
|
381
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'query', 'memory_addr', 'purpose', 'limit', 'insecureDevMode', 'allowOldEpochReads']), name);
|
|
145
382
|
optionalString(args, 'bundlePath', name);
|
|
383
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
384
|
+
optionalBoolean(args, 'allowOldEpochReads', name);
|
|
146
385
|
optionalString(args, 'query', name);
|
|
147
386
|
optionalString(args, 'memory_addr', name);
|
|
148
387
|
optionalString(args, 'purpose', name);
|
|
@@ -159,8 +398,12 @@ function validateToolArguments(name, args) {
|
|
|
159
398
|
'max_estimated_tokens',
|
|
160
399
|
'price_per_million_tokens',
|
|
161
400
|
'currency',
|
|
401
|
+
'insecureDevMode',
|
|
402
|
+
'allowOldEpochReads',
|
|
162
403
|
]), name);
|
|
163
404
|
optionalString(args, 'bundlePath', name);
|
|
405
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
406
|
+
optionalBoolean(args, 'allowOldEpochReads', name);
|
|
164
407
|
optionalString(args, 'query', name);
|
|
165
408
|
optionalString(args, 'purpose', name);
|
|
166
409
|
optionalLimit(args, 'limit', name);
|
|
@@ -171,16 +414,85 @@ function validateToolArguments(name, args) {
|
|
|
171
414
|
optionalString(args, 'currency', name);
|
|
172
415
|
return args;
|
|
173
416
|
case 'enigma_delete':
|
|
174
|
-
rejectAdditionalProperties(args, new Set(['bundlePath', 'memory_addr', 'reason']), name);
|
|
417
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'memory_addr', 'reason', 'insecureDevMode']), name);
|
|
175
418
|
optionalString(args, 'bundlePath', name);
|
|
419
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
176
420
|
requireString(args, 'memory_addr', name);
|
|
177
421
|
optionalString(args, 'reason', name);
|
|
178
422
|
return args;
|
|
423
|
+
case 'enigma_vault_rotate':
|
|
424
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'key_id', 'insecureDevMode']), name);
|
|
425
|
+
optionalString(args, 'bundlePath', name);
|
|
426
|
+
optionalString(args, 'key_id', name);
|
|
427
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
428
|
+
return args;
|
|
429
|
+
case 'enigma_vault_seal':
|
|
430
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'epoch', 'insecureDevMode']), name);
|
|
431
|
+
optionalString(args, 'bundlePath', name);
|
|
432
|
+
optionalIntegerRange(args, 'epoch', name, 1, Number.MAX_SAFE_INTEGER);
|
|
433
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
434
|
+
return args;
|
|
435
|
+
case 'enigma_vault_reset':
|
|
436
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'key_id', 'insecureDevMode']), name);
|
|
437
|
+
optionalString(args, 'bundlePath', name);
|
|
438
|
+
optionalString(args, 'key_id', name);
|
|
439
|
+
optionalBoolean(args, 'insecureDevMode', name);
|
|
440
|
+
return args;
|
|
179
441
|
case 'enigma_verify_receipts':
|
|
180
442
|
rejectAdditionalProperties(args, new Set(['bundlePath', 'bundle']), name);
|
|
181
443
|
optionalString(args, 'bundlePath', name);
|
|
182
444
|
optionalPlainObject(args, 'bundle', name);
|
|
183
445
|
return args;
|
|
446
|
+
case 'enigma_swarm_register_agent':
|
|
447
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'agent_id', 'swarm_id', 'namespace', 'permission_mask']), name);
|
|
448
|
+
optionalString(args, 'bundlePath', name);
|
|
449
|
+
requireString(args, 'agent_id', name);
|
|
450
|
+
optionalString(args, 'swarm_id', name);
|
|
451
|
+
optionalString(args, 'namespace', name);
|
|
452
|
+
optionalPermissionMask(args, 'permission_mask', name);
|
|
453
|
+
return args;
|
|
454
|
+
case 'enigma_graph_query':
|
|
455
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'agent_id', 'swarm_id', 'namespace', 'start', 'entity_id', 'query', 'max_depth', 'limit', 'direction']), name);
|
|
456
|
+
optionalString(args, 'bundlePath', name);
|
|
457
|
+
requireString(args, 'agent_id', name);
|
|
458
|
+
optionalString(args, 'swarm_id', name);
|
|
459
|
+
optionalString(args, 'namespace', name);
|
|
460
|
+
optionalString(args, 'start', name);
|
|
461
|
+
optionalString(args, 'entity_id', name);
|
|
462
|
+
optionalString(args, 'query', name);
|
|
463
|
+
optionalIntegerRange(args, 'max_depth', name, 0, 12);
|
|
464
|
+
optionalIntegerRange(args, 'limit', name, 1, 500);
|
|
465
|
+
optionalString(args, 'direction', name);
|
|
466
|
+
return args;
|
|
467
|
+
case 'enigma_cluster_memories':
|
|
468
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'agent_id', 'swarm_id', 'namespace', 'threshold', 'max_clusters']), name);
|
|
469
|
+
optionalString(args, 'bundlePath', name);
|
|
470
|
+
requireString(args, 'agent_id', name);
|
|
471
|
+
optionalString(args, 'swarm_id', name);
|
|
472
|
+
optionalString(args, 'namespace', name);
|
|
473
|
+
optionalNonNegativeNumber(args, 'threshold', name);
|
|
474
|
+
if (args.threshold !== undefined && args.threshold > 1) throw invalidParams(`${name} threshold must not exceed 1.`);
|
|
475
|
+
optionalIntegerRange(args, 'max_clusters', name, 1, 100);
|
|
476
|
+
return args;
|
|
477
|
+
case 'enigma_swarm_sync':
|
|
478
|
+
rejectAdditionalProperties(args, new Set(['bundlePath', 'agent_id', 'swarm_id', 'namespace', 'snapshot', 'apply', 'include_content', 'allow_content']), name);
|
|
479
|
+
optionalString(args, 'bundlePath', name);
|
|
480
|
+
requireString(args, 'agent_id', name);
|
|
481
|
+
optionalString(args, 'swarm_id', name);
|
|
482
|
+
optionalString(args, 'namespace', name);
|
|
483
|
+
optionalPlainObject(args, 'snapshot', name);
|
|
484
|
+
optionalBoolean(args, 'apply', name);
|
|
485
|
+
optionalBoolean(args, 'include_content', name);
|
|
486
|
+
optionalBoolean(args, 'allow_content', name);
|
|
487
|
+
return args;
|
|
488
|
+
case 'enigma_immune_ingress':
|
|
489
|
+
rejectAdditionalProperties(args, new Set(['candidate', 'candidates', 'generated_at', 'now']), name);
|
|
490
|
+
optionalPlainObject(args, 'candidate', name);
|
|
491
|
+
optionalObjectArray(args, 'candidates', name);
|
|
492
|
+
optionalString(args, 'generated_at', name);
|
|
493
|
+
optionalString(args, 'now', name);
|
|
494
|
+
if (args.candidate === undefined && args.candidates === undefined) throw invalidParams(`${name} requires candidate or candidates.`);
|
|
495
|
+
return args;
|
|
184
496
|
case 'enigma_meter_usage':
|
|
185
497
|
rejectAdditionalProperties(args, new Set([
|
|
186
498
|
'events',
|
|
@@ -291,6 +603,28 @@ function validateToolArguments(name, args) {
|
|
|
291
603
|
requireString(args, 'batch_ref', name);
|
|
292
604
|
optionalString(args, 'generated_at', name);
|
|
293
605
|
return args;
|
|
606
|
+
case 'enigma_vault_create_record':
|
|
607
|
+
rejectAdditionalProperties(args, new Set(['plaintext', 'metadata']), name);
|
|
608
|
+
requireString(args, 'plaintext', name);
|
|
609
|
+
optionalPlainObject(args, 'metadata', name);
|
|
610
|
+
return args;
|
|
611
|
+
case 'enigma_vault_zeroize_record':
|
|
612
|
+
rejectAdditionalProperties(args, new Set(['recordId']), name);
|
|
613
|
+
requireString(args, 'recordId', name);
|
|
614
|
+
return args;
|
|
615
|
+
case 'enigma_verify_erasure_attestation':
|
|
616
|
+
rejectAdditionalProperties(args, new Set(['attestation', 'allowSimulated', 'expectedPcr']), name);
|
|
617
|
+
optionalPlainObject(args, 'attestation', name);
|
|
618
|
+
optionalBoolean(args, 'allowSimulated', name);
|
|
619
|
+
optionalString(args, 'expectedPcr', name);
|
|
620
|
+
if (!args.attestation) throw invalidParams(`${name} requires attestation object.`);
|
|
621
|
+
return args;
|
|
622
|
+
case 'enigma_nullifier_record_tombstone':
|
|
623
|
+
rejectAdditionalProperties(args, new Set(['commitment', 'nullifierHash', 'ownerPubkey']), name);
|
|
624
|
+
requireString(args, 'commitment', name);
|
|
625
|
+
requireString(args, 'nullifierHash', name);
|
|
626
|
+
requireString(args, 'ownerPubkey', name);
|
|
627
|
+
return args;
|
|
294
628
|
default:
|
|
295
629
|
throw invalidParams('Unknown tool.');
|
|
296
630
|
}
|
|
@@ -305,6 +639,117 @@ function validatePromptArguments(args) {
|
|
|
305
639
|
return args;
|
|
306
640
|
}
|
|
307
641
|
|
|
642
|
+
function remoteToolDescriptors() {
|
|
643
|
+
assertRemoteToolPolicyCoverage(toolDescriptors);
|
|
644
|
+
return toolDescriptors.map((descriptor) => {
|
|
645
|
+
const policy = remoteToolPolicy(descriptor.name);
|
|
646
|
+
const forbidden = new Set(policy.clientForbiddenFields);
|
|
647
|
+
const schema = descriptor.inputSchema;
|
|
648
|
+
if (!schema?.properties || forbidden.size === 0) return descriptor;
|
|
649
|
+
const properties = Object.fromEntries(Object.entries(schema.properties).filter(([name]) => !forbidden.has(name)));
|
|
650
|
+
const required = Array.isArray(schema.required) ? schema.required.filter((name) => !forbidden.has(name)) : undefined;
|
|
651
|
+
return {
|
|
652
|
+
...descriptor,
|
|
653
|
+
inputSchema: {
|
|
654
|
+
...schema,
|
|
655
|
+
properties,
|
|
656
|
+
...(required === undefined ? {} : { required }),
|
|
657
|
+
},
|
|
658
|
+
};
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function assertNestedTenantBinding(value, tenantId, { required = false } = {}) {
|
|
663
|
+
let found = 0;
|
|
664
|
+
function visit(candidate) {
|
|
665
|
+
if (Array.isArray(candidate)) {
|
|
666
|
+
candidate.forEach(visit);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (!isPlainObject(candidate)) return;
|
|
670
|
+
for (const [key, child] of Object.entries(candidate)) {
|
|
671
|
+
if (key === 'tenant_id' || key === 'tenantId') {
|
|
672
|
+
found += 1;
|
|
673
|
+
if (child !== tenantId) throw invalidParams('Remote MCP settlement or metering input belongs to a different tenant.');
|
|
674
|
+
}
|
|
675
|
+
visit(child);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
visit(value);
|
|
679
|
+
if (required && found === 0) throw invalidParams('Remote MCP input does not contain the server-bound tenant.');
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
async function bindRemoteToolArguments(name, args, context) {
|
|
683
|
+
if (context.transport !== 'streamable-http') return args;
|
|
684
|
+
if (!isPlainObject(args)) throw invalidParams('tools/call arguments must be an object.');
|
|
685
|
+
const policy = remoteToolPolicy(name);
|
|
686
|
+
if (!policy) throw invalidParams('Remote MCP policy is missing for this tool.');
|
|
687
|
+
const forbidden = Object.keys(args).find((key) => policy.clientForbiddenFields.includes(key));
|
|
688
|
+
if (forbidden) throw invalidParams(`Remote MCP does not accept client-controlled ${forbidden}.`);
|
|
689
|
+
const requiresBinding = policy.vaultBinding !== 'none' || policy.tenantBinding !== 'none';
|
|
690
|
+
let binding = null;
|
|
691
|
+
if (requiresBinding) {
|
|
692
|
+
if (typeof context.resolveVaultContext !== 'function') throw new Error('remote tenant and vault resolver is not configured');
|
|
693
|
+
binding = await context.resolveVaultContext(context.principal);
|
|
694
|
+
if (!isPlainObject(binding) || typeof binding.tenant_id !== 'string' || !binding.tenant_id) {
|
|
695
|
+
throw new Error('remote tenant and vault resolver returned an invalid binding');
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
let bound = { ...args };
|
|
699
|
+
if (policy.vaultBinding !== 'none') {
|
|
700
|
+
if (typeof binding.bundlePath !== 'string' || !binding.bundlePath) throw new Error('remote vault resolver returned no bundle path');
|
|
701
|
+
bound.bundlePath = binding.bundlePath;
|
|
702
|
+
if (name === 'enigma_init') {
|
|
703
|
+
bound = {
|
|
704
|
+
...bound,
|
|
705
|
+
tenant_id: binding.tenant_id,
|
|
706
|
+
subject_id: String(binding.subject_id || ''),
|
|
707
|
+
actor_id: String(binding.actor_id || ''),
|
|
708
|
+
policy_id: String(binding.policy_id || ''),
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
if (name === 'enigma_search' || name === 'enigma_context_pack') bound.allowOldEpochReads = false;
|
|
712
|
+
Object.defineProperty(bound, REMOTE_SECURE_VAULT, { value: true, enumerable: true });
|
|
713
|
+
}
|
|
714
|
+
if (policy.tenantBinding === 'inject') {
|
|
715
|
+
if (name === 'enigma_meter_usage' && Array.isArray(bound.events)) {
|
|
716
|
+
assertNestedTenantBinding(bound.events, binding.tenant_id, { required: true });
|
|
717
|
+
}
|
|
718
|
+
bound.tenant_id = binding.tenant_id;
|
|
719
|
+
} else if (policy.tenantBinding === 'validate_nested') {
|
|
720
|
+
assertNestedTenantBinding(bound, binding.tenant_id, { required: true });
|
|
721
|
+
}
|
|
722
|
+
return validateToolArguments(name, bound);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
async function bindRemoteResourceInput(params, normalizedUri, context) {
|
|
726
|
+
if (context.transport !== 'streamable-http' || normalizedUri !== PASSPORT_SUMMARY_RESOURCE_URI) return inputWithBundlePath(params);
|
|
727
|
+
const forbiddenFields = new Set(['bundlePath', 'bundle_path', 'insecureDevMode', 'insecure_dev_mode']);
|
|
728
|
+
const parsed = new URL(String(params.uri));
|
|
729
|
+
const forbiddenQuery = [...parsed.searchParams.keys()].find((key) => forbiddenFields.has(key));
|
|
730
|
+
const forbiddenProperty = Object.keys(params).find((key) => forbiddenFields.has(key));
|
|
731
|
+
if (forbiddenQuery || forbiddenProperty) throw invalidParams(`Remote MCP does not accept client-controlled ${forbiddenQuery || forbiddenProperty}.`);
|
|
732
|
+
if (typeof context.resolveVaultContext !== 'function') throw new Error('remote vault resolver is not configured');
|
|
733
|
+
const binding = await context.resolveVaultContext(context.principal);
|
|
734
|
+
if (!isPlainObject(binding) || typeof binding.bundlePath !== 'string' || !binding.bundlePath) {
|
|
735
|
+
throw new Error('remote vault resolver returned an invalid binding');
|
|
736
|
+
}
|
|
737
|
+
const bound = { uri: params.uri, bundlePath: binding.bundlePath };
|
|
738
|
+
Object.defineProperty(bound, REMOTE_SECURE_VAULT, { value: true, enumerable: true });
|
|
739
|
+
return bound;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function sanitizeRemoteCustodyOutput(value, context) {
|
|
743
|
+
if (context.transport !== 'streamable-http' || !value || typeof value !== 'object' || Buffer.isBuffer(value) || value instanceof Uint8Array) return value;
|
|
744
|
+
if (Array.isArray(value)) return value.map((item) => sanitizeRemoteCustodyOutput(item, context));
|
|
745
|
+
const sanitized = {};
|
|
746
|
+
for (const [key, item] of Object.entries(value)) {
|
|
747
|
+
if (key === 'bundlePath' || key === 'bundle_path') continue;
|
|
748
|
+
sanitized[key] = sanitizeRemoteCustodyOutput(item, context);
|
|
749
|
+
}
|
|
750
|
+
return sanitized;
|
|
751
|
+
}
|
|
752
|
+
|
|
308
753
|
function sanitizeOperationalError(error) {
|
|
309
754
|
return {
|
|
310
755
|
ok: false,
|
|
@@ -313,8 +758,148 @@ function sanitizeOperationalError(error) {
|
|
|
313
758
|
};
|
|
314
759
|
}
|
|
315
760
|
|
|
761
|
+
function mcpImmuneIngressCandidates(input) {
|
|
762
|
+
if (!isPlainObject(input)) return input;
|
|
763
|
+
if (Object.prototype.hasOwnProperty.call(input, 'candidates')) return input.candidates;
|
|
764
|
+
if (Object.prototype.hasOwnProperty.call(input, 'candidate')) return input.candidate;
|
|
765
|
+
if (Object.prototype.hasOwnProperty.call(input, 'memory_candidates')) return input.memory_candidates;
|
|
766
|
+
if (Object.prototype.hasOwnProperty.call(input, 'memoryCandidates')) return input.memoryCandidates;
|
|
767
|
+
return input;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function mcpImmuneIngressOptions(input, options = {}) {
|
|
771
|
+
return {
|
|
772
|
+
...options,
|
|
773
|
+
now: options.now ?? input?.now ?? input?.generated_at ?? input?.generatedAt,
|
|
774
|
+
source_type: options.source_type ?? options.sourceType ?? 'mcp_candidate_ingress',
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
export function createMcpImmuneIngressReport(input = {}, options = {}) {
|
|
779
|
+
return createImmuneIngressReport(mcpImmuneIngressCandidates(input), mcpImmuneIngressOptions(input, options));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export function assertMcpImmuneIngressPublicSafe(input = {}, options = {}) {
|
|
783
|
+
return assertImmuneIngressPublicSafe(mcpImmuneIngressCandidates(input), mcpImmuneIngressOptions(input, options));
|
|
784
|
+
}
|
|
785
|
+
|
|
316
786
|
|
|
317
787
|
export const toolDescriptors = [
|
|
788
|
+
{
|
|
789
|
+
name: 'enigma_private_handoff_health',
|
|
790
|
+
description: 'Check whether the local Enigma private workspace is reachable. This diagnostic never accepts or returns a user prompt.',
|
|
791
|
+
inputSchema: {
|
|
792
|
+
type: 'object',
|
|
793
|
+
properties: {},
|
|
794
|
+
additionalProperties: false,
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
name: 'enigma_routing_contract',
|
|
799
|
+
description: 'Explain when an MCP host must use an Enigma private-session handoff instead of relaying prompt text through host-visible tool arguments.',
|
|
800
|
+
inputSchema: {
|
|
801
|
+
type: 'object',
|
|
802
|
+
properties: {},
|
|
803
|
+
additionalProperties: false,
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
name: 'enigma_start_private_session',
|
|
808
|
+
description: 'Open the Enigma private workspace for sensitive prompts. Pass only a non-sensitive intent label; the actual prompt must be typed inside Enigma and never placed in this tool call.',
|
|
809
|
+
inputSchema: {
|
|
810
|
+
type: 'object',
|
|
811
|
+
properties: {
|
|
812
|
+
intent: {
|
|
813
|
+
type: 'string',
|
|
814
|
+
maxLength: 160,
|
|
815
|
+
description: 'Optional non-sensitive handoff label such as "private legal question". Never include the actual private prompt.',
|
|
816
|
+
},
|
|
817
|
+
model: {
|
|
818
|
+
type: 'string',
|
|
819
|
+
maxLength: 160,
|
|
820
|
+
description: 'Optional configured Enigma model route to preselect.',
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
additionalProperties: false,
|
|
824
|
+
},
|
|
825
|
+
_meta: {
|
|
826
|
+
'openai/outputTemplate': PRIVATE_SESSION_RESOURCE_URI,
|
|
827
|
+
'ui/resourceUri': PRIVATE_SESSION_RESOURCE_URI,
|
|
828
|
+
},
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
name: 'enigma_complete',
|
|
832
|
+
description: 'Run a direct Enigma completion with Smart Privacy and explicit route disclosure. MCP tool arguments are visible to the MCP host; use enigma_start_private_session when the prompt must remain outside host chat.',
|
|
833
|
+
inputSchema: {
|
|
834
|
+
type: 'object',
|
|
835
|
+
properties: {
|
|
836
|
+
messages: {
|
|
837
|
+
type: 'array',
|
|
838
|
+
minItems: 1,
|
|
839
|
+
maxItems: 128,
|
|
840
|
+
items: {
|
|
841
|
+
type: 'object',
|
|
842
|
+
properties: {
|
|
843
|
+
role: { type: 'string', enum: ['system', 'user', 'assistant', 'tool'] },
|
|
844
|
+
content: { type: 'string', maxLength: 100000 },
|
|
845
|
+
},
|
|
846
|
+
required: ['role', 'content'],
|
|
847
|
+
additionalProperties: false,
|
|
848
|
+
},
|
|
849
|
+
},
|
|
850
|
+
model: { type: 'string', default: 'enigma-auto' },
|
|
851
|
+
privacy_mode: { type: 'string', enum: ['off', 'smart', 'full'], default: 'smart' },
|
|
852
|
+
temperature: { type: 'number', minimum: 0, maximum: 2 },
|
|
853
|
+
max_tokens: { type: 'integer', minimum: 1, maximum: 131072 },
|
|
854
|
+
reasoning_effort: { type: 'string', enum: ['none', 'low', 'medium', 'high'] },
|
|
855
|
+
web_search: { type: 'boolean', default: false },
|
|
856
|
+
require_private_route: { type: 'boolean', default: false },
|
|
857
|
+
},
|
|
858
|
+
required: ['messages'],
|
|
859
|
+
additionalProperties: false,
|
|
860
|
+
},
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
name: 'enigma_generate_image',
|
|
864
|
+
description: 'Generate image assets through a configured Enigma image route. The prompt is sent only to that configured route and is not retained in the MCP receipt.',
|
|
865
|
+
inputSchema: {
|
|
866
|
+
type: 'object',
|
|
867
|
+
properties: {
|
|
868
|
+
prompt: { type: 'string', maxLength: 16000 },
|
|
869
|
+
model: { type: 'string', maxLength: 160 },
|
|
870
|
+
negative_prompt: { type: 'string', maxLength: 8000 },
|
|
871
|
+
width: { type: 'integer', minimum: 256, maximum: 2048, default: 1024 },
|
|
872
|
+
height: { type: 'integer', minimum: 256, maximum: 2048, default: 1024 },
|
|
873
|
+
steps: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
|
874
|
+
cfg_scale: { type: 'number', minimum: 1, maximum: 30, default: 7.5 },
|
|
875
|
+
variants: { type: 'integer', minimum: 1, maximum: 4, default: 1 },
|
|
876
|
+
format: { type: 'string', enum: ['png', 'jpeg', 'webp'], default: 'webp' },
|
|
877
|
+
seed: { type: 'integer', minimum: 0, maximum: 2147483647 },
|
|
878
|
+
},
|
|
879
|
+
required: ['prompt', 'model'],
|
|
880
|
+
additionalProperties: false,
|
|
881
|
+
},
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
name: 'enigma_x402_execute',
|
|
885
|
+
description: 'Execute an x402 v2 paid HTTP request using the configured real wallet signer, strict recipient/network/asset allowlists, and an atomic-unit budget. This moves funds; inspect the server offer before calling.',
|
|
886
|
+
inputSchema: {
|
|
887
|
+
type: 'object',
|
|
888
|
+
properties: {
|
|
889
|
+
url: { type: 'string', maxLength: 4096 },
|
|
890
|
+
method: { type: 'string', enum: ['GET', 'POST'], default: 'GET' },
|
|
891
|
+
headers: {
|
|
892
|
+
type: 'object',
|
|
893
|
+
description: 'Only Accept, Content-Type, and Idempotency-Key are allowed.',
|
|
894
|
+
additionalProperties: { type: 'string', maxLength: 4096 },
|
|
895
|
+
},
|
|
896
|
+
body: { anyOf: [{ type: 'string' }, { type: 'object' }] },
|
|
897
|
+
max_response_bytes: { type: 'integer', minimum: 1024, maximum: 1048576, default: 262144 },
|
|
898
|
+
},
|
|
899
|
+
required: ['url'],
|
|
900
|
+
additionalProperties: false,
|
|
901
|
+
},
|
|
902
|
+
},
|
|
318
903
|
{
|
|
319
904
|
name: 'enigma_init',
|
|
320
905
|
description: 'Create a local Enigma vault bundle when one does not already exist.',
|
|
@@ -326,6 +911,7 @@ export const toolDescriptors = [
|
|
|
326
911
|
subject_id: { type: 'string' },
|
|
327
912
|
actor_id: { type: 'string' },
|
|
328
913
|
policy_id: { type: 'string' },
|
|
914
|
+
insecureDevMode: { type: 'boolean', description: 'Explicitly allow a plaintext disposable development bundle when no server passphrase is configured.' },
|
|
329
915
|
},
|
|
330
916
|
additionalProperties: false,
|
|
331
917
|
},
|
|
@@ -341,6 +927,7 @@ export const toolDescriptors = [
|
|
|
341
927
|
purpose: { type: 'string' },
|
|
342
928
|
tags: { type: 'array', items: { type: 'string' } },
|
|
343
929
|
metadata: { type: 'object' },
|
|
930
|
+
insecureDevMode: { type: 'boolean' },
|
|
344
931
|
},
|
|
345
932
|
required: ['text'],
|
|
346
933
|
additionalProperties: false,
|
|
@@ -357,6 +944,8 @@ export const toolDescriptors = [
|
|
|
357
944
|
memory_addr: { type: 'string' },
|
|
358
945
|
purpose: { type: 'string' },
|
|
359
946
|
limit: { type: 'integer', minimum: 1, maximum: 50 },
|
|
947
|
+
insecureDevMode: { type: 'boolean' },
|
|
948
|
+
allowOldEpochReads: { type: 'boolean' },
|
|
360
949
|
},
|
|
361
950
|
additionalProperties: false,
|
|
362
951
|
},
|
|
@@ -376,6 +965,8 @@ export const toolDescriptors = [
|
|
|
376
965
|
max_estimated_tokens: { type: 'number', minimum: 0 },
|
|
377
966
|
price_per_million_tokens: { type: 'number', minimum: 0 },
|
|
378
967
|
currency: { type: 'string' },
|
|
968
|
+
insecureDevMode: { type: 'boolean' },
|
|
969
|
+
allowOldEpochReads: { type: 'boolean' },
|
|
379
970
|
},
|
|
380
971
|
additionalProperties: false,
|
|
381
972
|
},
|
|
@@ -389,11 +980,51 @@ export const toolDescriptors = [
|
|
|
389
980
|
bundlePath: { type: 'string' },
|
|
390
981
|
memory_addr: { type: 'string' },
|
|
391
982
|
reason: { type: 'string' },
|
|
983
|
+
insecureDevMode: { type: 'boolean' },
|
|
392
984
|
},
|
|
393
985
|
required: ['memory_addr'],
|
|
394
986
|
additionalProperties: false,
|
|
395
987
|
},
|
|
396
988
|
},
|
|
989
|
+
{
|
|
990
|
+
name: 'enigma_vault_rotate',
|
|
991
|
+
description: 'Rotate to a new content-key epoch while honestly retaining prior keys for authorized historical reads.',
|
|
992
|
+
inputSchema: {
|
|
993
|
+
type: 'object',
|
|
994
|
+
properties: {
|
|
995
|
+
bundlePath: { type: 'string' },
|
|
996
|
+
key_id: { type: 'string' },
|
|
997
|
+
insecureDevMode: { type: 'boolean' },
|
|
998
|
+
},
|
|
999
|
+
additionalProperties: false,
|
|
1000
|
+
},
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
name: 'enigma_vault_seal',
|
|
1004
|
+
description: 'Seal a content-key epoch against future writes while retaining its key for policy-authorized reads.',
|
|
1005
|
+
inputSchema: {
|
|
1006
|
+
type: 'object',
|
|
1007
|
+
properties: {
|
|
1008
|
+
bundlePath: { type: 'string' },
|
|
1009
|
+
epoch: { type: 'integer', minimum: 1 },
|
|
1010
|
+
insecureDevMode: { type: 'boolean' },
|
|
1011
|
+
},
|
|
1012
|
+
additionalProperties: false,
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
name: 'enigma_vault_reset',
|
|
1017
|
+
description: 'Perform a software content-key reset, remove local records, and emit signed evidence without claiming physical-media, backup, or external-copy erasure.',
|
|
1018
|
+
inputSchema: {
|
|
1019
|
+
type: 'object',
|
|
1020
|
+
properties: {
|
|
1021
|
+
bundlePath: { type: 'string' },
|
|
1022
|
+
key_id: { type: 'string' },
|
|
1023
|
+
insecureDevMode: { type: 'boolean' },
|
|
1024
|
+
},
|
|
1025
|
+
additionalProperties: false,
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
397
1028
|
{
|
|
398
1029
|
name: 'enigma_verify_receipts',
|
|
399
1030
|
description: 'Verify receipts/checkpoints in a local or exported Enigma bundle and return a machine-readable verdict.',
|
|
@@ -406,6 +1037,99 @@ export const toolDescriptors = [
|
|
|
406
1037
|
additionalProperties: false,
|
|
407
1038
|
},
|
|
408
1039
|
},
|
|
1040
|
+
{
|
|
1041
|
+
name: 'enigma_swarm_register_agent',
|
|
1042
|
+
description: 'Register an agent in a local swarm domain with a namespace fence and explicit permission mask.',
|
|
1043
|
+
inputSchema: {
|
|
1044
|
+
type: 'object',
|
|
1045
|
+
properties: {
|
|
1046
|
+
bundlePath: { type: 'string' },
|
|
1047
|
+
agent_id: { type: 'string' },
|
|
1048
|
+
swarm_id: { type: 'string' },
|
|
1049
|
+
namespace: { type: 'string' },
|
|
1050
|
+
permission_mask: {
|
|
1051
|
+
oneOf: [
|
|
1052
|
+
{ type: 'integer', minimum: 0, maximum: 63 },
|
|
1053
|
+
{ type: 'string' },
|
|
1054
|
+
{ type: 'array', items: { type: 'string' } },
|
|
1055
|
+
],
|
|
1056
|
+
},
|
|
1057
|
+
},
|
|
1058
|
+
required: ['agent_id'],
|
|
1059
|
+
additionalProperties: false,
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
name: 'enigma_graph_query',
|
|
1064
|
+
description: 'Traverse the namespace-fenced local memory entity graph, including cross-atom associative links.',
|
|
1065
|
+
inputSchema: {
|
|
1066
|
+
type: 'object',
|
|
1067
|
+
properties: {
|
|
1068
|
+
bundlePath: { type: 'string' },
|
|
1069
|
+
agent_id: { type: 'string' },
|
|
1070
|
+
swarm_id: { type: 'string' },
|
|
1071
|
+
namespace: { type: 'string' },
|
|
1072
|
+
start: { type: 'string' },
|
|
1073
|
+
entity_id: { type: 'string' },
|
|
1074
|
+
query: { type: 'string' },
|
|
1075
|
+
max_depth: { type: 'integer', minimum: 0, maximum: 12 },
|
|
1076
|
+
limit: { type: 'integer', minimum: 1, maximum: 500 },
|
|
1077
|
+
direction: { type: 'string' },
|
|
1078
|
+
},
|
|
1079
|
+
required: ['agent_id'],
|
|
1080
|
+
additionalProperties: false,
|
|
1081
|
+
},
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
name: 'enigma_cluster_memories',
|
|
1085
|
+
description: 'Group active namespace-fenced memories by semantic proximity and return committed centroid fingerprints.',
|
|
1086
|
+
inputSchema: {
|
|
1087
|
+
type: 'object',
|
|
1088
|
+
properties: {
|
|
1089
|
+
bundlePath: { type: 'string' },
|
|
1090
|
+
agent_id: { type: 'string' },
|
|
1091
|
+
swarm_id: { type: 'string' },
|
|
1092
|
+
namespace: { type: 'string' },
|
|
1093
|
+
threshold: { type: 'number', minimum: 0, maximum: 1 },
|
|
1094
|
+
max_clusters: { type: 'integer', minimum: 1, maximum: 100 },
|
|
1095
|
+
},
|
|
1096
|
+
required: ['agent_id'],
|
|
1097
|
+
additionalProperties: false,
|
|
1098
|
+
},
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
name: 'enigma_swarm_sync',
|
|
1102
|
+
description: 'Create or validate an opt-in local gossip simulation using Merkle diffs; no network transmission occurs and raw content is excluded by default.',
|
|
1103
|
+
inputSchema: {
|
|
1104
|
+
type: 'object',
|
|
1105
|
+
properties: {
|
|
1106
|
+
bundlePath: { type: 'string' },
|
|
1107
|
+
agent_id: { type: 'string' },
|
|
1108
|
+
swarm_id: { type: 'string' },
|
|
1109
|
+
namespace: { type: 'string' },
|
|
1110
|
+
snapshot: { type: 'object' },
|
|
1111
|
+
apply: { type: 'boolean' },
|
|
1112
|
+
include_content: { type: 'boolean' },
|
|
1113
|
+
allow_content: { type: 'boolean' },
|
|
1114
|
+
},
|
|
1115
|
+
required: ['agent_id'],
|
|
1116
|
+
additionalProperties: false,
|
|
1117
|
+
},
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
name: 'enigma_immune_ingress',
|
|
1121
|
+
description: 'Scan MCP-supplied memory candidate objects and return a public-safe immune quarantine report with opaque refs only.',
|
|
1122
|
+
inputSchema: {
|
|
1123
|
+
type: 'object',
|
|
1124
|
+
properties: {
|
|
1125
|
+
candidate: { type: 'object' },
|
|
1126
|
+
candidates: { type: 'array', items: { type: 'object' } },
|
|
1127
|
+
generated_at: { type: 'string' },
|
|
1128
|
+
now: { type: 'string' },
|
|
1129
|
+
},
|
|
1130
|
+
additionalProperties: false,
|
|
1131
|
+
},
|
|
1132
|
+
},
|
|
409
1133
|
{
|
|
410
1134
|
name: 'enigma_meter_usage',
|
|
411
1135
|
description: 'Create content-minimized memory usage events or aggregate supplied usage events without raw prompts or provider responses.',
|
|
@@ -546,9 +1270,30 @@ export const toolDescriptors = [
|
|
|
546
1270
|
additionalProperties: false,
|
|
547
1271
|
},
|
|
548
1272
|
},
|
|
1273
|
+
// NOTE: enigma_verify_erasure_attestation is intentionally NOT exposed as an MCP
|
|
1274
|
+
// tool. The hardware path pins only the chain root and trusts the leaf public key
|
|
1275
|
+
// without verifying leaf/intermediate signatures, and the TPM path allowlists a
|
|
1276
|
+
// forgeable issuer string — an attacker could obtain valid:true with their own
|
|
1277
|
+
// key. The exported function remains for internal/direct use until real chain +
|
|
1278
|
+
// quote validation lands.
|
|
1279
|
+
{
|
|
1280
|
+
name: 'enigma_nullifier_record_tombstone',
|
|
1281
|
+
description: 'Build an owner-signed Solana record_revocation instruction for a registered Enigma commitment. Returns complete ordered account metas and instruction data; the owner must sign. Records protocol-level revocation/non-use only — not physical deletion of plaintext, backups, or external copies.',
|
|
1282
|
+
inputSchema: {
|
|
1283
|
+
type: 'object',
|
|
1284
|
+
properties: {
|
|
1285
|
+
commitment: { type: 'string', pattern: '^(0x)?[0-9a-fA-F]{64}$' },
|
|
1286
|
+
nullifierHash: { type: 'string', pattern: '^(0x)?[0-9a-fA-F]{64}$' },
|
|
1287
|
+
ownerPubkey: { type: 'string', description: 'Base58 Solana public key of the commitment owner (required signer)' },
|
|
1288
|
+
},
|
|
1289
|
+
required: ['commitment', 'nullifierHash', 'ownerPubkey'],
|
|
1290
|
+
additionalProperties: false,
|
|
1291
|
+
},
|
|
1292
|
+
},
|
|
549
1293
|
];
|
|
550
1294
|
|
|
551
1295
|
const PASSPORT_SUMMARY_RESOURCE_URI = 'enigma://passport/summary';
|
|
1296
|
+
const PRIVATE_SESSION_HANDOFF_RESOURCE_URI = PRIVATE_SESSION_RESOURCE_URI;
|
|
552
1297
|
const STANDARD_MEMORY_PROMPT_NAME = 'enigma_standard_memory_prompt';
|
|
553
1298
|
|
|
554
1299
|
export const resourceDescriptors = [
|
|
@@ -558,6 +1303,12 @@ export const resourceDescriptors = [
|
|
|
558
1303
|
description: 'MCP-safe Passport and Vault metadata for the local Enigma bundle. Raw memory plaintext is never exposed.',
|
|
559
1304
|
mimeType: 'application/json',
|
|
560
1305
|
},
|
|
1306
|
+
{
|
|
1307
|
+
uri: PRIVATE_SESSION_HANDOFF_RESOURCE_URI,
|
|
1308
|
+
name: 'Enigma Private Session Handoff',
|
|
1309
|
+
description: 'Enigma-branded MCP App handoff. The host sees only non-sensitive handoff metadata; the actual prompt is typed in the local Enigma workspace.',
|
|
1310
|
+
mimeType: 'text/html;profile=mcp-app',
|
|
1311
|
+
},
|
|
561
1312
|
];
|
|
562
1313
|
|
|
563
1314
|
export const promptDescriptors = [
|
|
@@ -580,16 +1331,41 @@ export const promptDescriptors = [
|
|
|
580
1331
|
];
|
|
581
1332
|
|
|
582
1333
|
function bundlePath(input = {}) {
|
|
583
|
-
|
|
1334
|
+
const raw = input.bundlePath ?? input.bundle_path ?? input.bundle ?? process.env.ENIGMA_BUNDLE ?? DEFAULT_BUNDLE;
|
|
1335
|
+
return resolve(String(raw));
|
|
584
1336
|
}
|
|
585
1337
|
|
|
586
|
-
|
|
587
|
-
|
|
1338
|
+
function bundlePassphrase(input = {}) {
|
|
1339
|
+
const value = input.passphrase ?? input.passPhrase ?? process.env.ENIGMA_PASSPHRASE ?? undefined;
|
|
1340
|
+
if (value !== undefined && String(value).trim().length === 0) throw new Error('ENIGMA_PASSPHRASE is empty');
|
|
1341
|
+
return value === undefined ? undefined : String(value);
|
|
588
1342
|
}
|
|
589
1343
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
1344
|
+
function bundleInsecureDevMode(input = {}) {
|
|
1345
|
+
if (input[REMOTE_SECURE_VAULT] === true) return false;
|
|
1346
|
+
return input.insecureDevMode === true
|
|
1347
|
+
|| input.insecure_dev_mode === true
|
|
1348
|
+
|| ['1', 'true'].includes(String(process.env.ENIGMA_INSECURE_DEV_MODE ?? '').toLowerCase());
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
function bundleCredentials(input = {}) {
|
|
1352
|
+
const passphrase = bundlePassphrase(input);
|
|
1353
|
+
const insecureDevMode = bundleInsecureDevMode(input);
|
|
1354
|
+
if (passphrase === undefined && !insecureDevMode) {
|
|
1355
|
+
throw new Error('Persistent MCP vault access requires ENIGMA_PASSPHRASE unless ENIGMA_INSECURE_DEV_MODE=1 is explicitly enabled.');
|
|
1356
|
+
}
|
|
1357
|
+
return {
|
|
1358
|
+
passphrase,
|
|
1359
|
+
insecureDevMode,
|
|
1360
|
+
allowOldEpochReads: input.allowOldEpochReads ?? input.allow_old_epoch_reads,
|
|
1361
|
+
checkpointProvider: input.checkpointProvider ?? configuredCheckpointProvider,
|
|
1362
|
+
requireExternalCheckpoint: input.requireExternalCheckpoint === true
|
|
1363
|
+
|| process.env.ENIGMA_REQUIRE_EXTERNAL_CHECKPOINT === '1',
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
async function readJson(path) {
|
|
1368
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
593
1369
|
}
|
|
594
1370
|
|
|
595
1371
|
async function fileExists(path) {
|
|
@@ -602,50 +1378,89 @@ async function fileExists(path) {
|
|
|
602
1378
|
}
|
|
603
1379
|
}
|
|
604
1380
|
|
|
605
|
-
function
|
|
606
|
-
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
1381
|
+
async function loadState(path, input = {}) {
|
|
1382
|
+
const credentials = bundleCredentials(input);
|
|
1383
|
+
const loaded = await readJsonFileWithRevision(path, credentials);
|
|
1384
|
+
const cacheKey = resolve(String(path));
|
|
1385
|
+
const authTag = credentialCacheTag(credentials);
|
|
1386
|
+
const cached = unlockedVaultCache.get(cacheKey);
|
|
1387
|
+
const policyMatches = credentials.allowOldEpochReads === undefined
|
|
1388
|
+
|| cached?.vault?.allowOldEpochReads === credentials.allowOldEpochReads;
|
|
1389
|
+
if (cached?.revision === loaded.revision && cached.authTag === authTag && policyMatches) {
|
|
1390
|
+
unlockedVaultCache.delete(cacheKey);
|
|
1391
|
+
unlockedVaultCache.set(cacheKey, cached);
|
|
1392
|
+
return { ...cached, stored: loaded.value, revision: loaded.revision };
|
|
1393
|
+
}
|
|
1394
|
+
if (cached) invalidateCachedVault(cacheKey);
|
|
1395
|
+
const imported = importBundle({
|
|
1396
|
+
bundle: loaded.value,
|
|
1397
|
+
...credentials,
|
|
1398
|
+
strict: true,
|
|
1399
|
+
recordImport: false,
|
|
620
1400
|
});
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
vault.receipt_log_root = roots.receipt_log_root;
|
|
633
|
-
return vault;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
async function loadState(path) {
|
|
637
|
-
const stored = await readJson(path);
|
|
638
|
-
const vault = reviveVault(stored);
|
|
639
|
-
return { stored, vault, passport: createPassport({ vault }) };
|
|
1401
|
+
const vault = imported.vault;
|
|
1402
|
+
const state = {
|
|
1403
|
+
stored: loaded.value,
|
|
1404
|
+
revision: loaded.revision,
|
|
1405
|
+
vault,
|
|
1406
|
+
passport: createPassport({ vault }),
|
|
1407
|
+
verified: imported.verified,
|
|
1408
|
+
authTag,
|
|
1409
|
+
};
|
|
1410
|
+
cacheUnlockedVault(cacheKey, state);
|
|
1411
|
+
return state;
|
|
640
1412
|
}
|
|
641
1413
|
|
|
642
|
-
async function persistState(path, vault) {
|
|
643
|
-
|
|
1414
|
+
async function persistState(path, vault, input = {}) {
|
|
1415
|
+
if (input.lockHeld !== true) {
|
|
1416
|
+
return withBundleFileLock(path, async () => {
|
|
1417
|
+
const expectedRevision = Object.prototype.hasOwnProperty.call(input, 'expectedRevision')
|
|
1418
|
+
? input.expectedRevision
|
|
1419
|
+
: (await fileExists(path) ? (await readJsonFileWithRevision(path, bundleCredentials(input))).revision : null);
|
|
1420
|
+
return persistState(path, vault, { ...input, lockHeld: true, expectedRevision });
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
const credentials = bundleCredentials(input);
|
|
1424
|
+
const exported = exportBundle({ vault, passphrase: credentials.passphrase, includePlaintext: false });
|
|
644
1425
|
const bundle = exported.bundle ?? exported;
|
|
645
|
-
await
|
|
1426
|
+
const persisted = await writeJsonFileAtomic(path, bundle, {
|
|
1427
|
+
...(Object.prototype.hasOwnProperty.call(input, 'expectedRevision')
|
|
1428
|
+
? { expectedRevision: input.expectedRevision }
|
|
1429
|
+
: {}),
|
|
1430
|
+
checkpointProvider: credentials.checkpointProvider,
|
|
1431
|
+
requireExternalCheckpoint: credentials.requireExternalCheckpoint,
|
|
1432
|
+
});
|
|
1433
|
+
const state = {
|
|
1434
|
+
stored: bundle,
|
|
1435
|
+
revision: persisted.revision,
|
|
1436
|
+
vault,
|
|
1437
|
+
passport: createPassport({ vault }),
|
|
1438
|
+
verified: true,
|
|
1439
|
+
authTag: credentialCacheTag(credentials),
|
|
1440
|
+
};
|
|
1441
|
+
cacheUnlockedVault(path, state);
|
|
1442
|
+
Object.defineProperty(bundle, '__revision', { value: persisted.revision, enumerable: false });
|
|
646
1443
|
return bundle;
|
|
647
1444
|
}
|
|
648
1445
|
|
|
1446
|
+
async function withVaultTransaction(path, input, operation) {
|
|
1447
|
+
return withBundleFileLock(path, async () => {
|
|
1448
|
+
const state = await loadState(path, input);
|
|
1449
|
+
try {
|
|
1450
|
+
const result = await operation(state);
|
|
1451
|
+
const bundle = await persistState(path, state.vault, {
|
|
1452
|
+
...input,
|
|
1453
|
+
lockHeld: true,
|
|
1454
|
+
expectedRevision: state.revision,
|
|
1455
|
+
});
|
|
1456
|
+
return { ...state, revision: bundle.__revision, result, bundle };
|
|
1457
|
+
} catch (error) {
|
|
1458
|
+
invalidateCachedVault(path);
|
|
1459
|
+
throw error;
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
|
|
649
1464
|
function bundleSummary(path, bundle, created) {
|
|
650
1465
|
return {
|
|
651
1466
|
ok: true,
|
|
@@ -681,7 +1496,11 @@ function inputWithBundlePath(params = {}) {
|
|
|
681
1496
|
} catch {
|
|
682
1497
|
// Invalid or relative resource identifiers are rejected by the resource handler.
|
|
683
1498
|
}
|
|
684
|
-
return
|
|
1499
|
+
return {
|
|
1500
|
+
uri,
|
|
1501
|
+
...(requestedPath === undefined ? {} : { bundlePath: requestedPath }),
|
|
1502
|
+
...(params.insecureDevMode === true ? { insecureDevMode: true } : {}),
|
|
1503
|
+
};
|
|
685
1504
|
}
|
|
686
1505
|
|
|
687
1506
|
function passportFromBundle(bundle) {
|
|
@@ -750,7 +1569,7 @@ export async function enigma_passport_summary_resource(input = {}) {
|
|
|
750
1569
|
throw new Error(`Unknown Enigma resource: ${uri ?? '<missing>'}`);
|
|
751
1570
|
}
|
|
752
1571
|
const path = bundlePath(options);
|
|
753
|
-
const bundle = await
|
|
1572
|
+
const { stored: bundle } = await loadState(path, options);
|
|
754
1573
|
return {
|
|
755
1574
|
contents: [
|
|
756
1575
|
{
|
|
@@ -762,6 +1581,162 @@ export async function enigma_passport_summary_resource(input = {}) {
|
|
|
762
1581
|
};
|
|
763
1582
|
}
|
|
764
1583
|
|
|
1584
|
+
|
|
1585
|
+
function privateSessionWidgetHtml() {
|
|
1586
|
+
const url = privateSessionUrl();
|
|
1587
|
+
return `<!doctype html>
|
|
1588
|
+
<html lang="en">
|
|
1589
|
+
<head>
|
|
1590
|
+
<meta charset="utf-8">
|
|
1591
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1592
|
+
<title>Enigma private session</title>
|
|
1593
|
+
<style>
|
|
1594
|
+
:root{color-scheme:dark;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#0a0908;color:#f4f2ef}
|
|
1595
|
+
*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;background:radial-gradient(circle at 84% 0,rgba(255,122,26,.15),transparent 24rem),#0a0908}
|
|
1596
|
+
main{width:min(620px,100%);padding:30px;border:1px solid rgba(255,255,255,.14);border-radius:18px;background:rgba(20,17,14,.92);box-shadow:inset 0 1px rgba(255,255,255,.07),0 24px 64px rgba(0,0,0,.45)}
|
|
1597
|
+
.eyebrow{font:600 11px ui-monospace,monospace;letter-spacing:.18em;color:#ff8b3d}.mark{display:inline-block;width:8px;height:8px;margin-right:8px;border-radius:50%;background:#ff7a1a}
|
|
1598
|
+
h1{max-width:14ch;margin:14px 0 10px;font-size:clamp(30px,7vw,52px);line-height:.98;letter-spacing:-.05em}p{max-width:58ch;color:#b9b6b1;font-size:14px;line-height:1.6}
|
|
1599
|
+
a{display:inline-flex;margin-top:20px;padding:11px 15px;border-radius:9px;background:#ff7a1a;color:#1a0b02;font:700 11px ui-monospace,monospace;text-decoration:none;text-transform:uppercase}
|
|
1600
|
+
section{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;margin-top:26px;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.12)}
|
|
1601
|
+
section div{padding:14px;background:#100e0c}small{display:block;color:#7d7a76;font:10px/1.45 ui-monospace,monospace}strong{display:block;margin-bottom:4px;font-size:12px}
|
|
1602
|
+
@media(max-width:520px){section{grid-template-columns:1fr}}
|
|
1603
|
+
</style>
|
|
1604
|
+
</head>
|
|
1605
|
+
<body>
|
|
1606
|
+
<main>
|
|
1607
|
+
<span class="eyebrow"><span class="mark"></span>ENIGMA / PRIVATE HANDOFF</span>
|
|
1608
|
+
<h1>Type the private prompt inside Enigma.</h1>
|
|
1609
|
+
<p>The actual prompt stays out of the MCP host chat. When you send it, the selected provider adapter receives the prepared request; Anchor Guard may mask supported patterns but is not semantic secrecy.</p>
|
|
1610
|
+
<a href="${url}" target="_blank" rel="noreferrer">Open private workspace</a>
|
|
1611
|
+
<section>
|
|
1612
|
+
<div><strong>MCP host</strong><small>Handoff fact, route label, non-sensitive intent. No workspace prompt.</small></div>
|
|
1613
|
+
<div><strong>Enigma workspace</strong><small>In-memory transcript and local context orchestration.</small></div>
|
|
1614
|
+
<div><strong>Configured provider</strong><small>Receives adapter input, optionally pattern-redacted by Anchor Guard.</small></div>
|
|
1615
|
+
</section>
|
|
1616
|
+
</main>
|
|
1617
|
+
</body>
|
|
1618
|
+
</html>`;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
function enigma_private_session_resource(input = {}) {
|
|
1622
|
+
const uri = input.uri ?? PRIVATE_SESSION_HANDOFF_RESOURCE_URI;
|
|
1623
|
+
if (String(uri) !== PRIVATE_SESSION_HANDOFF_RESOURCE_URI) {
|
|
1624
|
+
throw new Error(`Unknown Enigma resource: ${uri ?? '<missing>'}`);
|
|
1625
|
+
}
|
|
1626
|
+
return {
|
|
1627
|
+
contents: [{
|
|
1628
|
+
uri: PRIVATE_SESSION_HANDOFF_RESOURCE_URI,
|
|
1629
|
+
mimeType: 'text/html;profile=mcp-app',
|
|
1630
|
+
text: privateSessionWidgetHtml(),
|
|
1631
|
+
}],
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
export async function enigma_private_handoff_health(input = {}) {
|
|
1636
|
+
validateToolArguments('enigma_private_handoff_health', input);
|
|
1637
|
+
const origin = enigmaDesktopOrigin();
|
|
1638
|
+
const startedAt = Date.now();
|
|
1639
|
+
const protocolUrl = createPrivateSessionProtocolUrl();
|
|
1640
|
+
try {
|
|
1641
|
+
const response = await fetch(`${origin}/api/health`, {
|
|
1642
|
+
method: 'GET',
|
|
1643
|
+
headers: { Accept: 'application/json' },
|
|
1644
|
+
redirect: 'error',
|
|
1645
|
+
signal: AbortSignal.timeout(1_500),
|
|
1646
|
+
});
|
|
1647
|
+
const body = await response.json();
|
|
1648
|
+
const reachable = response.ok
|
|
1649
|
+
&& body?.ok === true
|
|
1650
|
+
&& body?.schema === 'enigma.desktop.health.v1'
|
|
1651
|
+
&& body?.service === 'enigma-desktop'
|
|
1652
|
+
&& typeof body?.instanceId === 'string';
|
|
1653
|
+
return {
|
|
1654
|
+
schema: 'enigma.private_handoff_health.v1',
|
|
1655
|
+
reachable,
|
|
1656
|
+
origin,
|
|
1657
|
+
latencyMs: Date.now() - startedAt,
|
|
1658
|
+
desktop: reachable ? body : null,
|
|
1659
|
+
protocolUrl,
|
|
1660
|
+
directProbeConfigured: Boolean(process.env.ENIGMA_DESKTOP_URL),
|
|
1661
|
+
privateSessionResource: PRIVATE_SESSION_HANDOFF_RESOURCE_URI,
|
|
1662
|
+
...(reachable ? {} : { reason: 'invalid_enigma_health_schema' }),
|
|
1663
|
+
};
|
|
1664
|
+
} catch {
|
|
1665
|
+
return {
|
|
1666
|
+
schema: 'enigma.private_handoff_health.v1',
|
|
1667
|
+
reachable: false,
|
|
1668
|
+
origin,
|
|
1669
|
+
latencyMs: Date.now() - startedAt,
|
|
1670
|
+
desktop: null,
|
|
1671
|
+
protocolUrl,
|
|
1672
|
+
directProbeConfigured: Boolean(process.env.ENIGMA_DESKTOP_URL),
|
|
1673
|
+
privateSessionResource: PRIVATE_SESSION_HANDOFF_RESOURCE_URI,
|
|
1674
|
+
action: 'Launch the Enigma desktop app through the enigma:// protocol. Set ENIGMA_DESKTOP_URL only for a known CLI host.',
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
export function enigma_routing_contract(input = {}) {
|
|
1680
|
+
validateToolArguments('enigma_routing_contract', input);
|
|
1681
|
+
return {
|
|
1682
|
+
schema: 'enigma.private_routing_contract.v1',
|
|
1683
|
+
decision: {
|
|
1684
|
+
sensitiveOrPrivate: 'Call enigma_start_private_session with a non-sensitive intent label only.',
|
|
1685
|
+
alreadyHostVisible: 'Use normal Enigma memory tools only when the user accepts that the host can inspect the supplied text.',
|
|
1686
|
+
actualPrivatePrompt: 'The user types it inside Enigma to keep it out of the MCP host chat; the configured provider still receives prepared adapter input.',
|
|
1687
|
+
},
|
|
1688
|
+
hostVisible: [
|
|
1689
|
+
'Messages typed into the host chat.',
|
|
1690
|
+
'The fact that an Enigma private session was requested.',
|
|
1691
|
+
'Non-sensitive intent and model labels passed to the handoff tool.',
|
|
1692
|
+
'Any text explicitly passed to ordinary MCP tool arguments.',
|
|
1693
|
+
],
|
|
1694
|
+
keptOutOfMcpHost: [
|
|
1695
|
+
'The prompt typed after the Enigma workspace opens.',
|
|
1696
|
+
'The in-memory workspace transcript until refresh or explicit clearing.',
|
|
1697
|
+
'The provider response rendered inside the workspace.',
|
|
1698
|
+
],
|
|
1699
|
+
providerVisible: [
|
|
1700
|
+
'The prompt and retrieved context prepared for the selected adapter.',
|
|
1701
|
+
'Anchor Guard can mask documented patterns but does not detect arbitrary sensitive prose.',
|
|
1702
|
+
],
|
|
1703
|
+
claims: {
|
|
1704
|
+
hostChatInvisible: false,
|
|
1705
|
+
privateHandoffAvailable: true,
|
|
1706
|
+
promptRelayIsPrivateFromHost: false,
|
|
1707
|
+
workspacePromptReturnedToMcpHost: false,
|
|
1708
|
+
configuredProviderReceivesAdapterInput: true,
|
|
1709
|
+
configuredProviderInvisible: false,
|
|
1710
|
+
},
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
export function enigma_start_private_session(input = {}) {
|
|
1715
|
+
input = validateToolArguments('enigma_start_private_session', input);
|
|
1716
|
+
const intent = input.intent?.trim() || 'private question';
|
|
1717
|
+
const model = input.model?.trim() || null;
|
|
1718
|
+
return {
|
|
1719
|
+
schema: 'enigma.private_session_handoff.v1',
|
|
1720
|
+
url: privateSessionUrl({ intent, ...(model ? { model } : {}) }),
|
|
1721
|
+
intent,
|
|
1722
|
+
model,
|
|
1723
|
+
resourceUri: PRIVATE_SESSION_HANDOFF_RESOURCE_URI,
|
|
1724
|
+
embedEnabled: true,
|
|
1725
|
+
hostBoundary: 'The workspace keeps the prompt out of the MCP host chat. The configured provider receives Enigma-prepared adapter input.',
|
|
1726
|
+
providerBoundary: 'Anchor Guard may mask email, wallet, IPv4, formatted phone, and base58 patterns. It does not make arbitrary sensitive prose invisible to the configured provider.',
|
|
1727
|
+
instructionsForHost: [
|
|
1728
|
+
'Do not ask the user to paste the sensitive prompt into the host chat.',
|
|
1729
|
+
'Do not place the sensitive prompt in an MCP tool argument.',
|
|
1730
|
+
'Open the Enigma private session and let the user type there.',
|
|
1731
|
+
],
|
|
1732
|
+
instructionsForUser: [
|
|
1733
|
+
'Open the Enigma private workspace.',
|
|
1734
|
+
'Choose a configured route if needed.',
|
|
1735
|
+
'Type the actual private prompt inside Enigma.',
|
|
1736
|
+
'The configured provider receives the prepared adapter input when you send.',
|
|
1737
|
+
],
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
765
1740
|
export function enigma_standard_memory_prompt(input = {}) {
|
|
766
1741
|
const args = input?.arguments && typeof input.arguments === 'object' && !Array.isArray(input.arguments)
|
|
767
1742
|
? input.arguments
|
|
@@ -788,66 +1763,140 @@ export function enigma_standard_memory_prompt(input = {}) {
|
|
|
788
1763
|
};
|
|
789
1764
|
}
|
|
790
1765
|
|
|
1766
|
+
function requireInferenceRuntime(capability) {
|
|
1767
|
+
if (!configuredInferenceRuntime || typeof configuredInferenceRuntime[capability] !== 'object') {
|
|
1768
|
+
throw new Error(`Enigma ${capability} inference runtime is not configured`);
|
|
1769
|
+
}
|
|
1770
|
+
return configuredInferenceRuntime;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
export async function enigma_complete(input = {}) {
|
|
1774
|
+
input = validateToolArguments('enigma_complete', input);
|
|
1775
|
+
const runtime = requireInferenceRuntime('chat');
|
|
1776
|
+
return runtime.chat.complete({
|
|
1777
|
+
messages: input.messages,
|
|
1778
|
+
model: input.model || 'enigma-auto',
|
|
1779
|
+
privacyMode: input.privacy_mode || 'smart',
|
|
1780
|
+
temperature: input.temperature,
|
|
1781
|
+
maxTokens: input.max_tokens,
|
|
1782
|
+
reasoningEffort: input.reasoning_effort,
|
|
1783
|
+
webSearch: input.web_search === true,
|
|
1784
|
+
requirePrivateRoute: input.require_private_route === true,
|
|
1785
|
+
stream: false,
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
export async function enigma_generate_image(input = {}) {
|
|
1790
|
+
input = validateToolArguments('enigma_generate_image', input);
|
|
1791
|
+
const runtime = requireInferenceRuntime('images');
|
|
1792
|
+
return runtime.images.generate({
|
|
1793
|
+
prompt: input.prompt,
|
|
1794
|
+
model: input.model,
|
|
1795
|
+
negativePrompt: input.negative_prompt,
|
|
1796
|
+
width: input.width,
|
|
1797
|
+
height: input.height,
|
|
1798
|
+
steps: input.steps,
|
|
1799
|
+
cfgScale: input.cfg_scale,
|
|
1800
|
+
variants: input.variants,
|
|
1801
|
+
format: input.format,
|
|
1802
|
+
seed: input.seed,
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
export async function enigma_x402_execute(input = {}) {
|
|
1807
|
+
input = validateToolArguments('enigma_x402_execute', input);
|
|
1808
|
+
if (!configuredX402Client) throw new Error('Enigma x402 execution client is not configured');
|
|
1809
|
+
const headers = { ...(input.headers || {}) };
|
|
1810
|
+
const body = input.body === undefined
|
|
1811
|
+
? undefined
|
|
1812
|
+
: typeof input.body === 'string'
|
|
1813
|
+
? input.body
|
|
1814
|
+
: JSON.stringify(input.body);
|
|
1815
|
+
if (body !== undefined && !Object.keys(headers).some((name) => name.toLowerCase() === 'content-type')) {
|
|
1816
|
+
headers['Content-Type'] = 'application/json';
|
|
1817
|
+
}
|
|
1818
|
+
const execution = await configuredX402Client(input.url, { method: input.method || 'GET', headers, body });
|
|
1819
|
+
const maximum = input.max_response_bytes || 262144;
|
|
1820
|
+
const declared = Number(execution.response.headers.get('content-length'));
|
|
1821
|
+
if (Number.isFinite(declared) && declared > maximum) {
|
|
1822
|
+
await execution.response.body?.cancel?.();
|
|
1823
|
+
throw new Error('x402 resource response exceeds the configured limit');
|
|
1824
|
+
}
|
|
1825
|
+
const bytes = Buffer.from(await execution.response.arrayBuffer());
|
|
1826
|
+
if (bytes.length > maximum) throw new Error('x402 resource response exceeds the configured limit');
|
|
1827
|
+
const contentType = execution.response.headers.get('content-type') || 'application/octet-stream';
|
|
1828
|
+
let responseBody = bytes.toString('utf8');
|
|
1829
|
+
if (contentType.includes('application/json')) {
|
|
1830
|
+
try { responseBody = JSON.parse(responseBody); } catch { throw new Error('x402 resource returned invalid JSON'); }
|
|
1831
|
+
}
|
|
1832
|
+
return {
|
|
1833
|
+
schema: 'enigma.x402_execution.v1',
|
|
1834
|
+
status: execution.response.status,
|
|
1835
|
+
contentType,
|
|
1836
|
+
body: responseBody,
|
|
1837
|
+
settlement: execution.settlement,
|
|
1838
|
+
paymentRequired: execution.paymentRequired,
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
|
|
791
1842
|
export async function enigma_init(input = {}) {
|
|
792
1843
|
input = validateToolArguments('enigma_init', input);
|
|
793
1844
|
const path = bundlePath(input);
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1845
|
+
const credentials = bundleCredentials(input);
|
|
1846
|
+
return withBundleFileLock(path, async () => {
|
|
1847
|
+
if (await fileExists(path)) {
|
|
1848
|
+
const state = await loadState(path, input);
|
|
1849
|
+
return bundleSummary(path, state.stored, false);
|
|
1850
|
+
}
|
|
1851
|
+
const vault = createVault({
|
|
1852
|
+
tenant_id: input.tenant_id,
|
|
1853
|
+
subject_id: input.subject_id,
|
|
1854
|
+
actor_id: input.actor_id,
|
|
1855
|
+
policy_id: input.policy_id,
|
|
1856
|
+
passphrase: credentials.passphrase,
|
|
1857
|
+
});
|
|
1858
|
+
const bundle = await persistState(path, vault, { ...input, lockHeld: true, expectedRevision: null });
|
|
1859
|
+
return bundleSummary(path, bundle, true);
|
|
805
1860
|
});
|
|
806
|
-
const bundle = await persistState(path, vault);
|
|
807
|
-
return bundleSummary(path, bundle, true);
|
|
808
1861
|
}
|
|
809
1862
|
|
|
810
1863
|
export async function enigma_remember(input = {}) {
|
|
811
1864
|
input = validateToolArguments('enigma_remember', input);
|
|
812
1865
|
const path = bundlePath(input);
|
|
813
|
-
const {
|
|
814
|
-
const result = remember({
|
|
1866
|
+
const { result } = await withVaultTransaction(path, input, ({ vault, passport }) => remember({
|
|
815
1867
|
vault,
|
|
816
1868
|
passport,
|
|
817
1869
|
text: input.text,
|
|
818
1870
|
purpose: input.purpose ?? 'mcp_memory',
|
|
819
1871
|
purpose_tags: Array.isArray(input.tags) ? input.tags : [],
|
|
820
1872
|
metadata: input.metadata ?? {},
|
|
821
|
-
});
|
|
822
|
-
await persistState(path, vault);
|
|
1873
|
+
}));
|
|
823
1874
|
return { ok: true, memory_addr: result.memory_addr, receipt_id: result.receipt?.receipt_id };
|
|
824
1875
|
}
|
|
825
1876
|
|
|
826
1877
|
export async function enigma_search(input = {}) {
|
|
827
1878
|
input = validateToolArguments('enigma_search', input);
|
|
828
1879
|
const path = bundlePath(input);
|
|
829
|
-
const {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1880
|
+
const { result } = await withVaultTransaction(path, input, ({ vault, passport }) => {
|
|
1881
|
+
if (input.memory_addr) {
|
|
1882
|
+
return recall({ vault, passport, memory_addr: input.memory_addr, purpose: input.purpose ?? 'mcp_search' });
|
|
1883
|
+
}
|
|
1884
|
+
const pack = compileContextPack({
|
|
1885
|
+
vault,
|
|
1886
|
+
passport,
|
|
1887
|
+
query: input.query ?? '',
|
|
1888
|
+
purpose: input.purpose ?? 'mcp_search',
|
|
1889
|
+
limit: Number(input.limit ?? 8),
|
|
1890
|
+
});
|
|
1891
|
+
return { memories: pack.memories ?? [], receipts: pack.retrieval_receipts ?? pack.receipts ?? [] };
|
|
841
1892
|
});
|
|
842
|
-
|
|
843
|
-
return { memories: pack.memories ?? [], receipts: pack.retrieval_receipts ?? pack.receipts ?? [] };
|
|
1893
|
+
return result;
|
|
844
1894
|
}
|
|
845
1895
|
|
|
846
1896
|
export async function enigma_context_pack(input = {}) {
|
|
847
1897
|
input = validateToolArguments('enigma_context_pack', input);
|
|
848
1898
|
const path = bundlePath(input);
|
|
849
|
-
const {
|
|
850
|
-
const pack = compileContextPack({
|
|
1899
|
+
const { result } = await withVaultTransaction(path, input, ({ vault, passport }) => compileContextPack({
|
|
851
1900
|
vault,
|
|
852
1901
|
passport,
|
|
853
1902
|
query: input.query ?? '',
|
|
@@ -858,29 +1907,107 @@ export async function enigma_context_pack(input = {}) {
|
|
|
858
1907
|
currency: input.currency,
|
|
859
1908
|
limit: Number(input.limit ?? 8),
|
|
860
1909
|
memory_addresses: input.memory_addresses,
|
|
861
|
-
});
|
|
862
|
-
|
|
863
|
-
return pack;
|
|
1910
|
+
}));
|
|
1911
|
+
return result;
|
|
864
1912
|
}
|
|
865
1913
|
|
|
866
1914
|
export async function enigma_delete(input = {}) {
|
|
867
1915
|
input = validateToolArguments('enigma_delete', input);
|
|
868
1916
|
const path = bundlePath(input);
|
|
869
|
-
const {
|
|
870
|
-
const result = deleteMemory({
|
|
1917
|
+
const { result } = await withVaultTransaction(path, input, ({ vault, passport }) => deleteMemory({
|
|
871
1918
|
vault,
|
|
872
1919
|
passport,
|
|
873
1920
|
memory_addr: input.memory_addr,
|
|
874
1921
|
reason: input.reason ?? 'mcp_delete',
|
|
875
|
-
});
|
|
876
|
-
await persistState(path, vault);
|
|
1922
|
+
}));
|
|
877
1923
|
return { ok: true, memory_addr: result.memory_addr, receipt_id: result.receipt?.receipt_id };
|
|
878
1924
|
}
|
|
879
1925
|
|
|
1926
|
+
export async function enigma_vault_rotate(input = {}) {
|
|
1927
|
+
input = validateToolArguments('enigma_vault_rotate', input);
|
|
1928
|
+
const path = bundlePath(input);
|
|
1929
|
+
const { result } = await withVaultTransaction(path, input, ({ vault }) => rotateContentKey({
|
|
1930
|
+
vault,
|
|
1931
|
+
key_id: input.key_id,
|
|
1932
|
+
}));
|
|
1933
|
+
return { ok: true, operation: 'key_rotate', ...result };
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
export async function enigma_vault_seal(input = {}) {
|
|
1937
|
+
input = validateToolArguments('enigma_vault_seal', input);
|
|
1938
|
+
const path = bundlePath(input);
|
|
1939
|
+
const { result } = await withVaultTransaction(path, input, ({ vault }) => sealContentKeyEpoch({
|
|
1940
|
+
vault,
|
|
1941
|
+
epoch: input.epoch,
|
|
1942
|
+
}));
|
|
1943
|
+
return { ok: true, operation: 'key_seal', ...result };
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
export async function enigma_vault_reset(input = {}) {
|
|
1947
|
+
input = validateToolArguments('enigma_vault_reset', input);
|
|
1948
|
+
const path = bundlePath(input);
|
|
1949
|
+
const { result } = await withVaultTransaction(path, input, ({ vault }) => resetVaultContentKeys({
|
|
1950
|
+
vault,
|
|
1951
|
+
key_id: input.key_id,
|
|
1952
|
+
}));
|
|
1953
|
+
return { ok: true, operation: 'key_reset', ...result };
|
|
1954
|
+
}
|
|
1955
|
+
|
|
880
1956
|
export async function enigma_verify_receipts(input = {}) {
|
|
881
1957
|
input = validateToolArguments('enigma_verify_receipts', input);
|
|
882
|
-
|
|
883
|
-
|
|
1958
|
+
if (input.bundle) return verifyBundle(input.bundle);
|
|
1959
|
+
const path = bundlePath(input);
|
|
1960
|
+
bundleCredentials(input);
|
|
1961
|
+
const stored = await readJson(path);
|
|
1962
|
+
const report = verifyBundle(stored);
|
|
1963
|
+
if (!report.ok) return report;
|
|
1964
|
+
await loadState(path, input);
|
|
1965
|
+
return report;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
async function activeSwarmAtoms(input) {
|
|
1969
|
+
const path = bundlePath(input);
|
|
1970
|
+
if (!(await fileExists(path))) return [];
|
|
1971
|
+
const { result } = await withVaultTransaction(path, input, ({ vault, passport }) => {
|
|
1972
|
+
const atoms = [];
|
|
1973
|
+
for (const memoryAddr of [...vault.activeAddresses].sort()) {
|
|
1974
|
+
const recalled = recall({
|
|
1975
|
+
vault,
|
|
1976
|
+
passport,
|
|
1977
|
+
memory_addr: memoryAddr,
|
|
1978
|
+
purpose: 'mcp_swarm_context',
|
|
1979
|
+
});
|
|
1980
|
+
const { content_ciphertext: ignoredCiphertext, ...memory } = recalled.memory;
|
|
1981
|
+
atoms.push({ ...memory, content: recalled.content });
|
|
1982
|
+
}
|
|
1983
|
+
return atoms;
|
|
1984
|
+
});
|
|
1985
|
+
return result;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
export async function enigma_swarm_register_agent(input = {}) {
|
|
1989
|
+
input = validateToolArguments('enigma_swarm_register_agent', input);
|
|
1990
|
+
return routeSwarmRegisterAgent(input);
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
export async function enigma_graph_query(input = {}) {
|
|
1994
|
+
input = validateToolArguments('enigma_graph_query', input);
|
|
1995
|
+
return routeGraphQuery({ ...input, atoms: await activeSwarmAtoms(input) });
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
export async function enigma_cluster_memories(input = {}) {
|
|
1999
|
+
input = validateToolArguments('enigma_cluster_memories', input);
|
|
2000
|
+
return routeClusterMemories({ ...input, atoms: await activeSwarmAtoms(input) });
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
export async function enigma_swarm_sync(input = {}) {
|
|
2004
|
+
input = validateToolArguments('enigma_swarm_sync', input);
|
|
2005
|
+
return routeSwarmSync({ ...input, atoms: await activeSwarmAtoms(input) });
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
export async function enigma_immune_ingress(input = {}) {
|
|
2009
|
+
input = validateToolArguments('enigma_immune_ingress', input);
|
|
2010
|
+
return createMcpImmuneIngressReport(input);
|
|
884
2011
|
}
|
|
885
2012
|
|
|
886
2013
|
export async function enigma_meter_usage(input = {}) {
|
|
@@ -943,13 +2070,130 @@ export async function enigma_settlement_batch(input = {}) {
|
|
|
943
2070
|
}
|
|
944
2071
|
|
|
945
2072
|
|
|
2073
|
+
export async function enigma_vault_create_record(input = {}) {
|
|
2074
|
+
input = validateToolArguments('enigma_vault_create_record', input);
|
|
2075
|
+
return defaultEnclave.createRecord(input.plaintext, input.metadata || {});
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
export async function enigma_vault_zeroize_record(input = {}) {
|
|
2079
|
+
input = validateToolArguments('enigma_vault_zeroize_record', input);
|
|
2080
|
+
return defaultEnclave.zeroizeRecord(input.recordId);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
export async function enigma_verify_erasure_attestation(input = {}) {
|
|
2084
|
+
input = validateToolArguments('enigma_verify_erasure_attestation', input);
|
|
2085
|
+
return AttestationVerifier.verify(input.attestation, {
|
|
2086
|
+
// Simulated attestations are developer-mode only: must be explicitly enabled.
|
|
2087
|
+
allowSimulated: input.allowSimulated ?? false,
|
|
2088
|
+
allowlistedSimulatedKeyPem: defaultEnclave.publicKeyPem,
|
|
2089
|
+
expectedPcr: input.expectedPcr,
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
export async function enigma_nullifier_record_tombstone(input = {}) {
|
|
2094
|
+
input = validateToolArguments('enigma_nullifier_record_tombstone', input);
|
|
2095
|
+
const { PublicKey } = await import('@solana/web3.js');
|
|
2096
|
+
|
|
2097
|
+
const programId = 'E18KZR1Jq8fG3FFACpoHsE21ME3t1ftKPEwXL7cFWkoZ';
|
|
2098
|
+
const programKey = new PublicKey(programId);
|
|
2099
|
+
// Strict 32-byte hex validation — no padding, no truncation, no silent mutation.
|
|
2100
|
+
const HEX32_RE = /^(0x)?[0-9a-fA-F]{64}$/;
|
|
2101
|
+
if (!HEX32_RE.test(input.commitment)) {
|
|
2102
|
+
throw new Error('enigma_nullifier_record_tombstone: commitment must be exactly 32 bytes of hex (64 hex chars, optional 0x prefix)');
|
|
2103
|
+
}
|
|
2104
|
+
if (!HEX32_RE.test(input.nullifierHash)) {
|
|
2105
|
+
throw new Error('enigma_nullifier_record_tombstone: nullifierHash must be exactly 32 bytes of hex (64 hex chars, optional 0x prefix)');
|
|
2106
|
+
}
|
|
2107
|
+
const commitmentClean = input.commitment.replace(/^0x/, '');
|
|
2108
|
+
const nullifierClean = input.nullifierHash.replace(/^0x/, '');
|
|
2109
|
+
|
|
2110
|
+
const commitmentBytes = Buffer.from(commitmentClean, 'hex');
|
|
2111
|
+
const nullifierBytes = Buffer.from(nullifierClean, 'hex');
|
|
2112
|
+
if (commitmentBytes.length !== 32 || nullifierBytes.length !== 32) {
|
|
2113
|
+
throw new Error('enigma_nullifier_record_tombstone: decoded values must be exactly 32 bytes');
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// Owner is the required Signer; the tombstone PDA is derived from owner + commitment.
|
|
2117
|
+
let ownerKey;
|
|
2118
|
+
try {
|
|
2119
|
+
ownerKey = new PublicKey(input.ownerPubkey);
|
|
2120
|
+
} catch {
|
|
2121
|
+
throw new Error('enigma_nullifier_record_tombstone: ownerPubkey must be a valid base58 public key');
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
const [commitmentPda, commitmentBump] = PublicKey.findProgramAddressSync(
|
|
2125
|
+
[Buffer.from('commitment'), ownerKey.toBuffer(), commitmentBytes],
|
|
2126
|
+
programKey,
|
|
2127
|
+
);
|
|
2128
|
+
const [tombstonePda, tombstoneBump] = PublicKey.findProgramAddressSync(
|
|
2129
|
+
[Buffer.from('tombstone'), ownerKey.toBuffer(), commitmentBytes],
|
|
2130
|
+
programKey,
|
|
2131
|
+
);
|
|
2132
|
+
const [registryPda, registryBump] = PublicKey.findProgramAddressSync(
|
|
2133
|
+
[Buffer.from('nullifier_registry')],
|
|
2134
|
+
programKey,
|
|
2135
|
+
);
|
|
2136
|
+
|
|
2137
|
+
// Anchor discriminator for global:record_revocation (owner-signed revocation record;
|
|
2138
|
+
// no PCR/attestation framing — physical deletion is out of scope).
|
|
2139
|
+
const discriminator = Buffer.from([108, 45, 14, 21, 217, 230, 163, 121]);
|
|
2140
|
+
const instructionData = Buffer.concat([
|
|
2141
|
+
discriminator,
|
|
2142
|
+
commitmentBytes,
|
|
2143
|
+
nullifierBytes,
|
|
2144
|
+
]);
|
|
2145
|
+
|
|
2146
|
+
// Ordered account metas matching RecordRevocation (commitment_record, tombstone,
|
|
2147
|
+
// registry, owner, system). The commitment must be registered first — revocation
|
|
2148
|
+
// flips its is_nullified flag on-chain.
|
|
2149
|
+
const accounts = [
|
|
2150
|
+
{ pubkey: commitmentPda.toBase58(), isSigner: false, isWritable: true, role: 'commitment_record', bump: commitmentBump },
|
|
2151
|
+
{ pubkey: tombstonePda.toBase58(), isSigner: false, isWritable: true, role: 'tombstone', bump: tombstoneBump },
|
|
2152
|
+
{ pubkey: registryPda.toBase58(), isSigner: false, isWritable: true, role: 'registry', bump: registryBump },
|
|
2153
|
+
{ pubkey: ownerKey.toBase58(), isSigner: true, isWritable: true, role: 'owner' },
|
|
2154
|
+
{ pubkey: '11111111111111111111111111111111', isSigner: false, isWritable: false, role: 'system_program' },
|
|
2155
|
+
];
|
|
2156
|
+
|
|
2157
|
+
return {
|
|
2158
|
+
programId,
|
|
2159
|
+
instruction: 'record_revocation',
|
|
2160
|
+
discriminator: Array.from(discriminator),
|
|
2161
|
+
accounts,
|
|
2162
|
+
instructionDataHex: instructionData.toString('hex'),
|
|
2163
|
+
commitment: input.commitment,
|
|
2164
|
+
nullifierHash: input.nullifierHash,
|
|
2165
|
+
ownerPubkey: ownerKey.toBase58(),
|
|
2166
|
+
requiresOwnerSignature: true,
|
|
2167
|
+
requiresRegisteredCommitment: true,
|
|
2168
|
+
timestamp: new Date().toISOString(),
|
|
2169
|
+
broadcastReady: true,
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
|
|
2174
|
+
// enigma_verify_erasure_attestation deliberately excluded from RPC handlers (see
|
|
2175
|
+
// toolDescriptors note above): hardware attestation verification is not yet safe.
|
|
946
2176
|
export const handlers = Object.freeze({
|
|
2177
|
+
enigma_private_handoff_health,
|
|
2178
|
+
enigma_routing_contract,
|
|
2179
|
+
enigma_start_private_session,
|
|
2180
|
+
enigma_complete,
|
|
2181
|
+
enigma_generate_image,
|
|
2182
|
+
enigma_x402_execute,
|
|
947
2183
|
enigma_init,
|
|
948
2184
|
enigma_remember,
|
|
949
2185
|
enigma_search,
|
|
950
2186
|
enigma_context_pack,
|
|
951
2187
|
enigma_delete,
|
|
2188
|
+
enigma_vault_rotate,
|
|
2189
|
+
enigma_vault_seal,
|
|
2190
|
+
enigma_vault_reset,
|
|
952
2191
|
enigma_verify_receipts,
|
|
2192
|
+
enigma_swarm_register_agent,
|
|
2193
|
+
enigma_graph_query,
|
|
2194
|
+
enigma_cluster_memories,
|
|
2195
|
+
enigma_swarm_sync,
|
|
2196
|
+
enigma_immune_ingress,
|
|
953
2197
|
enigma_meter_usage,
|
|
954
2198
|
enigma_settlement_job,
|
|
955
2199
|
enigma_settlement_capacity,
|
|
@@ -957,6 +2201,9 @@ export const handlers = Object.freeze({
|
|
|
957
2201
|
enigma_settlement_receipt,
|
|
958
2202
|
enigma_settlement_verify,
|
|
959
2203
|
enigma_settlement_batch,
|
|
2204
|
+
enigma_vault_create_record,
|
|
2205
|
+
enigma_vault_zeroize_record,
|
|
2206
|
+
enigma_nullifier_record_tombstone,
|
|
960
2207
|
});
|
|
961
2208
|
|
|
962
2209
|
function jsonRpcResult(id, result) {
|
|
@@ -987,6 +2234,28 @@ function toolHandler(name) {
|
|
|
987
2234
|
|
|
988
2235
|
function toolCallContent(result, toolName) {
|
|
989
2236
|
const verificationFailed = (toolName === 'enigma_verify_receipts' || toolName === 'enigma_settlement_verify') && result && typeof result === 'object' && result.ok === false;
|
|
2237
|
+
if (toolName === 'enigma_generate_image' && result && typeof result === 'object') {
|
|
2238
|
+
const content = [];
|
|
2239
|
+
const assets = (result.assets || []).map((asset, index) => {
|
|
2240
|
+
const mimeType = `image/${asset.format === 'jpg' ? 'jpeg' : asset.format || 'webp'}`;
|
|
2241
|
+
if (typeof asset.base64 === 'string') {
|
|
2242
|
+
content.push({ type: 'image', data: asset.base64, mimeType });
|
|
2243
|
+
return { index, format: asset.format, inline: true };
|
|
2244
|
+
}
|
|
2245
|
+
if (typeof asset.url === 'string' && asset.url.startsWith('data:')) {
|
|
2246
|
+
const match = /^data:([^;,]+);base64,(.+)$/s.exec(asset.url);
|
|
2247
|
+
if (match) {
|
|
2248
|
+
content.push({ type: 'image', data: match[2], mimeType: match[1] });
|
|
2249
|
+
return { index, format: asset.format, inline: true };
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
content.push({ type: 'text', text: `Generated image ${index + 1}: ${asset.url}` });
|
|
2253
|
+
return { index, format: asset.format, url: asset.url };
|
|
2254
|
+
});
|
|
2255
|
+
const structuredContent = { ...result, assets };
|
|
2256
|
+
content.unshift({ type: 'text', text: JSON.stringify(structuredContent) });
|
|
2257
|
+
return { content, structuredContent, isError: false };
|
|
2258
|
+
}
|
|
990
2259
|
return {
|
|
991
2260
|
content: [{ type: 'text', text: JSON.stringify(result ?? null) }],
|
|
992
2261
|
structuredContent: result ?? null,
|
|
@@ -1020,7 +2289,7 @@ function validateNoParams(params, method) {
|
|
|
1020
2289
|
rejectAdditionalProperties(input, new Set(), `${method} params`);
|
|
1021
2290
|
}
|
|
1022
2291
|
|
|
1023
|
-
async function handleSingleJsonRpcRequest(request) {
|
|
2292
|
+
async function handleSingleJsonRpcRequest(request, context = {}) {
|
|
1024
2293
|
if (!isRequestObject(request)) return jsonRpcError(null, JSON_RPC_ERROR.INVALID_REQUEST, 'Invalid Request');
|
|
1025
2294
|
|
|
1026
2295
|
const notification = !hasJsonRpcId(request);
|
|
@@ -1031,6 +2300,12 @@ async function handleSingleJsonRpcRequest(request) {
|
|
|
1031
2300
|
if (request.jsonrpc !== JSONRPC_VERSION || typeof request.method !== 'string') {
|
|
1032
2301
|
return jsonRpcError(id, JSON_RPC_ERROR.INVALID_REQUEST, 'Invalid Request');
|
|
1033
2302
|
}
|
|
2303
|
+
if (context.transport === 'streamable-http') {
|
|
2304
|
+
const requiredScopes = requiredScopesForMcpPayload(request);
|
|
2305
|
+
if (!context.principal || !Array.isArray(context.principal.scopes) || requiredScopes.some((scope) => !context.principal.scopes.includes(scope))) {
|
|
2306
|
+
return notification ? undefined : jsonRpcError(id, JSON_RPC_ERROR.INVALID_REQUEST, 'Insufficient OAuth scope.', { requiredScopes });
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
1034
2309
|
|
|
1035
2310
|
try {
|
|
1036
2311
|
switch (request.method) {
|
|
@@ -1054,7 +2329,7 @@ async function handleSingleJsonRpcRequest(request) {
|
|
|
1054
2329
|
return notification ? undefined : jsonRpcResult(id, {});
|
|
1055
2330
|
case 'tools/list':
|
|
1056
2331
|
validateNoParams(request.params, 'tools/list');
|
|
1057
|
-
return notification ? undefined : jsonRpcResult(id, { tools: toolDescriptors });
|
|
2332
|
+
return notification ? undefined : jsonRpcResult(id, { tools: context.transport === 'streamable-http' ? remoteToolDescriptors() : toolDescriptors });
|
|
1058
2333
|
case 'resources/list':
|
|
1059
2334
|
validateNoParams(request.params, 'resources/list');
|
|
1060
2335
|
return notification ? undefined : jsonRpcResult(id, { resources: resourceDescriptors });
|
|
@@ -1063,11 +2338,32 @@ async function handleSingleJsonRpcRequest(request) {
|
|
|
1063
2338
|
return notification ? undefined : jsonRpcResult(id, { resourceTemplates: [] });
|
|
1064
2339
|
case 'resources/read': {
|
|
1065
2340
|
const params = ensureParamsObject(request.params, 'resources/read');
|
|
1066
|
-
rejectAdditionalProperties(params, new Set(['uri', 'bundlePath']), 'resources/read params');
|
|
2341
|
+
rejectAdditionalProperties(params, new Set(['uri', 'bundlePath', 'insecureDevMode']), 'resources/read params');
|
|
1067
2342
|
requireString(params, 'uri', 'resources/read params');
|
|
1068
2343
|
optionalString(params, 'bundlePath', 'resources/read params');
|
|
1069
|
-
|
|
1070
|
-
const
|
|
2344
|
+
optionalBoolean(params, 'insecureDevMode', 'resources/read params');
|
|
2345
|
+
const normalizedUri = normalizeResourceUri(params.uri);
|
|
2346
|
+
let result;
|
|
2347
|
+
if (normalizedUri === PASSPORT_SUMMARY_RESOURCE_URI) {
|
|
2348
|
+
result = await enigma_passport_summary_resource(await bindRemoteResourceInput(params, normalizedUri, context));
|
|
2349
|
+
} else if (normalizedUri === PRIVATE_SESSION_HANDOFF_RESOURCE_URI) {
|
|
2350
|
+
result = enigma_private_session_resource({ uri: normalizedUri });
|
|
2351
|
+
} else {
|
|
2352
|
+
throw invalidParams('Unknown resource.');
|
|
2353
|
+
}
|
|
2354
|
+
if (context.transport === 'streamable-http' && Array.isArray(result?.contents)) {
|
|
2355
|
+
result = {
|
|
2356
|
+
...result,
|
|
2357
|
+
contents: result.contents.map((content) => {
|
|
2358
|
+
if (content?.mimeType !== 'application/json' || typeof content.text !== 'string') return content;
|
|
2359
|
+
try {
|
|
2360
|
+
return { ...content, text: JSON.stringify(sanitizeRemoteCustodyOutput(JSON.parse(content.text), context)) };
|
|
2361
|
+
} catch {
|
|
2362
|
+
return content;
|
|
2363
|
+
}
|
|
2364
|
+
}),
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
1071
2367
|
return notification ? undefined : jsonRpcResult(id, result);
|
|
1072
2368
|
}
|
|
1073
2369
|
case 'prompts/list':
|
|
@@ -1087,9 +2383,11 @@ async function handleSingleJsonRpcRequest(request) {
|
|
|
1087
2383
|
requireString(params, 'name', 'tools/call params');
|
|
1088
2384
|
const handler = toolHandler(params.name);
|
|
1089
2385
|
if (!handler) throw invalidParams('Unknown tool.');
|
|
1090
|
-
const args =
|
|
2386
|
+
const args = context.transport === 'streamable-http'
|
|
2387
|
+
? await bindRemoteToolArguments(params.name, params.arguments ?? {}, context)
|
|
2388
|
+
: toolArguments(params.name, params);
|
|
1091
2389
|
try {
|
|
1092
|
-
const result = await handler(args);
|
|
2390
|
+
const result = sanitizeRemoteCustodyOutput(await handler(args), context);
|
|
1093
2391
|
return notification ? undefined : jsonRpcResult(id, toolCallContent(result, params.name));
|
|
1094
2392
|
} catch (error) {
|
|
1095
2393
|
return notification ? undefined : jsonRpcResult(id, toolCallError(error));
|
|
@@ -1105,13 +2403,13 @@ async function handleSingleJsonRpcRequest(request) {
|
|
|
1105
2403
|
}
|
|
1106
2404
|
}
|
|
1107
2405
|
|
|
1108
|
-
export async function handleJsonRpcRequest(request) {
|
|
1109
|
-
if (!Array.isArray(request)) return handleSingleJsonRpcRequest(request);
|
|
2406
|
+
export async function handleJsonRpcRequest(request, context = {}) {
|
|
2407
|
+
if (!Array.isArray(request)) return handleSingleJsonRpcRequest(request, context);
|
|
1110
2408
|
if (request.length === 0) return jsonRpcError(null, JSON_RPC_ERROR.INVALID_REQUEST, 'Invalid Request');
|
|
1111
2409
|
|
|
1112
2410
|
const responses = [];
|
|
1113
2411
|
for (const item of request) {
|
|
1114
|
-
const response = await handleSingleJsonRpcRequest(item);
|
|
2412
|
+
const response = await handleSingleJsonRpcRequest(item, context);
|
|
1115
2413
|
if (response !== undefined) responses.push(response);
|
|
1116
2414
|
}
|
|
1117
2415
|
return responses.length === 0 ? undefined : responses;
|
|
@@ -1165,12 +2463,25 @@ export default {
|
|
|
1165
2463
|
resourceDescriptors,
|
|
1166
2464
|
promptDescriptors,
|
|
1167
2465
|
handlers,
|
|
2466
|
+
enigma_private_handoff_health,
|
|
2467
|
+
enigma_routing_contract,
|
|
2468
|
+
enigma_start_private_session,
|
|
2469
|
+
configureMcpInferenceRuntime,
|
|
2470
|
+
configureMcpX402Client,
|
|
2471
|
+
enigma_complete,
|
|
2472
|
+
enigma_generate_image,
|
|
2473
|
+
enigma_x402_execute,
|
|
1168
2474
|
enigma_init,
|
|
1169
2475
|
enigma_remember,
|
|
1170
2476
|
enigma_search,
|
|
1171
2477
|
enigma_context_pack,
|
|
1172
2478
|
enigma_delete,
|
|
1173
2479
|
enigma_verify_receipts,
|
|
2480
|
+
enigma_swarm_register_agent,
|
|
2481
|
+
enigma_graph_query,
|
|
2482
|
+
enigma_cluster_memories,
|
|
2483
|
+
enigma_swarm_sync,
|
|
2484
|
+
enigma_immune_ingress,
|
|
1174
2485
|
enigma_meter_usage,
|
|
1175
2486
|
enigma_settlement_job,
|
|
1176
2487
|
enigma_settlement_capacity,
|
|
@@ -1180,6 +2491,8 @@ export default {
|
|
|
1180
2491
|
enigma_settlement_batch,
|
|
1181
2492
|
enigma_passport_summary_resource,
|
|
1182
2493
|
enigma_standard_memory_prompt,
|
|
2494
|
+
createMcpImmuneIngressReport,
|
|
2495
|
+
assertMcpImmuneIngressPublicSafe,
|
|
1183
2496
|
handleJsonRpcRequest,
|
|
1184
2497
|
startStdioServer,
|
|
1185
2498
|
};
|