@sanctuary-framework/mcp-server 0.2.0
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/LICENSE +190 -0
- package/README.md +210 -0
- package/dist/cli.cjs +4451 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +4449 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +4524 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1207 -0
- package/dist/index.d.ts +1207 -0
- package/dist/index.js +4502 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sanctuary MCP Server — Configuration
|
|
5
|
+
*
|
|
6
|
+
* Loads and validates server configuration from file or environment variables.
|
|
7
|
+
*/
|
|
8
|
+
interface SanctuaryConfig {
|
|
9
|
+
version: string;
|
|
10
|
+
storage_path: string;
|
|
11
|
+
principal_id?: string;
|
|
12
|
+
state: {
|
|
13
|
+
encryption: "aes-256-gcm";
|
|
14
|
+
key_protection: "passphrase" | "hardware-key" | "none";
|
|
15
|
+
key_derivation: "argon2id";
|
|
16
|
+
integrity: "merkle-sha256";
|
|
17
|
+
identity_provider: "ed25519";
|
|
18
|
+
};
|
|
19
|
+
execution: {
|
|
20
|
+
environment: "local-process" | "docker" | "tee";
|
|
21
|
+
attestation: boolean;
|
|
22
|
+
resource_limits: {
|
|
23
|
+
max_memory_mb: number;
|
|
24
|
+
max_storage_mb: number;
|
|
25
|
+
max_cpu_percent: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
disclosure: {
|
|
29
|
+
proof_system: "groth16" | "plonk" | "commitment-only";
|
|
30
|
+
default_policy: "minimum-necessary" | "withhold-all";
|
|
31
|
+
};
|
|
32
|
+
reputation: {
|
|
33
|
+
mode: "self-custodied" | "service-mediated";
|
|
34
|
+
attestation_format: "eas-compatible";
|
|
35
|
+
export_format: "SANCTUARY_REP_V1";
|
|
36
|
+
service_endpoints: string[];
|
|
37
|
+
};
|
|
38
|
+
transport: "stdio" | "http";
|
|
39
|
+
http_port: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Load configuration from file, falling back to defaults.
|
|
43
|
+
*/
|
|
44
|
+
declare function loadConfig(configPath?: string): Promise<SanctuaryConfig>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sanctuary MCP Server — Storage Backend Interface
|
|
48
|
+
*
|
|
49
|
+
* Abstract interface for persistent storage. All state flows through this
|
|
50
|
+
* interface, making the storage backend pluggable (filesystem, IPFS, S3, etc.).
|
|
51
|
+
*
|
|
52
|
+
* The storage backend deals in raw bytes — encryption/decryption happens
|
|
53
|
+
* in the StateStore layer above.
|
|
54
|
+
*/
|
|
55
|
+
/** Metadata about a stored entry */
|
|
56
|
+
interface StorageEntryMeta {
|
|
57
|
+
key: string;
|
|
58
|
+
namespace: string;
|
|
59
|
+
size_bytes: number;
|
|
60
|
+
modified_at: string;
|
|
61
|
+
}
|
|
62
|
+
/** Abstract storage backend interface */
|
|
63
|
+
interface StorageBackend {
|
|
64
|
+
/**
|
|
65
|
+
* Write raw bytes to storage.
|
|
66
|
+
* @param namespace - Logical grouping
|
|
67
|
+
* @param key - Entry key within namespace
|
|
68
|
+
* @param data - Raw bytes to store
|
|
69
|
+
*/
|
|
70
|
+
write(namespace: string, key: string, data: Uint8Array): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Read raw bytes from storage.
|
|
73
|
+
* @returns The stored bytes, or null if not found
|
|
74
|
+
*/
|
|
75
|
+
read(namespace: string, key: string): Promise<Uint8Array | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Delete an entry from storage.
|
|
78
|
+
* @param secureOverwrite - If true, overwrite with random bytes before deletion
|
|
79
|
+
*/
|
|
80
|
+
delete(namespace: string, key: string, secureOverwrite?: boolean): Promise<boolean>;
|
|
81
|
+
/**
|
|
82
|
+
* List all entries in a namespace.
|
|
83
|
+
*/
|
|
84
|
+
list(namespace: string, prefix?: string): Promise<StorageEntryMeta[]>;
|
|
85
|
+
/**
|
|
86
|
+
* Check if an entry exists.
|
|
87
|
+
*/
|
|
88
|
+
exists(namespace: string, key: string): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Get the total size of all stored data.
|
|
91
|
+
*/
|
|
92
|
+
totalSize(): Promise<number>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Sanctuary MCP Server — AES-256-GCM Encryption
|
|
97
|
+
*
|
|
98
|
+
* All state encryption in Sanctuary uses AES-256-GCM (authenticated encryption).
|
|
99
|
+
* This provides both confidentiality and integrity — a modified ciphertext will
|
|
100
|
+
* fail authentication, detecting tampering.
|
|
101
|
+
*
|
|
102
|
+
* Security invariants:
|
|
103
|
+
* - Every encryption uses a unique 12-byte IV (NIST SP 800-38D)
|
|
104
|
+
* - The 16-byte authentication tag is always verified on decryption
|
|
105
|
+
* - Keys are 256 bits (32 bytes)
|
|
106
|
+
*/
|
|
107
|
+
/** Encrypted payload structure stored on disk */
|
|
108
|
+
interface EncryptedPayload {
|
|
109
|
+
/** Format version */
|
|
110
|
+
v: number;
|
|
111
|
+
/** Algorithm identifier */
|
|
112
|
+
alg: "aes-256-gcm";
|
|
113
|
+
/** Initialization vector (base64url) */
|
|
114
|
+
iv: string;
|
|
115
|
+
/** Ciphertext (base64url) */
|
|
116
|
+
ct: string;
|
|
117
|
+
/** Authentication tag (base64url) — included in ciphertext by @noble/ciphers */
|
|
118
|
+
/** Timestamp */
|
|
119
|
+
ts: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sanctuary MCP Server — L1 Cognitive Sovereignty: StateStore
|
|
124
|
+
*
|
|
125
|
+
* The encrypted state store is the foundation of Sanctuary.
|
|
126
|
+
* Every read and write goes through here. All data is encrypted
|
|
127
|
+
* with namespace-specific keys. All writes are signed by an identity.
|
|
128
|
+
* All reads verify integrity via Merkle proofs.
|
|
129
|
+
*
|
|
130
|
+
* Security invariants:
|
|
131
|
+
* - Plaintext never touches the filesystem
|
|
132
|
+
* - Every write gets a unique IV
|
|
133
|
+
* - Every write is signed (non-repudiation)
|
|
134
|
+
* - Monotonic version numbers prevent rollback
|
|
135
|
+
* - Merkle tree verifies namespace integrity
|
|
136
|
+
* - Secure deletion overwrites before unlinking
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/** Result of a state write operation */
|
|
140
|
+
interface WriteResult {
|
|
141
|
+
key: string;
|
|
142
|
+
namespace: string;
|
|
143
|
+
version: number;
|
|
144
|
+
merkle_root: string;
|
|
145
|
+
written_at: string;
|
|
146
|
+
size_bytes: number;
|
|
147
|
+
integrity_hash: string;
|
|
148
|
+
}
|
|
149
|
+
/** Result of a state read operation */
|
|
150
|
+
interface ReadResult {
|
|
151
|
+
key: string;
|
|
152
|
+
namespace: string;
|
|
153
|
+
value: string;
|
|
154
|
+
version: number;
|
|
155
|
+
integrity_verified: boolean;
|
|
156
|
+
merkle_proof: string[];
|
|
157
|
+
written_at: string;
|
|
158
|
+
written_by: string;
|
|
159
|
+
}
|
|
160
|
+
/** Options for state write */
|
|
161
|
+
interface WriteOptions {
|
|
162
|
+
content_type?: string;
|
|
163
|
+
ttl_seconds?: number;
|
|
164
|
+
tags?: string[];
|
|
165
|
+
}
|
|
166
|
+
declare class StateStore {
|
|
167
|
+
private storage;
|
|
168
|
+
private masterKey;
|
|
169
|
+
private versionCache;
|
|
170
|
+
private contentHashes;
|
|
171
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
172
|
+
private versionKey;
|
|
173
|
+
/**
|
|
174
|
+
* Get or initialize the content hash map for a namespace.
|
|
175
|
+
*/
|
|
176
|
+
private getNamespaceHashes;
|
|
177
|
+
/**
|
|
178
|
+
* Write encrypted state.
|
|
179
|
+
*
|
|
180
|
+
* @param namespace - Logical grouping
|
|
181
|
+
* @param key - State key
|
|
182
|
+
* @param value - Plaintext value (will be encrypted)
|
|
183
|
+
* @param identityId - Identity performing the write
|
|
184
|
+
* @param encryptedPrivateKey - Identity's encrypted private key (for signing)
|
|
185
|
+
* @param identityEncryptionKey - Key to decrypt the identity's private key
|
|
186
|
+
* @param options - Optional metadata
|
|
187
|
+
*/
|
|
188
|
+
write(namespace: string, key: string, value: string, identityId: string, encryptedPrivateKey: EncryptedPayload, identityEncryptionKey: Uint8Array, options?: WriteOptions): Promise<WriteResult>;
|
|
189
|
+
/**
|
|
190
|
+
* Read and decrypt state.
|
|
191
|
+
*
|
|
192
|
+
* @param namespace - Logical grouping
|
|
193
|
+
* @param key - State key
|
|
194
|
+
* @param signerPublicKey - Expected signer's public key (for signature verification)
|
|
195
|
+
* @param verifyIntegrity - Whether to verify Merkle proof (default: true)
|
|
196
|
+
*/
|
|
197
|
+
read(namespace: string, key: string, signerPublicKey?: Uint8Array, verifyIntegrity?: boolean): Promise<ReadResult | null>;
|
|
198
|
+
/**
|
|
199
|
+
* List keys in a namespace (metadata only — no decryption).
|
|
200
|
+
*/
|
|
201
|
+
list(namespace: string, prefix?: string, tags?: string[], limit?: number, offset?: number): Promise<{
|
|
202
|
+
keys: Array<{
|
|
203
|
+
key: string;
|
|
204
|
+
version: number;
|
|
205
|
+
size_bytes: number;
|
|
206
|
+
written_at: string;
|
|
207
|
+
tags: string[];
|
|
208
|
+
}>;
|
|
209
|
+
total: number;
|
|
210
|
+
merkle_root: string;
|
|
211
|
+
}>;
|
|
212
|
+
/**
|
|
213
|
+
* Securely delete state (overwrite with random bytes before removal).
|
|
214
|
+
*/
|
|
215
|
+
delete(namespace: string, key: string): Promise<{
|
|
216
|
+
deleted: boolean;
|
|
217
|
+
key: string;
|
|
218
|
+
namespace: string;
|
|
219
|
+
new_merkle_root: string;
|
|
220
|
+
deleted_at: string;
|
|
221
|
+
}>;
|
|
222
|
+
/**
|
|
223
|
+
* Export all state for a namespace as an encrypted bundle.
|
|
224
|
+
*/
|
|
225
|
+
export(namespace?: string): Promise<{
|
|
226
|
+
bundle: string;
|
|
227
|
+
namespaces: string[];
|
|
228
|
+
total_keys: number;
|
|
229
|
+
bundle_hash: string;
|
|
230
|
+
exported_at: string;
|
|
231
|
+
}>;
|
|
232
|
+
/**
|
|
233
|
+
* Import a previously exported state bundle.
|
|
234
|
+
*/
|
|
235
|
+
import(bundleBase64: string, conflictResolution?: "skip" | "overwrite" | "version"): Promise<{
|
|
236
|
+
imported_keys: number;
|
|
237
|
+
skipped_keys: number;
|
|
238
|
+
conflicts: number;
|
|
239
|
+
namespaces: string[];
|
|
240
|
+
imported_at: string;
|
|
241
|
+
}>;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Sanctuary MCP Server — L2 Operational Isolation: Audit Log
|
|
246
|
+
*
|
|
247
|
+
* Append-only log of all sovereignty-relevant operations.
|
|
248
|
+
* Stored encrypted under L1 sovereignty.
|
|
249
|
+
*
|
|
250
|
+
* Every tool invocation that modifies state, generates proofs,
|
|
251
|
+
* or records reputation produces an audit entry. The human principal
|
|
252
|
+
* can inspect what their agent has done.
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
interface AuditEntry {
|
|
256
|
+
timestamp: string;
|
|
257
|
+
layer: "l1" | "l2" | "l3" | "l4";
|
|
258
|
+
operation: string;
|
|
259
|
+
identity_id: string;
|
|
260
|
+
result: "success" | "failure";
|
|
261
|
+
details?: Record<string, unknown>;
|
|
262
|
+
}
|
|
263
|
+
declare class AuditLog {
|
|
264
|
+
private storage;
|
|
265
|
+
private encryptionKey;
|
|
266
|
+
private entries;
|
|
267
|
+
private counter;
|
|
268
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
269
|
+
/**
|
|
270
|
+
* Append an audit entry.
|
|
271
|
+
*/
|
|
272
|
+
append(layer: AuditEntry["layer"], operation: string, identityId: string, details?: Record<string, unknown>, result?: "success" | "failure"): void;
|
|
273
|
+
private persistEntry;
|
|
274
|
+
/**
|
|
275
|
+
* Query the audit log with filtering.
|
|
276
|
+
*/
|
|
277
|
+
query(options: {
|
|
278
|
+
since?: string;
|
|
279
|
+
layer?: AuditEntry["layer"];
|
|
280
|
+
operation_type?: string;
|
|
281
|
+
limit?: number;
|
|
282
|
+
}): Promise<{
|
|
283
|
+
entries: AuditEntry[];
|
|
284
|
+
total: number;
|
|
285
|
+
}>;
|
|
286
|
+
private loadPersistedEntries;
|
|
287
|
+
/**
|
|
288
|
+
* Get total number of entries.
|
|
289
|
+
*/
|
|
290
|
+
get size(): number;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Sanctuary MCP Server — L3 Selective Disclosure: Commitment Schemes
|
|
295
|
+
*
|
|
296
|
+
* Cryptographic commitments allow an agent to commit to a value
|
|
297
|
+
* without revealing it, then later prove what was committed.
|
|
298
|
+
*
|
|
299
|
+
* This is the MVS approach to selective disclosure — simpler than
|
|
300
|
+
* full ZK proofs but still cryptographically sound. The commitment
|
|
301
|
+
* is SHA-256(value || blinding_factor), which is:
|
|
302
|
+
* - Hiding: the commitment reveals nothing about the value
|
|
303
|
+
* - Binding: the committer cannot change the value after committing
|
|
304
|
+
*
|
|
305
|
+
* Security invariants:
|
|
306
|
+
* - Blinding factors are cryptographically random (32 bytes)
|
|
307
|
+
* - Commitments are stored encrypted under L1 sovereignty
|
|
308
|
+
* - Revealed values are verified via constant-time comparison
|
|
309
|
+
*/
|
|
310
|
+
|
|
311
|
+
/** A cryptographic commitment */
|
|
312
|
+
interface Commitment {
|
|
313
|
+
/** The commitment hash: SHA-256(value || blinding_factor) as base64url */
|
|
314
|
+
commitment: string;
|
|
315
|
+
/** The blinding factor (must be stored securely for later reveal) */
|
|
316
|
+
blinding_factor: string;
|
|
317
|
+
/** When the commitment was created */
|
|
318
|
+
committed_at: string;
|
|
319
|
+
}
|
|
320
|
+
/** Stored commitment metadata (encrypted at rest) */
|
|
321
|
+
interface StoredCommitment {
|
|
322
|
+
commitment: string;
|
|
323
|
+
blinding_factor: string;
|
|
324
|
+
value: string;
|
|
325
|
+
committed_at: string;
|
|
326
|
+
revealed: boolean;
|
|
327
|
+
revealed_at?: string;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Commitment store — manages commitments encrypted under L1 sovereignty.
|
|
331
|
+
*/
|
|
332
|
+
declare class CommitmentStore {
|
|
333
|
+
private storage;
|
|
334
|
+
private encryptionKey;
|
|
335
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
336
|
+
/**
|
|
337
|
+
* Store a commitment (encrypted) for later reference.
|
|
338
|
+
*/
|
|
339
|
+
store(commitment: Commitment, value: string): Promise<string>;
|
|
340
|
+
/**
|
|
341
|
+
* Retrieve a stored commitment by ID.
|
|
342
|
+
*/
|
|
343
|
+
get(id: string): Promise<StoredCommitment | null>;
|
|
344
|
+
/**
|
|
345
|
+
* Mark a commitment as revealed.
|
|
346
|
+
*/
|
|
347
|
+
markRevealed(id: string): Promise<void>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Sanctuary MCP Server — L3 Selective Disclosure: Disclosure Policies
|
|
352
|
+
*
|
|
353
|
+
* Disclosure policies define what an agent will and will not disclose
|
|
354
|
+
* in different interaction contexts. Policies are evaluated against
|
|
355
|
+
* incoming disclosure requests to produce per-field decisions.
|
|
356
|
+
*
|
|
357
|
+
* This is the agent's "privacy preferences" layer — it codifies the
|
|
358
|
+
* human principal's intent about what information can flow where.
|
|
359
|
+
*
|
|
360
|
+
* Security invariants:
|
|
361
|
+
* - Policies are stored encrypted under L1 sovereignty
|
|
362
|
+
* - Default action is always "withhold" unless explicitly overridden
|
|
363
|
+
* - Policy evaluation is deterministic (same request → same decision)
|
|
364
|
+
*/
|
|
365
|
+
|
|
366
|
+
/** A single disclosure rule within a policy */
|
|
367
|
+
interface DisclosureRule {
|
|
368
|
+
/** Interaction context this rule applies to */
|
|
369
|
+
context: string;
|
|
370
|
+
/** Fields/claims the agent MAY disclose */
|
|
371
|
+
disclose: string[];
|
|
372
|
+
/** Fields/claims the agent MUST NOT disclose */
|
|
373
|
+
withhold: string[];
|
|
374
|
+
/** Fields that require proof rather than plain disclosure */
|
|
375
|
+
proof_required: string[];
|
|
376
|
+
}
|
|
377
|
+
/** A complete disclosure policy */
|
|
378
|
+
interface DisclosurePolicy {
|
|
379
|
+
policy_id: string;
|
|
380
|
+
policy_name: string;
|
|
381
|
+
rules: DisclosureRule[];
|
|
382
|
+
default_action: "withhold" | "ask-principal";
|
|
383
|
+
identity_id?: string;
|
|
384
|
+
created_at: string;
|
|
385
|
+
updated_at: string;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Policy store — manages disclosure policies encrypted under L1 sovereignty.
|
|
389
|
+
*/
|
|
390
|
+
declare class PolicyStore {
|
|
391
|
+
private storage;
|
|
392
|
+
private encryptionKey;
|
|
393
|
+
private policies;
|
|
394
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
395
|
+
/**
|
|
396
|
+
* Create and store a new disclosure policy.
|
|
397
|
+
*/
|
|
398
|
+
create(policyName: string, rules: DisclosureRule[], defaultAction: "withhold" | "ask-principal", identityId?: string): Promise<DisclosurePolicy>;
|
|
399
|
+
/**
|
|
400
|
+
* Get a policy by ID.
|
|
401
|
+
*/
|
|
402
|
+
get(policyId: string): Promise<DisclosurePolicy | null>;
|
|
403
|
+
/**
|
|
404
|
+
* List all policies.
|
|
405
|
+
*/
|
|
406
|
+
list(): Promise<DisclosurePolicy[]>;
|
|
407
|
+
/**
|
|
408
|
+
* Load all persisted policies into memory.
|
|
409
|
+
*/
|
|
410
|
+
private loadAll;
|
|
411
|
+
private persist;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Sanctuary MCP Server — Ed25519 Identity Management
|
|
416
|
+
*
|
|
417
|
+
* Sovereign identity based on Ed25519 keypairs.
|
|
418
|
+
* Private keys are always encrypted at rest — never stored in plaintext.
|
|
419
|
+
*
|
|
420
|
+
* Security invariants:
|
|
421
|
+
* - Private keys never appear in any MCP tool response
|
|
422
|
+
* - Private keys are encrypted with identity-specific keys derived from the master key
|
|
423
|
+
* - Key rotation produces a signed rotation event (verifiable chain)
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
/** Public identity information (safe to share) */
|
|
427
|
+
interface PublicIdentity {
|
|
428
|
+
identity_id: string;
|
|
429
|
+
label: string;
|
|
430
|
+
public_key: string;
|
|
431
|
+
did: string;
|
|
432
|
+
created_at: string;
|
|
433
|
+
key_type: "ed25519";
|
|
434
|
+
key_protection: "passphrase" | "hardware-key" | "recovery-key";
|
|
435
|
+
}
|
|
436
|
+
/** Stored identity (private key is encrypted) */
|
|
437
|
+
interface StoredIdentity extends PublicIdentity {
|
|
438
|
+
encrypted_private_key: EncryptedPayload;
|
|
439
|
+
/** Previous public keys (for rotation chain verification) */
|
|
440
|
+
rotation_history: Array<{
|
|
441
|
+
old_public_key: string;
|
|
442
|
+
new_public_key: string;
|
|
443
|
+
rotation_event: string;
|
|
444
|
+
rotated_at: string;
|
|
445
|
+
}>;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Sanctuary MCP Server — L4 Verifiable Reputation: Reputation Store
|
|
450
|
+
*
|
|
451
|
+
* Records interaction outcomes as signed attestations, queries aggregated
|
|
452
|
+
* reputation data, and supports export/import for cross-platform portability.
|
|
453
|
+
*
|
|
454
|
+
* Attestation format is EAS-compatible (Ethereum Attestation Service) to
|
|
455
|
+
* enable future on-chain anchoring without requiring blockchain for MVS.
|
|
456
|
+
*
|
|
457
|
+
* Security invariants:
|
|
458
|
+
* - All attestations are signed by the recording identity
|
|
459
|
+
* - Attestations are stored encrypted under L1 sovereignty
|
|
460
|
+
* - Reputation queries return aggregates, never raw interaction data
|
|
461
|
+
* - Export bundles include all signatures for independent verification
|
|
462
|
+
* - Import verifies every signature before accepting attestations
|
|
463
|
+
*/
|
|
464
|
+
|
|
465
|
+
/** Interaction outcome for recording */
|
|
466
|
+
interface InteractionOutcome {
|
|
467
|
+
type: "transaction" | "negotiation" | "service" | "dispute" | "custom";
|
|
468
|
+
result: "completed" | "partial" | "failed" | "disputed";
|
|
469
|
+
metrics?: Record<string, number>;
|
|
470
|
+
}
|
|
471
|
+
/** A signed attestation of an interaction */
|
|
472
|
+
interface Attestation {
|
|
473
|
+
attestation_id: string;
|
|
474
|
+
schema: "sanctuary-interaction-v1";
|
|
475
|
+
data: {
|
|
476
|
+
interaction_id: string;
|
|
477
|
+
participant_did: string;
|
|
478
|
+
counterparty_did: string;
|
|
479
|
+
outcome_type: string;
|
|
480
|
+
outcome_result: string;
|
|
481
|
+
metrics: Record<string, number>;
|
|
482
|
+
context: string;
|
|
483
|
+
timestamp: string;
|
|
484
|
+
};
|
|
485
|
+
signature: string;
|
|
486
|
+
signer: string;
|
|
487
|
+
}
|
|
488
|
+
/** Stored attestation (encrypted at rest) */
|
|
489
|
+
interface StoredAttestation {
|
|
490
|
+
attestation: Attestation;
|
|
491
|
+
counterparty_attestation?: string;
|
|
492
|
+
counterparty_confirmed: boolean;
|
|
493
|
+
recorded_at: string;
|
|
494
|
+
}
|
|
495
|
+
/** Aggregated metric statistics */
|
|
496
|
+
interface MetricAggregate {
|
|
497
|
+
mean: number;
|
|
498
|
+
median: number;
|
|
499
|
+
min: number;
|
|
500
|
+
max: number;
|
|
501
|
+
count: number;
|
|
502
|
+
}
|
|
503
|
+
/** Reputation query result */
|
|
504
|
+
interface ReputationSummary {
|
|
505
|
+
total_interactions: number;
|
|
506
|
+
completed: number;
|
|
507
|
+
partial: number;
|
|
508
|
+
failed: number;
|
|
509
|
+
disputed: number;
|
|
510
|
+
contexts: string[];
|
|
511
|
+
time_range: {
|
|
512
|
+
start: string;
|
|
513
|
+
end: string;
|
|
514
|
+
};
|
|
515
|
+
aggregate_metrics: Record<string, MetricAggregate>;
|
|
516
|
+
}
|
|
517
|
+
/** Portable reputation bundle */
|
|
518
|
+
interface ReputationBundle {
|
|
519
|
+
version: "SANCTUARY_REP_V1";
|
|
520
|
+
attestations: Attestation[];
|
|
521
|
+
exported_at: string;
|
|
522
|
+
exporter_did: string;
|
|
523
|
+
bundle_signature: string;
|
|
524
|
+
}
|
|
525
|
+
/** Escrow for trust bootstrapping */
|
|
526
|
+
interface Escrow {
|
|
527
|
+
escrow_id: string;
|
|
528
|
+
transaction_terms: string;
|
|
529
|
+
terms_hash: string;
|
|
530
|
+
collateral_amount?: number;
|
|
531
|
+
counterparty_did: string;
|
|
532
|
+
creator_did: string;
|
|
533
|
+
created_at: string;
|
|
534
|
+
expires_at: string;
|
|
535
|
+
status: "pending" | "active" | "released" | "disputed" | "expired";
|
|
536
|
+
}
|
|
537
|
+
/** Principal guarantee for a new agent */
|
|
538
|
+
interface Guarantee {
|
|
539
|
+
guarantee_id: string;
|
|
540
|
+
principal_did: string;
|
|
541
|
+
agent_did: string;
|
|
542
|
+
scope: string;
|
|
543
|
+
max_liability?: number;
|
|
544
|
+
valid_until: string;
|
|
545
|
+
certificate: string;
|
|
546
|
+
created_at: string;
|
|
547
|
+
}
|
|
548
|
+
declare class ReputationStore {
|
|
549
|
+
private storage;
|
|
550
|
+
private encryptionKey;
|
|
551
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
552
|
+
/**
|
|
553
|
+
* Record an interaction outcome as a signed attestation.
|
|
554
|
+
*/
|
|
555
|
+
record(interactionId: string, counterpartyDid: string, outcome: InteractionOutcome, context: string, identity: StoredIdentity, identityEncryptionKey: Uint8Array, counterpartyAttestation?: string): Promise<StoredAttestation>;
|
|
556
|
+
/**
|
|
557
|
+
* Query reputation data with filtering.
|
|
558
|
+
* Returns aggregates only — not raw interaction data.
|
|
559
|
+
*/
|
|
560
|
+
query(options: {
|
|
561
|
+
context?: string;
|
|
562
|
+
time_range?: {
|
|
563
|
+
start: string;
|
|
564
|
+
end: string;
|
|
565
|
+
};
|
|
566
|
+
metrics?: string[];
|
|
567
|
+
counterparty_did?: string;
|
|
568
|
+
}): Promise<ReputationSummary>;
|
|
569
|
+
/**
|
|
570
|
+
* Export attestations as a portable reputation bundle.
|
|
571
|
+
*/
|
|
572
|
+
exportBundle(identity: StoredIdentity, identityEncryptionKey: Uint8Array, context?: string): Promise<ReputationBundle>;
|
|
573
|
+
/**
|
|
574
|
+
* Import attestations from a reputation bundle.
|
|
575
|
+
* Verifies signatures if requested (default: true).
|
|
576
|
+
*
|
|
577
|
+
* @param publicKeys - Map of DID → public key bytes for signature verification
|
|
578
|
+
*/
|
|
579
|
+
importBundle(bundle: ReputationBundle, verifySignatures: boolean, publicKeys: Map<string, Uint8Array>): Promise<{
|
|
580
|
+
imported: number;
|
|
581
|
+
invalid: number;
|
|
582
|
+
contexts: string[];
|
|
583
|
+
}>;
|
|
584
|
+
/**
|
|
585
|
+
* Create an escrow for trust bootstrapping.
|
|
586
|
+
*/
|
|
587
|
+
createEscrow(transactionTerms: string, counterpartyDid: string, timeoutSeconds: number, creatorDid: string, collateralAmount?: number): Promise<Escrow>;
|
|
588
|
+
/**
|
|
589
|
+
* Get an escrow by ID.
|
|
590
|
+
*/
|
|
591
|
+
getEscrow(escrowId: string): Promise<Escrow | null>;
|
|
592
|
+
/**
|
|
593
|
+
* Create a principal's guarantee for a new agent.
|
|
594
|
+
*/
|
|
595
|
+
createGuarantee(principalIdentity: StoredIdentity, agentDid: string, scope: string, durationSeconds: number, identityEncryptionKey: Uint8Array, maxLiability?: number): Promise<Guarantee>;
|
|
596
|
+
private loadAll;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Sanctuary MCP Server — In-Memory Storage Backend
|
|
601
|
+
*
|
|
602
|
+
* Used for testing. Implements the same interface as filesystem storage
|
|
603
|
+
* but stores everything in memory. Data does not persist across restarts.
|
|
604
|
+
*/
|
|
605
|
+
|
|
606
|
+
declare class MemoryStorage implements StorageBackend {
|
|
607
|
+
private store;
|
|
608
|
+
private storageKey;
|
|
609
|
+
write(namespace: string, key: string, data: Uint8Array): Promise<void>;
|
|
610
|
+
read(namespace: string, key: string): Promise<Uint8Array | null>;
|
|
611
|
+
delete(namespace: string, key: string, _secureOverwrite?: boolean): Promise<boolean>;
|
|
612
|
+
list(namespace: string, prefix?: string): Promise<StorageEntryMeta[]>;
|
|
613
|
+
exists(namespace: string, key: string): Promise<boolean>;
|
|
614
|
+
totalSize(): Promise<number>;
|
|
615
|
+
/** Clear all stored data (useful in tests) */
|
|
616
|
+
clear(): void;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Sanctuary MCP Server — Filesystem Storage Backend
|
|
621
|
+
*
|
|
622
|
+
* Default storage backend using the local filesystem.
|
|
623
|
+
* Files are stored as: {basePath}/{namespace}/{key}.enc
|
|
624
|
+
*
|
|
625
|
+
* Security invariants:
|
|
626
|
+
* - Secure deletion overwrites file content with random bytes before unlinking
|
|
627
|
+
* - Directory creation uses restrictive permissions (0o700)
|
|
628
|
+
* - File creation uses restrictive permissions (0o600)
|
|
629
|
+
*/
|
|
630
|
+
|
|
631
|
+
declare class FilesystemStorage implements StorageBackend {
|
|
632
|
+
private basePath;
|
|
633
|
+
constructor(basePath: string);
|
|
634
|
+
private entryPath;
|
|
635
|
+
private namespacePath;
|
|
636
|
+
write(namespace: string, key: string, data: Uint8Array): Promise<void>;
|
|
637
|
+
read(namespace: string, key: string): Promise<Uint8Array | null>;
|
|
638
|
+
delete(namespace: string, key: string, secureOverwrite?: boolean): Promise<boolean>;
|
|
639
|
+
list(namespace: string, prefix?: string): Promise<StorageEntryMeta[]>;
|
|
640
|
+
exists(namespace: string, key: string): Promise<boolean>;
|
|
641
|
+
totalSize(): Promise<number>;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Sanctuary MCP Server — Principal Policy Types
|
|
646
|
+
*
|
|
647
|
+
* Type definitions for the Principal Policy system.
|
|
648
|
+
* The Principal Policy is the human-controlled, agent-immutable
|
|
649
|
+
* configuration that gates operations through approval tiers.
|
|
650
|
+
*/
|
|
651
|
+
/** Tier 2 anomaly action: what to do when an anomaly is detected */
|
|
652
|
+
type AnomalyAction = "approve" | "log" | "allow";
|
|
653
|
+
/** Tier 2 anomaly detection configuration */
|
|
654
|
+
interface Tier2Config {
|
|
655
|
+
/** Action when agent accesses a namespace it hasn't used before */
|
|
656
|
+
new_namespace_access: AnomalyAction;
|
|
657
|
+
/** Action when agent interacts with an unknown counterparty DID */
|
|
658
|
+
new_counterparty: AnomalyAction;
|
|
659
|
+
/** Tool call frequency multiplier that triggers anomaly */
|
|
660
|
+
frequency_spike_multiplier: number;
|
|
661
|
+
/** Maximum signing operations per minute before triggering */
|
|
662
|
+
max_signs_per_minute: number;
|
|
663
|
+
/** Reading more than N keys in a namespace within 60 seconds */
|
|
664
|
+
bulk_read_threshold: number;
|
|
665
|
+
/** Policy for first session when no baseline exists */
|
|
666
|
+
first_session_policy: AnomalyAction;
|
|
667
|
+
}
|
|
668
|
+
/** Approval channel configuration */
|
|
669
|
+
interface ApprovalChannelConfig {
|
|
670
|
+
type: "stderr" | "webhook" | "callback";
|
|
671
|
+
timeout_seconds: number;
|
|
672
|
+
auto_deny: boolean;
|
|
673
|
+
webhook_url?: string;
|
|
674
|
+
webhook_secret?: string;
|
|
675
|
+
}
|
|
676
|
+
/** Complete Principal Policy */
|
|
677
|
+
interface PrincipalPolicy {
|
|
678
|
+
version: number;
|
|
679
|
+
/** Operations that always require human approval */
|
|
680
|
+
tier1_always_approve: string[];
|
|
681
|
+
/** Behavioral anomaly detection configuration */
|
|
682
|
+
tier2_anomaly: Tier2Config;
|
|
683
|
+
/** Operations that never require approval (audit only) */
|
|
684
|
+
tier3_always_allow: string[];
|
|
685
|
+
/** How approval requests reach the human */
|
|
686
|
+
approval_channel: ApprovalChannelConfig;
|
|
687
|
+
}
|
|
688
|
+
/** Approval request sent to the human */
|
|
689
|
+
interface ApprovalRequest {
|
|
690
|
+
operation: string;
|
|
691
|
+
tier: 1 | 2;
|
|
692
|
+
reason: string;
|
|
693
|
+
context: Record<string, unknown>;
|
|
694
|
+
timestamp: string;
|
|
695
|
+
}
|
|
696
|
+
/** Approval response from the human */
|
|
697
|
+
interface ApprovalResponse {
|
|
698
|
+
decision: "approve" | "deny";
|
|
699
|
+
decided_at: string;
|
|
700
|
+
decided_by: "human" | "timeout" | "auto";
|
|
701
|
+
}
|
|
702
|
+
/** Result of the approval gate evaluation */
|
|
703
|
+
interface GateResult {
|
|
704
|
+
allowed: boolean;
|
|
705
|
+
tier: 1 | 2 | 3;
|
|
706
|
+
reason: string;
|
|
707
|
+
approval_required: boolean;
|
|
708
|
+
approval_response?: ApprovalResponse;
|
|
709
|
+
}
|
|
710
|
+
/** Behavioral baseline for anomaly detection */
|
|
711
|
+
interface SessionProfile {
|
|
712
|
+
/** Namespaces accessed (read or write) */
|
|
713
|
+
known_namespaces: string[];
|
|
714
|
+
/** Counterparty DIDs seen in reputation operations */
|
|
715
|
+
known_counterparties: string[];
|
|
716
|
+
/** Tool call counts per tool name (lifetime in session) */
|
|
717
|
+
tool_call_counts: Record<string, number>;
|
|
718
|
+
/** Whether this is the first session (no prior baseline) */
|
|
719
|
+
is_first_session: boolean;
|
|
720
|
+
/** Session start time */
|
|
721
|
+
started_at: string;
|
|
722
|
+
/** When the baseline was last saved */
|
|
723
|
+
saved_at?: string;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Sanctuary MCP Server — Approval Channel
|
|
728
|
+
*
|
|
729
|
+
* Out-of-band communication with the human principal for operation approval.
|
|
730
|
+
* The default channel uses stderr (outside MCP's stdin/stdout protocol),
|
|
731
|
+
* ensuring the agent cannot intercept or forge approval responses.
|
|
732
|
+
*
|
|
733
|
+
* Security invariant:
|
|
734
|
+
* - Approval prompts go through a channel the agent cannot access.
|
|
735
|
+
* - Timeouts result in denial by default (fail closed).
|
|
736
|
+
*/
|
|
737
|
+
|
|
738
|
+
/** Abstract approval channel interface */
|
|
739
|
+
interface ApprovalChannel {
|
|
740
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Stderr approval channel — writes prompts to stderr, waits for response.
|
|
744
|
+
*
|
|
745
|
+
* In the MCP stdio model:
|
|
746
|
+
* - stdin/stdout carry the MCP protocol (JSON-RPC)
|
|
747
|
+
* - stderr is available for out-of-band human communication
|
|
748
|
+
*
|
|
749
|
+
* Since many harnesses do not support interactive stdin during tool calls,
|
|
750
|
+
* this channel uses a timeout-based model: the prompt is displayed, and
|
|
751
|
+
* if no response is received within the timeout, the default action applies.
|
|
752
|
+
*
|
|
753
|
+
* For MVS, the channel auto-resolves based on the auto_deny setting.
|
|
754
|
+
* Interactive stdin reading is deferred to a future version with harness support.
|
|
755
|
+
*/
|
|
756
|
+
declare class StderrApprovalChannel implements ApprovalChannel {
|
|
757
|
+
private config;
|
|
758
|
+
constructor(config: ApprovalChannelConfig);
|
|
759
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
760
|
+
private formatPrompt;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Programmatic approval channel — for testing and API integration.
|
|
764
|
+
*/
|
|
765
|
+
declare class CallbackApprovalChannel implements ApprovalChannel {
|
|
766
|
+
private callback;
|
|
767
|
+
constructor(callback: (request: ApprovalRequest) => Promise<ApprovalResponse>);
|
|
768
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Auto-approve channel — for testing. Approves everything.
|
|
772
|
+
*/
|
|
773
|
+
declare class AutoApproveChannel implements ApprovalChannel {
|
|
774
|
+
requestApproval(_request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Sanctuary MCP Server — Behavioral Baseline Tracker
|
|
779
|
+
*
|
|
780
|
+
* Tracks the agent's behavioral profile during a session and persists
|
|
781
|
+
* it for cross-session anomaly detection. The baseline defines "normal"
|
|
782
|
+
* so that deviations can trigger Tier 2 approval.
|
|
783
|
+
*
|
|
784
|
+
* Security invariants:
|
|
785
|
+
* - Baseline is stored encrypted under L1 sovereignty
|
|
786
|
+
* - Baseline changes are audit-logged
|
|
787
|
+
* - Baseline is integrity-verified via L1 Merkle tree
|
|
788
|
+
* - No MCP tool can directly modify the baseline
|
|
789
|
+
*/
|
|
790
|
+
|
|
791
|
+
declare class BaselineTracker {
|
|
792
|
+
private storage;
|
|
793
|
+
private encryptionKey;
|
|
794
|
+
private profile;
|
|
795
|
+
/** Sliding window: timestamps of tool calls per tool name (last 60s) */
|
|
796
|
+
private callWindows;
|
|
797
|
+
/** Sliding window: read counts per namespace (last 60s) */
|
|
798
|
+
private readWindows;
|
|
799
|
+
/** Sliding window: sign call timestamps (last 60s) */
|
|
800
|
+
private signWindow;
|
|
801
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
802
|
+
/**
|
|
803
|
+
* Load the previous session's baseline from storage.
|
|
804
|
+
* If none exists, this is a first session.
|
|
805
|
+
*/
|
|
806
|
+
load(): Promise<void>;
|
|
807
|
+
/**
|
|
808
|
+
* Save the current baseline to storage (encrypted).
|
|
809
|
+
* Called at session end or periodically.
|
|
810
|
+
*/
|
|
811
|
+
save(): Promise<void>;
|
|
812
|
+
/**
|
|
813
|
+
* Record a tool call for baseline tracking.
|
|
814
|
+
* Returns anomaly information if applicable.
|
|
815
|
+
*/
|
|
816
|
+
recordToolCall(toolName: string): void;
|
|
817
|
+
/**
|
|
818
|
+
* Record a namespace access.
|
|
819
|
+
* @returns true if this is a new namespace (not in baseline)
|
|
820
|
+
*/
|
|
821
|
+
recordNamespaceAccess(namespace: string): boolean;
|
|
822
|
+
/**
|
|
823
|
+
* Record a namespace read for bulk-read detection.
|
|
824
|
+
* @returns the number of reads in the current 60-second window
|
|
825
|
+
*/
|
|
826
|
+
recordNamespaceRead(namespace: string): number;
|
|
827
|
+
/**
|
|
828
|
+
* Record a counterparty DID interaction.
|
|
829
|
+
* @returns true if this is a new counterparty (not in baseline)
|
|
830
|
+
*/
|
|
831
|
+
recordCounterparty(did: string): boolean;
|
|
832
|
+
/**
|
|
833
|
+
* Record a signing operation.
|
|
834
|
+
* @returns the number of signs in the current 60-second window
|
|
835
|
+
*/
|
|
836
|
+
recordSign(): number;
|
|
837
|
+
/**
|
|
838
|
+
* Get the current call rate for a tool (calls per minute).
|
|
839
|
+
*/
|
|
840
|
+
getCallRate(toolName: string): number;
|
|
841
|
+
/**
|
|
842
|
+
* Get the average call rate across all tools in the baseline.
|
|
843
|
+
*/
|
|
844
|
+
getAverageCallRate(): number;
|
|
845
|
+
/** Whether this is the first session */
|
|
846
|
+
get isFirstSession(): boolean;
|
|
847
|
+
/** Get a read-only view of the current profile */
|
|
848
|
+
getProfile(): SessionProfile;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Sanctuary MCP Server — Approval Gate
|
|
853
|
+
*
|
|
854
|
+
* The three-tier approval gate sits between the MCP router and tool handlers.
|
|
855
|
+
* Every tool call passes through the gate before execution.
|
|
856
|
+
*
|
|
857
|
+
* Evaluation order:
|
|
858
|
+
* 1. Tier 1: Is this operation in the always-approve list? → Request approval.
|
|
859
|
+
* 2. Tier 2: Does this call represent a behavioral anomaly? → Request approval.
|
|
860
|
+
* 3. Tier 3 / default: Allow with audit logging.
|
|
861
|
+
*
|
|
862
|
+
* Security invariants:
|
|
863
|
+
* - The gate cannot be bypassed — it wraps every tool handler.
|
|
864
|
+
* - Denial responses do not reveal policy details to the agent.
|
|
865
|
+
* - All gate decisions (approve, deny, allow) are audit-logged.
|
|
866
|
+
*/
|
|
867
|
+
|
|
868
|
+
declare class ApprovalGate {
|
|
869
|
+
private policy;
|
|
870
|
+
private baseline;
|
|
871
|
+
private channel;
|
|
872
|
+
private auditLog;
|
|
873
|
+
constructor(policy: PrincipalPolicy, baseline: BaselineTracker, channel: ApprovalChannel, auditLog: AuditLog);
|
|
874
|
+
/**
|
|
875
|
+
* Evaluate a tool call against the Principal Policy.
|
|
876
|
+
*
|
|
877
|
+
* @param toolName - Full MCP tool name (e.g., "sanctuary/state_export")
|
|
878
|
+
* @param args - Tool call arguments (for context extraction)
|
|
879
|
+
* @returns GateResult indicating whether the call is allowed
|
|
880
|
+
*/
|
|
881
|
+
evaluate(toolName: string, args: Record<string, unknown>): Promise<GateResult>;
|
|
882
|
+
/**
|
|
883
|
+
* Detect Tier 2 behavioral anomalies.
|
|
884
|
+
*/
|
|
885
|
+
private detectAnomaly;
|
|
886
|
+
/**
|
|
887
|
+
* Request approval from the human principal.
|
|
888
|
+
*/
|
|
889
|
+
private requestApproval;
|
|
890
|
+
/**
|
|
891
|
+
* Summarize tool arguments for the approval prompt.
|
|
892
|
+
* Strips potentially large values to keep the prompt readable.
|
|
893
|
+
*/
|
|
894
|
+
private summarizeArgs;
|
|
895
|
+
/** Get the baseline tracker for saving at session end */
|
|
896
|
+
getBaseline(): BaselineTracker;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Sanctuary MCP Server — Principal Policy Loader
|
|
901
|
+
*
|
|
902
|
+
* Loads the Principal Policy from a YAML file at server startup.
|
|
903
|
+
* The policy is immutable at runtime — no MCP tool can modify it.
|
|
904
|
+
*
|
|
905
|
+
* Security invariant:
|
|
906
|
+
* - The policy is loaded ONCE at startup and frozen.
|
|
907
|
+
* - No code path exists to modify the policy during a session.
|
|
908
|
+
* - If no policy file exists, a sensible default is generated and saved.
|
|
909
|
+
*/
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Load the Principal Policy from disk.
|
|
913
|
+
* If no policy file exists, generate the default and save it.
|
|
914
|
+
* The returned policy is frozen — immutable at runtime.
|
|
915
|
+
*/
|
|
916
|
+
declare function loadPrincipalPolicy(storagePath: string): Promise<PrincipalPolicy>;
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Sanctuary MCP Server — L1 Cognitive Sovereignty: Tool Definitions
|
|
920
|
+
*
|
|
921
|
+
* MCP tool wrappers for StateStore and IdentityRoot operations.
|
|
922
|
+
* These tools are the public API that agents interact with.
|
|
923
|
+
*/
|
|
924
|
+
|
|
925
|
+
/** Manages all identities — provides storage and retrieval */
|
|
926
|
+
declare class IdentityManager {
|
|
927
|
+
private storage;
|
|
928
|
+
private masterKey;
|
|
929
|
+
private identities;
|
|
930
|
+
private primaryIdentityId;
|
|
931
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
932
|
+
private get encryptionKey();
|
|
933
|
+
/** Load identities from storage on startup */
|
|
934
|
+
load(): Promise<void>;
|
|
935
|
+
/** Save an identity to storage */
|
|
936
|
+
save(identity: StoredIdentity): Promise<void>;
|
|
937
|
+
get(id: string): StoredIdentity | undefined;
|
|
938
|
+
getDefault(): StoredIdentity | undefined;
|
|
939
|
+
list(): PublicIdentity[];
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* Sanctuary MCP Server — Sovereignty Health Report (SHR) Types
|
|
944
|
+
*
|
|
945
|
+
* Machine-readable, signed, versioned sovereignty capability advertisement.
|
|
946
|
+
* An agent presents its SHR to counterparties to prove its sovereignty posture.
|
|
947
|
+
* The SHR is signed by one of the instance's Ed25519 identities and can be
|
|
948
|
+
* independently verified by any party without trusting the presenter.
|
|
949
|
+
*
|
|
950
|
+
* SHR version: 1.0
|
|
951
|
+
*/
|
|
952
|
+
type LayerStatus = "active" | "degraded" | "inactive";
|
|
953
|
+
type DegradationSeverity = "info" | "warning" | "critical";
|
|
954
|
+
type DegradationCode = "NO_TEE" | "PROCESS_ISOLATION_ONLY" | "COMMITMENT_ONLY" | "NO_ZK_PROOFS" | "SELF_REPORTED_ATTESTATION" | "NO_SELECTIVE_DISCLOSURE" | "BASIC_SYBIL_ONLY";
|
|
955
|
+
interface SHRLayerL1 {
|
|
956
|
+
status: LayerStatus;
|
|
957
|
+
encryption: string;
|
|
958
|
+
key_custody: "self" | "delegated" | "platform";
|
|
959
|
+
integrity: string;
|
|
960
|
+
identity_type: string;
|
|
961
|
+
state_portable: boolean;
|
|
962
|
+
}
|
|
963
|
+
interface SHRLayerL2 {
|
|
964
|
+
status: LayerStatus;
|
|
965
|
+
isolation_type: string;
|
|
966
|
+
attestation_available: boolean;
|
|
967
|
+
}
|
|
968
|
+
interface SHRLayerL3 {
|
|
969
|
+
status: LayerStatus;
|
|
970
|
+
proof_system: string;
|
|
971
|
+
selective_disclosure: boolean;
|
|
972
|
+
}
|
|
973
|
+
interface SHRLayerL4 {
|
|
974
|
+
status: LayerStatus;
|
|
975
|
+
reputation_mode: string;
|
|
976
|
+
attestation_format: string;
|
|
977
|
+
reputation_portable: boolean;
|
|
978
|
+
}
|
|
979
|
+
interface SHRDegradation {
|
|
980
|
+
layer: "l1" | "l2" | "l3" | "l4";
|
|
981
|
+
code: DegradationCode;
|
|
982
|
+
severity: DegradationSeverity;
|
|
983
|
+
description: string;
|
|
984
|
+
mitigation?: string;
|
|
985
|
+
}
|
|
986
|
+
interface SHRCapabilities {
|
|
987
|
+
handshake: boolean;
|
|
988
|
+
shr_exchange: boolean;
|
|
989
|
+
reputation_verify: boolean;
|
|
990
|
+
encrypted_channel: boolean;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* The SHR body — the content that gets signed.
|
|
994
|
+
* Canonical form: JSON with sorted keys, no whitespace.
|
|
995
|
+
*/
|
|
996
|
+
interface SHRBody {
|
|
997
|
+
shr_version: "1.0";
|
|
998
|
+
instance_id: string;
|
|
999
|
+
generated_at: string;
|
|
1000
|
+
expires_at: string;
|
|
1001
|
+
layers: {
|
|
1002
|
+
l1: SHRLayerL1;
|
|
1003
|
+
l2: SHRLayerL2;
|
|
1004
|
+
l3: SHRLayerL3;
|
|
1005
|
+
l4: SHRLayerL4;
|
|
1006
|
+
};
|
|
1007
|
+
capabilities: SHRCapabilities;
|
|
1008
|
+
degradations: SHRDegradation[];
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* The complete signed SHR — body + signature envelope.
|
|
1012
|
+
*/
|
|
1013
|
+
interface SignedSHR {
|
|
1014
|
+
body: SHRBody;
|
|
1015
|
+
signed_by: string;
|
|
1016
|
+
signature: string;
|
|
1017
|
+
}
|
|
1018
|
+
interface SHRVerificationResult {
|
|
1019
|
+
valid: boolean;
|
|
1020
|
+
errors: string[];
|
|
1021
|
+
warnings: string[];
|
|
1022
|
+
sovereignty_level: "full" | "degraded" | "minimal";
|
|
1023
|
+
counterparty_id: string;
|
|
1024
|
+
expires_at: string;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Sanctuary MCP Server — SHR Generator
|
|
1029
|
+
*
|
|
1030
|
+
* Generates a Sovereignty Health Report from current server state,
|
|
1031
|
+
* signs it with a specified identity, and returns the complete signed SHR.
|
|
1032
|
+
*/
|
|
1033
|
+
|
|
1034
|
+
interface SHRGeneratorOptions {
|
|
1035
|
+
config: SanctuaryConfig;
|
|
1036
|
+
identityManager: IdentityManager;
|
|
1037
|
+
masterKey: Uint8Array;
|
|
1038
|
+
/** Override validity window (milliseconds). Default: 1 hour. */
|
|
1039
|
+
validityMs?: number;
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Generate and sign a Sovereignty Health Report.
|
|
1043
|
+
*
|
|
1044
|
+
* @param identityId - Which identity to sign with (defaults to primary)
|
|
1045
|
+
* @param opts - Generator dependencies
|
|
1046
|
+
* @returns The signed SHR, or an error string
|
|
1047
|
+
*/
|
|
1048
|
+
declare function generateSHR(identityId: string | undefined, opts: SHRGeneratorOptions): SignedSHR | string;
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Sanctuary MCP Server — SHR Verifier
|
|
1052
|
+
*
|
|
1053
|
+
* Verifies a counterparty's Sovereignty Health Report:
|
|
1054
|
+
* - Signature validity (Ed25519 over canonical body)
|
|
1055
|
+
* - Temporal validity (not expired)
|
|
1056
|
+
* - Schema completeness
|
|
1057
|
+
* - Sovereignty level assessment
|
|
1058
|
+
*/
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Verify a signed SHR.
|
|
1062
|
+
*
|
|
1063
|
+
* @param shr - The signed SHR to verify
|
|
1064
|
+
* @param now - Optional override for current time (for testing)
|
|
1065
|
+
* @returns Verification result with validity, errors, warnings, and sovereignty assessment
|
|
1066
|
+
*/
|
|
1067
|
+
declare function verifySHR(shr: SignedSHR, now?: Date): SHRVerificationResult;
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Sanctuary MCP Server — Sovereignty Handshake Types
|
|
1071
|
+
*
|
|
1072
|
+
* The sovereignty handshake is a mutual verification protocol between
|
|
1073
|
+
* two Sanctuary instances. Each party presents its SHR and proves
|
|
1074
|
+
* liveness via nonce challenge-response.
|
|
1075
|
+
*
|
|
1076
|
+
* Protocol:
|
|
1077
|
+
* A → B: HandshakeChallenge (A's SHR + nonce)
|
|
1078
|
+
* B → A: HandshakeResponse (B's SHR + B's nonce + signature over A's nonce)
|
|
1079
|
+
* A → B: HandshakeCompletion (signature over B's nonce)
|
|
1080
|
+
* Result: Both hold a HandshakeResult with verified counterparty status
|
|
1081
|
+
*/
|
|
1082
|
+
|
|
1083
|
+
/** Trust tier derived from sovereignty handshake */
|
|
1084
|
+
type TrustTier = "verified-sovereign" | "verified-degraded" | "unverified";
|
|
1085
|
+
/** Sovereignty level from SHR assessment */
|
|
1086
|
+
type SovereigntyLevel = "full" | "degraded" | "minimal" | "unverified";
|
|
1087
|
+
/**
|
|
1088
|
+
* Step 1: Initiator sends challenge
|
|
1089
|
+
*/
|
|
1090
|
+
interface HandshakeChallenge {
|
|
1091
|
+
protocol_version: "1.0";
|
|
1092
|
+
shr: SignedSHR;
|
|
1093
|
+
nonce: string;
|
|
1094
|
+
initiated_at: string;
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Step 2: Responder sends response
|
|
1098
|
+
*/
|
|
1099
|
+
interface HandshakeResponse {
|
|
1100
|
+
protocol_version: "1.0";
|
|
1101
|
+
shr: SignedSHR;
|
|
1102
|
+
responder_nonce: string;
|
|
1103
|
+
initiator_nonce_signature: string;
|
|
1104
|
+
responded_at: string;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Step 3: Initiator sends completion
|
|
1108
|
+
*/
|
|
1109
|
+
interface HandshakeCompletion {
|
|
1110
|
+
protocol_version: "1.0";
|
|
1111
|
+
responder_nonce_signature: string;
|
|
1112
|
+
completed_at: string;
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Final result: both parties hold this after a successful handshake
|
|
1116
|
+
*/
|
|
1117
|
+
interface HandshakeResult {
|
|
1118
|
+
counterparty_id: string;
|
|
1119
|
+
counterparty_shr: SignedSHR;
|
|
1120
|
+
verified: boolean;
|
|
1121
|
+
sovereignty_level: SovereigntyLevel;
|
|
1122
|
+
trust_tier: TrustTier;
|
|
1123
|
+
completed_at: string;
|
|
1124
|
+
expires_at: string;
|
|
1125
|
+
errors: string[];
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* In-progress handshake state (stored on initiator side)
|
|
1129
|
+
*/
|
|
1130
|
+
interface HandshakeSession {
|
|
1131
|
+
session_id: string;
|
|
1132
|
+
role: "initiator" | "responder";
|
|
1133
|
+
state: "initiated" | "responded" | "completed" | "failed";
|
|
1134
|
+
our_nonce: string;
|
|
1135
|
+
their_nonce?: string;
|
|
1136
|
+
our_shr: SignedSHR;
|
|
1137
|
+
their_shr?: SignedSHR;
|
|
1138
|
+
initiated_at: string;
|
|
1139
|
+
result?: HandshakeResult;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Sanctuary MCP Server — Sovereignty Handshake Protocol
|
|
1144
|
+
*
|
|
1145
|
+
* Core handshake logic: initiate, respond, complete.
|
|
1146
|
+
* Nonce-based challenge-response prevents replay attacks.
|
|
1147
|
+
* SHR signatures are verified at each step.
|
|
1148
|
+
*/
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* Step 1: Initiate a handshake.
|
|
1152
|
+
* Generates a challenge containing our SHR and a nonce.
|
|
1153
|
+
*/
|
|
1154
|
+
declare function initiateHandshake(ourSHR: SignedSHR): {
|
|
1155
|
+
challenge: HandshakeChallenge;
|
|
1156
|
+
session: HandshakeSession;
|
|
1157
|
+
};
|
|
1158
|
+
/**
|
|
1159
|
+
* Step 2: Respond to a handshake challenge.
|
|
1160
|
+
* Verifies the initiator's SHR, signs their nonce, generates our nonce.
|
|
1161
|
+
*/
|
|
1162
|
+
declare function respondToHandshake(challenge: HandshakeChallenge, ourSHR: SignedSHR, identityManager: IdentityManager, masterKey: Uint8Array, identityId?: string): {
|
|
1163
|
+
response: HandshakeResponse;
|
|
1164
|
+
session: HandshakeSession;
|
|
1165
|
+
} | {
|
|
1166
|
+
error: string;
|
|
1167
|
+
};
|
|
1168
|
+
/**
|
|
1169
|
+
* Step 3: Complete the handshake (initiator side).
|
|
1170
|
+
* Verifies the responder's SHR and nonce signature, signs responder's nonce.
|
|
1171
|
+
*/
|
|
1172
|
+
declare function completeHandshake(response: HandshakeResponse, session: HandshakeSession, identityManager: IdentityManager, masterKey: Uint8Array, identityId?: string): {
|
|
1173
|
+
completion: HandshakeCompletion;
|
|
1174
|
+
result: HandshakeResult;
|
|
1175
|
+
} | {
|
|
1176
|
+
error: string;
|
|
1177
|
+
};
|
|
1178
|
+
/**
|
|
1179
|
+
* Step 4: Verify completion (responder side).
|
|
1180
|
+
* Verifies the initiator signed our nonce correctly.
|
|
1181
|
+
*/
|
|
1182
|
+
declare function verifyCompletion(completion: HandshakeCompletion, session: HandshakeSession): HandshakeResult;
|
|
1183
|
+
|
|
1184
|
+
/**
|
|
1185
|
+
* Sanctuary MCP Server — Main Entry Point
|
|
1186
|
+
*
|
|
1187
|
+
* Initializes and exports the Sanctuary MCP server.
|
|
1188
|
+
* Wires together: config → storage → crypto core → L1-L4 tools → MCP server
|
|
1189
|
+
*/
|
|
1190
|
+
|
|
1191
|
+
interface SanctuaryServer {
|
|
1192
|
+
server: Server;
|
|
1193
|
+
config: SanctuaryConfig;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Initialize the Sanctuary MCP Server.
|
|
1197
|
+
*
|
|
1198
|
+
* @param options - Configuration overrides and initialization options
|
|
1199
|
+
* @returns The configured MCP server, ready to connect to a transport
|
|
1200
|
+
*/
|
|
1201
|
+
declare function createSanctuaryServer(options?: {
|
|
1202
|
+
configPath?: string;
|
|
1203
|
+
passphrase?: string;
|
|
1204
|
+
storage?: StorageBackend;
|
|
1205
|
+
}): Promise<SanctuaryServer>;
|
|
1206
|
+
|
|
1207
|
+
export { ApprovalGate, AuditLog, AutoApproveChannel, BaselineTracker, CallbackApprovalChannel, CommitmentStore, FilesystemStorage, type GateResult, type HandshakeChallenge, type HandshakeCompletion, type HandshakeResponse, type HandshakeResult, MemoryStorage, PolicyStore, type PrincipalPolicy, ReputationStore, type SHRBody, type SHRVerificationResult, type SanctuaryConfig, type SanctuaryServer, type SignedSHR, StateStore, StderrApprovalChannel, completeHandshake, createSanctuaryServer, generateSHR, initiateHandshake, loadConfig, loadPrincipalPolicy, respondToHandshake, verifyCompletion, verifySHR };
|