@cello-protocol/client 0.0.2

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.
Files changed (53) hide show
  1. package/dist/agent-hash-queue.d.ts +206 -0
  2. package/dist/agent-hash-queue.d.ts.map +1 -0
  3. package/dist/agent-hash-queue.js +380 -0
  4. package/dist/agent-hash-queue.js.map +1 -0
  5. package/dist/backup-key-derivation.d.ts +37 -0
  6. package/dist/backup-key-derivation.d.ts.map +1 -0
  7. package/dist/backup-key-derivation.js +48 -0
  8. package/dist/backup-key-derivation.js.map +1 -0
  9. package/dist/client-backup.d.ts +144 -0
  10. package/dist/client-backup.d.ts.map +1 -0
  11. package/dist/client-backup.js +273 -0
  12. package/dist/client-backup.js.map +1 -0
  13. package/dist/client.d.ts +249 -0
  14. package/dist/client.d.ts.map +1 -0
  15. package/dist/client.js +4664 -0
  16. package/dist/client.js.map +1 -0
  17. package/dist/connection-policy.d.ts +163 -0
  18. package/dist/connection-policy.d.ts.map +1 -0
  19. package/dist/connection-policy.js +248 -0
  20. package/dist/connection-policy.js.map +1 -0
  21. package/dist/db-key-derivation.d.ts +26 -0
  22. package/dist/db-key-derivation.d.ts.map +1 -0
  23. package/dist/db-key-derivation.js +37 -0
  24. package/dist/db-key-derivation.js.map +1 -0
  25. package/dist/encrypted-file-signing-key-provider.d.ts +92 -0
  26. package/dist/encrypted-file-signing-key-provider.d.ts.map +1 -0
  27. package/dist/encrypted-file-signing-key-provider.js +251 -0
  28. package/dist/encrypted-file-signing-key-provider.js.map +1 -0
  29. package/dist/index.d.ts +13 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +8 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/mcp-server.d.ts +270 -0
  34. package/dist/mcp-server.d.ts.map +1 -0
  35. package/dist/mcp-server.js +1155 -0
  36. package/dist/mcp-server.js.map +1 -0
  37. package/dist/network-directory-node.d.ts +85 -0
  38. package/dist/network-directory-node.d.ts.map +1 -0
  39. package/dist/network-directory-node.js +584 -0
  40. package/dist/network-directory-node.js.map +1 -0
  41. package/dist/s3-cloud-storage-provider.d.ts +54 -0
  42. package/dist/s3-cloud-storage-provider.d.ts.map +1 -0
  43. package/dist/s3-cloud-storage-provider.js +78 -0
  44. package/dist/s3-cloud-storage-provider.js.map +1 -0
  45. package/dist/sqlcipher-client-store.d.ts +68 -0
  46. package/dist/sqlcipher-client-store.d.ts.map +1 -0
  47. package/dist/sqlcipher-client-store.js +382 -0
  48. package/dist/sqlcipher-client-store.js.map +1 -0
  49. package/dist/types.d.ts +408 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +7 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +48 -0
@@ -0,0 +1,251 @@
1
+ /**
2
+ * EncryptedFileSigningKeyProvider — file-backed SigningKeyProvider for CELLO_ENV=local/dev.
3
+ *
4
+ * PERSIST-010: Reads the Ed25519 private key seed from an encrypted key file at the
5
+ * configured path, decrypts it into memory for signing, and zeroes the in-memory key
6
+ * buffer after each sign() call (SI-002).
7
+ *
8
+ * The private key NEVER crosses the provider boundary (SI-001). The only exported
9
+ * values are the public key (via getPublicKey()) and signatures (via sign()).
10
+ *
11
+ * Key file format (same as FileKeyProvider in @cello-protocol/crypto):
12
+ * Bytes 0–3: Magic [0xCE, 0x11, 0x0E, 0x01]
13
+ * Byte 4: Version (0x01)
14
+ * Bytes 5–36: 32-byte Ed25519 seed
15
+ *
16
+ * This file is NOT exported from packages/client/src/index.ts.
17
+ * It is only imported by the composition root (server.ts).
18
+ *
19
+ * RFC reference: Ed25519 signing per RFC 8032.
20
+ */
21
+ import { readFile } from "node:fs/promises";
22
+ import { ed25519 } from "@noble/curves/ed25519.js";
23
+ import { SigningKeyProviderError } from "@cello-protocol/interfaces";
24
+ // ─── Key file format constants ───────────────────────────────────────────────
25
+ const KEY_FILE_MAGIC = new Uint8Array([0xce, 0x11, 0x0e, 0x01]);
26
+ const KEY_FILE_VERSION = 1;
27
+ const SEED_BYTES = 32;
28
+ const KEY_FILE_SIZE = KEY_FILE_MAGIC.length + 1 + SEED_BYTES; // 37 bytes
29
+ // ─── EncryptedFileSigningKeyProvider ─────────────────────────────────────────
30
+ /**
31
+ * SigningKeyProvider backed by an encrypted key file on disk.
32
+ *
33
+ * Lifecycle: EncryptedFileSigningKeyProvider.load(path, opts) → ready to sign.
34
+ *
35
+ * On each sign() call, the seed is read from the file into a temporary buffer,
36
+ * used for signing, and the buffer is zeroed immediately after — even on throw.
37
+ * This ensures the private key exists in process memory only for the minimum
38
+ * time required to produce the signature.
39
+ *
40
+ * Security invariants:
41
+ * SI-001: No method returns/exports the private key.
42
+ * SI-002: Key buffer zeroed after EVERY sign() call, even on throw (try/finally).
43
+ * SI-003: sign() failure propagates — never falls back to weaker signing.
44
+ */
45
+ export class EncryptedFileSigningKeyProvider {
46
+ #publicKey;
47
+ #keyPath;
48
+ #agentId;
49
+ #logger;
50
+ /**
51
+ * Working buffer for seed bytes during signing — zeroed in finally after every sign() call.
52
+ *
53
+ * This is a persistent instance field shared across sign() calls. The design is safe because
54
+ * ed25519.sign() is synchronous — there is no await between raw.copy() and the finally zeroing,
55
+ * so no concurrent call can observe key material in the buffer. If async operations were ever
56
+ * added between load and use, a local-variable-per-call design would be safer.
57
+ */
58
+ #workingBuffer = new Uint8Array(SEED_BYTES);
59
+ #corrupted = false;
60
+ #throwAfterLoad = false;
61
+ constructor(publicKey, keyPath, agentId, logger) {
62
+ this.#publicKey = publicKey;
63
+ this.#keyPath = keyPath;
64
+ this.#agentId = agentId;
65
+ this.#logger = logger;
66
+ }
67
+ /**
68
+ * Load the signing key from the key file at the given path.
69
+ *
70
+ * Validates the file format and derives the public key. The seed itself
71
+ * is not retained — it is re-read from the file on each sign() call.
72
+ *
73
+ * Throws SigningKeyProviderError if:
74
+ * - File not found (reason: 'key_file_not_found')
75
+ * - File corrupt (reason: 'key_file_corrupt')
76
+ *
77
+ * @param path - Absolute path to the encrypted key file (SIGNING_KEY_PATH)
78
+ * @param opts - Configuration including agentId and logger
79
+ */
80
+ static async load(path, opts) {
81
+ const { agentId, logger } = opts;
82
+ let raw;
83
+ try {
84
+ raw = await readFile(path);
85
+ }
86
+ catch (err) {
87
+ const code = err.code;
88
+ if (code === "ENOENT") {
89
+ logger.error("client.key.provider.init.failed", {
90
+ agentId,
91
+ providerType: "EncryptedFileSigningKeyProvider",
92
+ reason: "key_file_not_found",
93
+ errorMessage: err.message,
94
+ });
95
+ throw new SigningKeyProviderError("key_file_not_found", path);
96
+ }
97
+ const reason = `cannot read key file: ${err.message}`;
98
+ logger.error("client.key.provider.init.failed", {
99
+ agentId,
100
+ providerType: "EncryptedFileSigningKeyProvider",
101
+ reason,
102
+ errorMessage: err.message,
103
+ });
104
+ throw new SigningKeyProviderError("key_file_corrupt", path);
105
+ }
106
+ // Validate and extract seed to derive public key, then zero the temp buffer
107
+ const seedForInit = validateAndExtractSeed(raw, path, agentId, logger);
108
+ const publicKey = ed25519.getPublicKey(seedForInit);
109
+ seedForInit.fill(0); // Zero the initialization buffer immediately
110
+ logger.info("client.key.provider.initialised", {
111
+ agentId,
112
+ providerType: "EncryptedFileSigningKeyProvider",
113
+ });
114
+ return new EncryptedFileSigningKeyProvider(publicKey, path, agentId, logger);
115
+ }
116
+ /** Return the 32-byte Ed25519 public key. */
117
+ async getPublicKey() {
118
+ return this.#publicKey;
119
+ }
120
+ /**
121
+ * Sign data with the Ed25519 private key.
122
+ *
123
+ * Security: On each call, the seed is re-read from the key file into a
124
+ * working buffer, used for signing, and the buffer is zeroed in a finally
125
+ * block — even if signing throws (SI-002).
126
+ *
127
+ * The public key is derived once at load() and cached — it is not sensitive.
128
+ */
129
+ async sign(data, opts) {
130
+ if (this.#corrupted) {
131
+ this.#workingBuffer.fill(0);
132
+ const err = new SigningKeyProviderError("provider_corrupted");
133
+ this.#logger.error("client.key.sign.failed", {
134
+ agentId: this.#agentId,
135
+ reason: "provider_corrupted",
136
+ });
137
+ throw err;
138
+ }
139
+ // Re-read seed from file into working buffer
140
+ try {
141
+ const raw = await readFile(this.#keyPath);
142
+ raw.copy(Buffer.from(this.#workingBuffer.buffer, this.#workingBuffer.byteOffset, SEED_BYTES), 0, KEY_FILE_MAGIC.length + 1, KEY_FILE_SIZE);
143
+ }
144
+ catch (err) {
145
+ this.#workingBuffer.fill(0);
146
+ const reason = err instanceof Error ? err.message : String(err);
147
+ this.#logger.error("client.key.sign.failed", {
148
+ agentId: this.#agentId,
149
+ reason,
150
+ errorMessage: err.message,
151
+ });
152
+ throw new SigningKeyProviderError(reason);
153
+ }
154
+ // SI-002 test seam: throw AFTER key material is in the buffer so the finally
155
+ // block zeroing is exercised under adversarial conditions.
156
+ if (this.#throwAfterLoad) {
157
+ try {
158
+ throw new Error("injected failure after key load");
159
+ }
160
+ finally {
161
+ // SI-002: ALWAYS zero the working buffer, even on test-injected throw
162
+ this.#workingBuffer.fill(0);
163
+ }
164
+ }
165
+ try {
166
+ const signature = ed25519.sign(data, this.#workingBuffer);
167
+ this.#logger.info("client.key.signed", {
168
+ agentId: this.#agentId,
169
+ dataLength: data.length,
170
+ ...(opts?.correlationId !== undefined && { correlationId: opts.correlationId }),
171
+ });
172
+ return signature;
173
+ }
174
+ catch (err) {
175
+ const reason = err instanceof Error ? err.message : String(err);
176
+ this.#logger.error("client.key.sign.failed", {
177
+ agentId: this.#agentId,
178
+ reason,
179
+ errorMessage: err.message,
180
+ });
181
+ throw new SigningKeyProviderError(reason);
182
+ }
183
+ finally {
184
+ // SI-002: ALWAYS zero the working buffer after sign(), even on throw
185
+ this.#workingBuffer.fill(0);
186
+ }
187
+ }
188
+ // ─── Test-only methods (not part of SigningKeyProvider interface) ───────────
189
+ /**
190
+ * @internal Test seam — returns true if the working buffer is currently all-zeros.
191
+ * This does NOT expose key material. Tests use this to verify SI-002 (zeroing)
192
+ * without ever seeing the private key bytes.
193
+ */
194
+ isKeyBufferZeroedForTesting() {
195
+ return this.#workingBuffer.every((b) => b === 0);
196
+ }
197
+ /**
198
+ * @internal Test seam — corrupts the provider state to trigger sign() failures
199
+ * BEFORE the key file is read. Used to test SI-003 (no fallback).
200
+ * Note: does NOT exercise the try/finally zeroing path — use throwAfterLoadForTesting() for that.
201
+ */
202
+ corruptForTesting() {
203
+ this.#corrupted = true;
204
+ }
205
+ /**
206
+ * @internal Test seam — causes sign() to throw AFTER the key has been loaded into
207
+ * the working buffer but BEFORE ed25519.sign() is called. Used to verify SI-002:
208
+ * the finally block zeroes the key buffer even when sign() throws mid-operation.
209
+ */
210
+ throwAfterLoadForTesting() {
211
+ this.#throwAfterLoad = true;
212
+ }
213
+ }
214
+ // ─── Private helpers ─────────────────────────────────────────────────────────
215
+ /**
216
+ * Validate key file format and extract the seed into a new buffer.
217
+ * Throws SigningKeyProviderError on invalid format.
218
+ */
219
+ function validateAndExtractSeed(raw, path, agentId, logger) {
220
+ if (raw.length !== KEY_FILE_SIZE) {
221
+ logger.error("client.key.provider.init.failed", {
222
+ agentId,
223
+ providerType: "EncryptedFileSigningKeyProvider",
224
+ reason: "key_file_corrupt",
225
+ });
226
+ throw new SigningKeyProviderError("key_file_corrupt", path);
227
+ }
228
+ for (let i = 0; i < KEY_FILE_MAGIC.length; i++) {
229
+ if (raw[i] !== KEY_FILE_MAGIC[i]) {
230
+ logger.error("client.key.provider.init.failed", {
231
+ agentId,
232
+ providerType: "EncryptedFileSigningKeyProvider",
233
+ reason: "key_file_corrupt",
234
+ });
235
+ throw new SigningKeyProviderError("key_file_corrupt", path);
236
+ }
237
+ }
238
+ if (raw[KEY_FILE_MAGIC.length] !== KEY_FILE_VERSION) {
239
+ logger.error("client.key.provider.init.failed", {
240
+ agentId,
241
+ providerType: "EncryptedFileSigningKeyProvider",
242
+ reason: "key_file_corrupt",
243
+ });
244
+ throw new SigningKeyProviderError("key_file_corrupt", path);
245
+ }
246
+ // Copy seed into a new buffer (caller must zero after use)
247
+ const seed = new Uint8Array(SEED_BYTES);
248
+ raw.copy(Buffer.from(seed.buffer), 0, KEY_FILE_MAGIC.length + 1, KEY_FILE_SIZE);
249
+ return seed;
250
+ }
251
+ //# sourceMappingURL=encrypted-file-signing-key-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encrypted-file-signing-key-provider.js","sourceRoot":"","sources":["../src/encrypted-file-signing-key-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { createClient } from "./client.js";
2
+ export { S3CloudStorageProvider } from "./s3-cloud-storage-provider.js";
3
+ export type { S3CloudStorageConfig } from "./s3-cloud-storage-provider.js";
4
+ export { AgentHashQueue, buildSignedAckTbs, verifyRelayAck, RELAY_PREDECESSOR_UNKNOWN, } from "./agent-hash-queue.js";
5
+ export type { AgentHashQueueOptions, RelayAck, PendingHashEntry, RelayPredecessorUnknown, } from "./agent-hash-queue.js";
6
+ export { NetworkDirectoryNode, bootstrapNetworkKeyShares, runNetworkDkg } from "./network-directory-node.js";
7
+ export { createMcpSessionServer } from "./mcp-server.js";
8
+ export { ClientBackup, BACKUP_WARNING } from "./client-backup.js";
9
+ export type { ClientBackupOptions } from "./client-backup.js";
10
+ export type { CelloClient, PeerEntry, SendResult, SendFailureReason, ReceivedEnvelope, ReceivedMessage, SendMessageResult, SendMessageFailureReason, SessionRecord, SessionStatus, ReceiveAssignmentResult, SessionAssignmentEvent, InitiateSessionResult, } from "./types.js";
11
+ export { evaluateConnectionPackage, OPEN_POLICY, SELECTIVE_DEFAULT, CLOSED_POLICY, } from "./connection-policy.js";
12
+ export type { DirectoryContext, SignalRequirement, SignalRequirementPolicy, UnmetRequirement, ConnectionReport, } from "./connection-policy.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,qBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC7G,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,iBAAiB,EACjB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { createClient } from "./client.js";
2
+ export { S3CloudStorageProvider } from "./s3-cloud-storage-provider.js";
3
+ export { AgentHashQueue, buildSignedAckTbs, verifyRelayAck, RELAY_PREDECESSOR_UNKNOWN, } from "./agent-hash-queue.js";
4
+ export { NetworkDirectoryNode, bootstrapNetworkKeyShares, runNetworkDkg } from "./network-directory-node.js";
5
+ export { createMcpSessionServer } from "./mcp-server.js";
6
+ export { ClientBackup, BACKUP_WARNING } from "./client-backup.js";
7
+ export { evaluateConnectionPackage, OPEN_POLICY, SELECTIVE_DEFAULT, CLOSED_POLICY, } from "./connection-policy.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC7G,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAiBlE,OAAO,EACL,yBAAyB,EACzB,WAAW,EACX,iBAAiB,EACjB,aAAa,GACd,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * CELLO MCP Session Server — mcp-server.ts (CELLO-MCP-003)
3
+ *
4
+ * createMcpSessionServer(node, client, keyProvider): McpServer
5
+ * Registers the M3 tool set (19 tools) against a CelloClient.
6
+ * Transport-agnostic: identical tool names, schemas, and wiring under
7
+ * InMemoryTransport (tests) and stdio (production). AC-016.
8
+ *
9
+ * MCP-003 additions (10 new tools):
10
+ * cello_register — REG-001 DKG registration
11
+ * cello_request_connection — CONNREQ-002 Round 1 sender
12
+ * cello_respond_to_disclosure_request — CONNREQ-002 Round 2 sender
13
+ * cello_await_connection_request — waits for agent-review inbound request
14
+ * cello_accept_connection — inference-mode accept
15
+ * cello_reject_connection — inference-mode reject
16
+ * cello_request_more_disclosure — inference-mode ask for more
17
+ * cello_list_connections — list active connections
18
+ * cello_set_policy — configure policy engine
19
+ * cello_get_policy — read current policy
20
+ *
21
+ * MCP-002 modifications:
22
+ * cello_initiate_session: checks hasConnection() first
23
+ * cello_status: gains registered, agent_id, connection_count, policy_mode, policy_review_mode
24
+ *
25
+ * PSEUDOCODE (Phase P — MCP-003):
26
+ *
27
+ * cello_register({ phone_stub }):
28
+ * 1. result = await client.register(phone_stub)
29
+ * 2. if 'error' in result: return { error: { reason: result.error } }
30
+ * 3. return { registered: true, agent_id, primary_pubkey, ml_dsa_pubkey }
31
+ * SI-001: never include ml_dsa secret
32
+ *
33
+ * cello_request_connection({ target_pubkey, include_endorsements?, include_attestations? }):
34
+ * 1. Build a minimal ConnectionPackage (empty endorsements/attestations unless requested)
35
+ * 2. result = await client.cello_request_connection({ target_pubkey, package_cbor })
36
+ * 3. Map result to MCP response shape
37
+ *
38
+ * cello_respond_to_disclosure_request({ connection_request_id, ... }):
39
+ * 1. result = await client.cello_respond_to_disclosure_request({ connection_request_id, package_cbor })
40
+ * 2. Map result
41
+ *
42
+ * cello_await_connection_request({ timeout_ms? }):
43
+ * 1. result = await client.awaitConnectionRequest(timeout_ms ?? 30_000)
44
+ * 2. if timeout: return { type: 'timeout' }
45
+ * 3. Return { type: 'pending_review', connection_request_id, from_pubkey, report }
46
+ * SI-003: report is ConnectionReport — no raw signatures, no full pubkeys
47
+ *
48
+ * cello_accept_connection({ connection_request_id }):
49
+ * 1. result = await client.acceptConnection(connection_request_id)
50
+ * 2. Map to { accepted: true, connection_id } or { error: { reason } }
51
+ *
52
+ * cello_reject_connection({ connection_request_id, reason? }):
53
+ * 1. result = await client.rejectConnection(connection_request_id, reason)
54
+ * 2. Map to { rejected: true } or { error: { reason } }
55
+ *
56
+ * cello_request_more_disclosure({ connection_request_id, requested_items }):
57
+ * 1. result = await client.requestMoreDisclosure(connection_request_id, requested_items)
58
+ * 2. Map to { request_sent: true } or { error: { reason } }
59
+ *
60
+ * cello_list_connections():
61
+ * 1. connections = client.listConnections()
62
+ * 2. Map each record to { connection_id, counterparty_pubkey, counterparty_primary_pubkey,
63
+ * established_at, status: 'active' }
64
+ *
65
+ * cello_set_policy({ mode, review_mode, requirements? }):
66
+ * 1. policy = { mode, review_mode, requirements: requirements ?? [] }
67
+ * 2. client.setPolicy(policy)
68
+ * 3. return { policy_set: true, mode, review_mode, requirement_count }
69
+ *
70
+ * cello_get_policy():
71
+ * 1. policy = client.getPolicy()
72
+ * 2. return { mode, review_mode, requirements }
73
+ *
74
+ * Modified: cello_initiate_session({ target_pubkey }):
75
+ * 1. NEW: check client.hasConnection(target_pubkey)
76
+ * if !connection → return { ok: false, reason: 'no_connection' }
77
+ * (existing transport guard + directory signaling unchanged)
78
+ *
79
+ * Modified: cello_status():
80
+ * + registered: bool
81
+ * + agent_id: hex | null
82
+ * + connection_count: number
83
+ * + policy_mode: string
84
+ * + policy_review_mode: string
85
+ *
86
+ * PSEUDOCODE (Phase P):
87
+ *
88
+ * State held by the MCP server instance:
89
+ * startedAt: number = Date.now()
90
+ * inboundSessionQueue: Uint8Array[] — FIFO queue of inbound session_id bytes
91
+ *
92
+ * Server setup:
93
+ * client.onSessionAssignment((sessionIdBytes) => {
94
+ * inboundSessionQueue.push(sessionIdBytes)
95
+ * })
96
+ *
97
+ * Helper: transportStarted():
98
+ * return node.listenAddresses().length > 0
99
+ *
100
+ * Helper: directoryReachable():
101
+ * // In M1, we determine directory reachability from whether we have active sessions
102
+ * // with a directory_endpoint set. Best-effort check from session records.
103
+ * return any session in client.listSessions() has a directory_endpoint with a peer_id
104
+ *
105
+ * Helper: toHex(bytes):
106
+ * return Buffer.from(bytes).toString('hex')
107
+ *
108
+ * Helper: fromHex(str):
109
+ * return Buffer.from(str, 'hex')
110
+ *
111
+ * ─── tool: cello_initiate_session({ target_pubkey }) ─────────────────────────────
112
+ * 1. Guard: if !transportStarted() → return transport_not_started error
113
+ * 2. SESSION-002 session_request flow:
114
+ * a. Look up target_pubkey in client's sessions (M1 stub: directory signaling is
115
+ * handled via receiveSessionAssignment. The session_request must be sent through
116
+ * the directory signaling stream. In M1 this is driven externally by the test
117
+ * harness calling receiveSessionAssignment on both clients. Here we emit the
118
+ * request via the stored directory stream if available, then poll listSessions()
119
+ * for the resulting session_id.)
120
+ * b. Actually: The NODE-001 signaling flow is: client initiates a session_request
121
+ * to the directory over the persistent signaling stream, the directory creates a
122
+ * SessionAssignment and pushes it to both clients. In M1, the directory is a
123
+ * separate process that receives the request. For the MCP tool surface:
124
+ * - The client must have a way to send a session_request to the directory.
125
+ * - CelloClientImpl already holds directoryStreams per session. But those are
126
+ * post-assignment. The pre-session directory signaling stream is separate.
127
+ * c. Per CONTEXT.md: session establishment — directory issues signed SessionAssignment.
128
+ * The client sends session_request to directory's /cello/signaling/1.0.0 stream.
129
+ * d. Implementation: initiate a directory signaling stream at the MCP server level
130
+ * (separate from the per-session streams in CelloClientImpl). The MCP server
131
+ * must know the directory endpoint. In M1 tests, the directory endpoint is
132
+ * obtained from an existing session's record OR passed at construction time.
133
+ *
134
+ * NOTE: In M1, cello_initiate_session is driven by the test harness calling
135
+ * receiveSessionAssignment on both clients (the directory side is real in e2e tests).
136
+ * The MCP tool implements the client-side: send the session_request frame to the
137
+ * directory signaling stream and poll until session_assignment arrives.
138
+ *
139
+ * For the actual M1 implementation:
140
+ * 1. Connect to directory /cello/signaling/1.0.0 (using stored endpoint from existing session,
141
+ * or a pre-configured directory multiaddr)
142
+ * 2. Auth challenge-response
143
+ * 3. Send { type: "session_request", target_pubkey: fromHex(target_pubkey) }
144
+ * 4. Poll listSessions() every 100ms until a new session with counterparty_pubkey == target_pubkey
145
+ * appears, or timeout (10s)
146
+ * 5. Return session details from the new SessionRecord
147
+ *
148
+ * ─── tool: cello_await_session({ timeout_ms }) ────────────────────────────────────
149
+ * 1. deadline = Date.now() + timeout_ms
150
+ * 2. Poll every 20ms until deadline:
151
+ * a. if inboundSessionQueue.length > 0:
152
+ * sessionId = inboundSessionQueue.shift()
153
+ * sessionIdHex = toHex(sessionId)
154
+ * record = client.listSessions().find(s => toHex(s.session_id) === sessionIdHex)
155
+ * if record: return { type: 'new_session', session_id: sessionIdHex,
156
+ * counterparty_pubkey: toHex(record.counterparty_pubkey),
157
+ * genesis_prev_root: toHex(record.genesis_prev_root) }
158
+ * 3. return { type: 'timeout' }
159
+ *
160
+ * ─── tool: cello_send({ session_id, content }) ────────────────────────────────────
161
+ * 1. Guard: transport_not_started
162
+ * 2. result = await client.sendMessage(session_id, TextEncoder.encode(content))
163
+ * 3. if result.ok:
164
+ * // Retrieve leaf_hash from the session record's most recent leaf
165
+ * record = client.listSessions().find(s => toHex(s.session_id) === session_id)
166
+ * leafHash = computeLeafHash(record.local_tree_leaves[last])
167
+ * return { delivered: true, leaf_hash: toHex(leafHash) }
168
+ * else:
169
+ * return { delivered: false, reason: result.reason }
170
+ *
171
+ * ─── tool: cello_receive_session({ session_id, timeout_ms }) — session-locked ────────
172
+ * 1. Guard: transport_not_started
173
+ * 2. deadline = Date.now() + timeout_ms
174
+ * 3. Poll every 20ms until deadline:
175
+ * a. msg = client.receiveMessage(session_id)
176
+ * b. if msg:
177
+ * return { type: 'message', content: TextDecoder.decode(msg.content),
178
+ * sender_pubkey: toHex(msg.senderPubkey),
179
+ * sequence_number: msg.sequenceNumber,
180
+ * leaf_hash: toHex(msg.leafHash) }
181
+ * 4. return { type: 'timeout' }
182
+ *
183
+ * ─── tool: cello_receive({ timeout_ms }) — any-session default ───────────────────────
184
+ * 1. Guard: transport_not_started
185
+ * 2. result = await client.receiveMessageAsync(timeout_ms)
186
+ * 3. if timeout: return { type: 'timeout' }
187
+ * 4. return { type: 'message', session_id, content, sender_pubkey, sequence_number, leaf_hash }
188
+ *
189
+ * ─── tool: cello_close_session({ session_id }) ────────────────────────────────────
190
+ * 1. Guard: transport_not_started
191
+ * 2. result = await client.initiateSessionSeal(session_id)
192
+ * if !result.ok: return { status: 'seal_rejected', sealed_root: null,
193
+ * close_timestamp: Date.now(), reason: result.reason, mmr_peak: null }
194
+ * 3. Poll listSessions() every 100ms for up to 30s:
195
+ * a. record = sessions.find(s => toHex(s.session_id) === session_id)
196
+ * b. if record.status === 'sealed':
197
+ * return { status: 'sealed', sealed_root: toHex(record.sealed_root),
198
+ * close_timestamp: Date.now(), reason: null, mmr_peak: null }
199
+ * c. if record.status === 'seal_rejected':
200
+ * return { status: 'seal_rejected', sealed_root: null,
201
+ * close_timestamp: Date.now(), reason: 'directory_rejected', mmr_peak: null }
202
+ * 4. return { status: 'seal_deferred', sealed_root: null,
203
+ * close_timestamp: Date.now(), reason: 'directory_unreachable', mmr_peak: null }
204
+ *
205
+ * ─── tool: cello_list_sessions() ──────────────────────────────────────────────────
206
+ * 1. records = client.listSessions()
207
+ * 2. For each record:
208
+ * emit { session_id: hex, counterparty_pubkey: hex, counterparty_peer_id: string,
209
+ * relay_endpoint: { peer_id: hex, multiaddrs }, status, last_seen_seq,
210
+ * leaf_count: record.local_tree_leaves.length }
211
+ *
212
+ * ─── tool: cello_status() ─────────────────────────────────────────────────────────
213
+ * No transport_not_started guard (same as MCP-001).
214
+ * 1. ownPubkey = toHex(await keyProvider.getPublicKey())
215
+ * 2. activeSessions = client.listSessions().filter(s => s.status === 'active')
216
+ * 3. return {
217
+ * transport_started: transportStarted(),
218
+ * own_pubkey: ownPubkey,
219
+ * listen_addresses: node.listenAddresses(),
220
+ * connected_peer_count: node.getConnections().length,
221
+ * uptime_seconds: Math.floor((Date.now() - startedAt) / 1000),
222
+ * active_session_count: activeSessions.length,
223
+ * directory_reachable: directoryReachable()
224
+ * }
225
+ *
226
+ * ─── tool: cello_get_sealed_receipt({ session_id }) ──────────────────────────────
227
+ * SI-001: MUST NOT return for seal_rejected sessions.
228
+ * SI-002: MUST NOT return private key material.
229
+ * 1. record = client.listSessions().find(s => toHex(s.session_id) === session_id)
230
+ * 2. if !record: return { error: { reason: 'session_not_found', session_id } }
231
+ * 3. if record.status !== 'sealed': return { error: { reason: 'session_not_sealed', session_id } }
232
+ * 4. pubA = record (lower hex participant), pubB = higher hex participant (from genesis_prev_root ordering)
233
+ * Actually: participants are [own_pubkey, counterparty_pubkey] sorted as stored. The spec says
234
+ * [A_pubkey, B_pubkey] which is the order they appear in the session (A=initiator, B=responder).
235
+ * Since we don't know which role we played, emit [own, counterparty] in canonical order.
236
+ * 5. return { session_id, sealed_root: hex, participants: [hex, hex],
237
+ * close_timestamp: <from seal>, attestation_self: 'PENDING',
238
+ * attestation_counterparty: 'PENDING',
239
+ * leaf_count: record.local_tree_leaves.length,
240
+ * directory_signature: hex }
241
+ *
242
+ * ─── tool: cello_get_inclusion_proof({ session_id, leaf_index }) ──────────────────
243
+ * SI-001: MUST NOT return proof for seal_rejected sessions.
244
+ * SI-003: returned sealed_root MUST equal inclusionProof reconstruction root.
245
+ * 1. record = client.listSessions().find(s => toHex(s.session_id) === session_id)
246
+ * 2. if !record || record.status !== 'sealed':
247
+ * return { error: { reason: 'session_not_sealed' } }
248
+ * 3. treeSize = record.local_tree_leaves.length
249
+ * 4. if leaf_index < 0 || leaf_index >= treeSize:
250
+ * return { error: { reason: 'leaf_index_out_of_range', leaf_index, tree_size: treeSize } }
251
+ * 5. Build tree from record.local_tree_leaves using buildMerkleTree(inputs: LeafInput[])
252
+ * 6. leafHash = tree.levelHashes[0][leaf_index]
253
+ * 7. proof = inclusionProof(tree, leaf_index)
254
+ * 8. root = merkleRoot(tree)
255
+ * 9. SI-003: assert root equals record.sealed_root (consistent snapshot)
256
+ * NOTE: sealed_root from directory is based on the canonical leaf sequence. The local
257
+ * tree should match if seal completed. If they don't match, return internal_error.
258
+ * 10. return { leaf_hash: hex, leaf_index, tree_size: treeSize, proof: [hex], sealed_root: hex }
259
+ */
260
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
261
+ import type { CelloClient } from "./types.js";
262
+ import type { CelloNode } from "@cello-protocol/transport";
263
+ import type { KeyProvider } from "@cello-protocol/crypto";
264
+ import type { CheckpointStatusProvider } from "@cello-protocol/interfaces";
265
+ import type { ClientBackup } from "./client-backup.js";
266
+ export declare function createMcpSessionServer(node: CelloNode, client: CelloClient, keyProvider: KeyProvider, opts?: {
267
+ checkpointStatusProvider?: CheckpointStatusProvider;
268
+ clientBackup?: ClientBackup;
269
+ }): McpServer;
270
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,KAAK,EAAE,WAAW,EAA0B,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAuBvD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,WAAW,EACxB,IAAI,CAAC,EAAE;IAAE,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GAC1F,SAAS,CA+jCX"}