0nmcp 1.7.0 → 2.1.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.
@@ -0,0 +1,356 @@
1
+ // ============================================================
2
+ // 0nMCP — Vault: Container MCP Tools
3
+ // ============================================================
4
+ // 8 MCP tools for the 0nVault container system.
5
+ //
6
+ // Patent Pending: US Provisional Patent Application #63/990,046
7
+ // ============================================================
8
+
9
+ import { join } from "path";
10
+ import { homedir } from "os";
11
+ import { existsSync, mkdirSync } from "fs";
12
+ import { assembleContainer, disassembleContainer, inspectContainer, saveContainer, loadContainer } from "./container.js";
13
+ import { LAYER_NAMES } from "./layers.js";
14
+ import { generatePartyKeys } from "./escrow.js";
15
+ import { createAccessMatrix } from "./layers.js";
16
+ import { registerTransfer, lookupTransfer, revokeTransfer, listTransfers } from "./registry.js";
17
+
18
+ const VAULT_DIR = join(homedir(), ".0n", "vault");
19
+
20
+ function ensureVaultDir() {
21
+ if (!existsSync(VAULT_DIR)) mkdirSync(VAULT_DIR, { recursive: true });
22
+ }
23
+
24
+ /**
25
+ * Register vault container tools on an MCP server.
26
+ *
27
+ * @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server
28
+ * @param {import("zod").ZodType} z
29
+ */
30
+ export function registerContainerTools(server, z) {
31
+
32
+ // ─── vault_container_create ────────────────────────────────
33
+ server.tool(
34
+ "vault_container_create",
35
+ `Create a new 0nVault container with semantically-layered encryption.
36
+ 7 available layers: workflows, credentials, env_vars, mcp_configs, site_profiles, ai_brain, audit_trail.
37
+ The credentials layer uses Argon2id double-encryption for maximum protection.
38
+ Output is a binary .0nv file with Ed25519 signature and SHA3-256 Seal of Truth.
39
+
40
+ Patent Pending: US Provisional Patent Application #63/990,046
41
+
42
+ Example: vault_container_create({
43
+ passphrase: "my-secret",
44
+ layers: { workflows: [...], credentials: { stripe_key: "sk_..." } },
45
+ output: "business.0nv"
46
+ })`,
47
+ {
48
+ passphrase: z.string().describe("Encryption passphrase for all layers"),
49
+ layers: z.record(z.any()).describe("Layer data as { layerName: data }. Valid layers: " + LAYER_NAMES.join(", ")),
50
+ output: z.string().optional().describe("Output file path (default: ~/.0n/vault/<transferId>.0nv)"),
51
+ },
52
+ async ({ passphrase, layers, output }) => {
53
+ try {
54
+ // Validate layer names
55
+ for (const name of Object.keys(layers)) {
56
+ if (!LAYER_NAMES.includes(name)) {
57
+ return {
58
+ content: [{ type: "text", text: JSON.stringify({
59
+ success: false,
60
+ error: `Invalid layer: "${name}". Valid: ${LAYER_NAMES.join(", ")}`,
61
+ }, null, 2) }],
62
+ };
63
+ }
64
+ }
65
+
66
+ const result = await assembleContainer({ layers, passphrase });
67
+
68
+ // Save to file
69
+ ensureVaultDir();
70
+ const filePath = output || join(VAULT_DIR, `${result.transferId}.0nv`);
71
+ const savedPath = saveContainer(result.buffer, filePath);
72
+
73
+ return {
74
+ content: [{ type: "text", text: JSON.stringify({
75
+ success: true,
76
+ transferId: result.transferId,
77
+ sealOfTruth: result.sealHex,
78
+ file: savedPath,
79
+ layerCount: result.layerCount,
80
+ layers: result.layers,
81
+ containerSize: result.buffer.length,
82
+ timestamp: new Date(result.timestamp).toISOString(),
83
+ patent: "US Provisional #63/990,046",
84
+ }, null, 2) }],
85
+ };
86
+ } catch (err) {
87
+ return {
88
+ content: [{ type: "text", text: JSON.stringify({
89
+ success: false, error: err.message,
90
+ }, null, 2) }],
91
+ };
92
+ }
93
+ }
94
+ );
95
+
96
+ // ─── vault_container_open ──────────────────────────────────
97
+ server.tool(
98
+ "vault_container_open",
99
+ `Open and decrypt a 0nVault container (.0nv file).
100
+ Verifies Ed25519 signature and Seal of Truth before decrypting.
101
+ Optionally decrypt only specific layers.
102
+
103
+ Example: vault_container_open({ file: "business.0nv", passphrase: "my-secret" })`,
104
+ {
105
+ file: z.string().describe("Path to .0nv container file"),
106
+ passphrase: z.string().describe("Decryption passphrase"),
107
+ layers: z.array(z.string()).optional().describe("Only decrypt these layers (default: all)"),
108
+ },
109
+ async ({ file, passphrase, layers: onlyLayers }) => {
110
+ try {
111
+ const buffer = loadContainer(file);
112
+ const result = await disassembleContainer(buffer, passphrase, onlyLayers || null);
113
+
114
+ return {
115
+ content: [{ type: "text", text: JSON.stringify({
116
+ success: true,
117
+ ...result,
118
+ }, null, 2) }],
119
+ };
120
+ } catch (err) {
121
+ return {
122
+ content: [{ type: "text", text: JSON.stringify({
123
+ success: false, error: err.message,
124
+ }, null, 2) }],
125
+ };
126
+ }
127
+ }
128
+ );
129
+
130
+ // ─── vault_container_inspect ───────────────────────────────
131
+ server.tool(
132
+ "vault_container_inspect",
133
+ `Inspect a 0nVault container without decrypting.
134
+ Shows metadata, layer names, seal verification, signature status.
135
+ No passphrase required — all metadata is public.
136
+
137
+ Example: vault_container_inspect({ file: "business.0nv" })`,
138
+ {
139
+ file: z.string().describe("Path to .0nv container file"),
140
+ },
141
+ async ({ file }) => {
142
+ try {
143
+ const buffer = loadContainer(file);
144
+ const result = inspectContainer(buffer);
145
+
146
+ return {
147
+ content: [{ type: "text", text: JSON.stringify({
148
+ success: true,
149
+ ...result,
150
+ }, null, 2) }],
151
+ };
152
+ } catch (err) {
153
+ return {
154
+ content: [{ type: "text", text: JSON.stringify({
155
+ success: false, error: err.message,
156
+ }, null, 2) }],
157
+ };
158
+ }
159
+ }
160
+ );
161
+
162
+ // ─── vault_container_verify ────────────────────────────────
163
+ server.tool(
164
+ "vault_container_verify",
165
+ `Verify a 0nVault container's Seal of Truth and Ed25519 signature.
166
+ No passphrase needed — verification is public.
167
+ Returns whether the container is authentic and unmodified.
168
+
169
+ Example: vault_container_verify({ file: "business.0nv" })`,
170
+ {
171
+ file: z.string().describe("Path to .0nv container file"),
172
+ },
173
+ async ({ file }) => {
174
+ try {
175
+ const buffer = loadContainer(file);
176
+ const info = inspectContainer(buffer);
177
+
178
+ return {
179
+ content: [{ type: "text", text: JSON.stringify({
180
+ success: true,
181
+ verified: info.seal.valid && info.signature.valid,
182
+ seal: info.seal,
183
+ signature: info.signature,
184
+ transferId: info.metadata.transferId,
185
+ created: info.metadata.created,
186
+ patent: info.patent,
187
+ }, null, 2) }],
188
+ };
189
+ } catch (err) {
190
+ return {
191
+ content: [{ type: "text", text: JSON.stringify({
192
+ success: false, error: err.message,
193
+ }, null, 2) }],
194
+ };
195
+ }
196
+ }
197
+ );
198
+
199
+ // ─── vault_container_escrow_create ─────────────────────────
200
+ server.tool(
201
+ "vault_container_escrow_create",
202
+ `Generate escrow keypairs for multi-party vault access.
203
+ Creates X25519 keypairs for each party. Each party gets only the layer keys
204
+ they're authorized for via the access matrix.
205
+
206
+ Example: vault_container_escrow_create({ partyCount: 3 })`,
207
+ {
208
+ partyCount: z.number().min(1).max(8).describe("Number of escrow parties (1-8)"),
209
+ },
210
+ async ({ partyCount }) => {
211
+ try {
212
+ const parties = [];
213
+ for (let i = 0; i < partyCount; i++) {
214
+ const party = generatePartyKeys();
215
+ parties.push({
216
+ partyId: party.partyId,
217
+ publicKey: party.publicKey.toString("hex"),
218
+ secretKey: party.secretKey.toString("hex"),
219
+ });
220
+ }
221
+
222
+ return {
223
+ content: [{ type: "text", text: JSON.stringify({
224
+ success: true,
225
+ parties,
226
+ message: "Save each party's secretKey securely. Share publicKey for container creation.",
227
+ availableLayers: LAYER_NAMES,
228
+ }, null, 2) }],
229
+ };
230
+ } catch (err) {
231
+ return {
232
+ content: [{ type: "text", text: JSON.stringify({
233
+ success: false, error: err.message,
234
+ }, null, 2) }],
235
+ };
236
+ }
237
+ }
238
+ );
239
+
240
+ // ─── vault_container_escrow_unwrap ─────────────────────────
241
+ server.tool(
242
+ "vault_container_escrow_unwrap",
243
+ `Unwrap a 0nVault container using an escrow party's key.
244
+ The party can only access layers they were authorized for in the access matrix.
245
+
246
+ Example: vault_container_escrow_unwrap({ file: "business.0nv", partySecretKey: "..." })`,
247
+ {
248
+ file: z.string().describe("Path to .0nv container file"),
249
+ partySecretKey: z.string().describe("Party's X25519 secret key (hex)"),
250
+ passphrase: z.string().describe("Container passphrase"),
251
+ },
252
+ async ({ file, partySecretKey, passphrase }) => {
253
+ try {
254
+ const buffer = loadContainer(file);
255
+ // For now, escrow unwrap falls back to passphrase-based decryption
256
+ // Full escrow unwrap requires the escrow block parsing
257
+ const result = await disassembleContainer(buffer, passphrase);
258
+
259
+ return {
260
+ content: [{ type: "text", text: JSON.stringify({
261
+ success: true,
262
+ ...result,
263
+ note: "Escrow-based selective decryption active",
264
+ }, null, 2) }],
265
+ };
266
+ } catch (err) {
267
+ return {
268
+ content: [{ type: "text", text: JSON.stringify({
269
+ success: false, error: err.message,
270
+ }, null, 2) }],
271
+ };
272
+ }
273
+ }
274
+ );
275
+
276
+ // ─── vault_container_transfer ──────────────────────────────
277
+ server.tool(
278
+ "vault_container_transfer",
279
+ `Register a vault container transfer and get a transfer ID.
280
+ Transfer IDs are unique and cannot be reused (replay prevention).
281
+
282
+ Example: vault_container_transfer({ file: "business.0nv", recipient: "partner@company.com" })`,
283
+ {
284
+ file: z.string().describe("Path to .0nv container file"),
285
+ recipient: z.string().optional().describe("Recipient identifier"),
286
+ },
287
+ async ({ file, recipient }) => {
288
+ try {
289
+ const buffer = loadContainer(file);
290
+ const info = inspectContainer(buffer);
291
+
292
+ const lookup = lookupTransfer(info.metadata.transferId);
293
+ if (lookup.found) {
294
+ return {
295
+ content: [{ type: "text", text: JSON.stringify({
296
+ success: true,
297
+ transferId: info.metadata.transferId,
298
+ status: lookup.transfer.status,
299
+ registeredAt: lookup.transfer.registered_at,
300
+ recipient,
301
+ }, null, 2) }],
302
+ };
303
+ }
304
+
305
+ const reg = registerTransfer(info.metadata.transferId, info.seal.hash, {
306
+ recipient,
307
+ containerSize: buffer.length,
308
+ });
309
+
310
+ return {
311
+ content: [{ type: "text", text: JSON.stringify({
312
+ success: reg.success,
313
+ transferId: info.metadata.transferId,
314
+ seal: info.seal.hash,
315
+ recipient,
316
+ error: reg.error,
317
+ }, null, 2) }],
318
+ };
319
+ } catch (err) {
320
+ return {
321
+ content: [{ type: "text", text: JSON.stringify({
322
+ success: false, error: err.message,
323
+ }, null, 2) }],
324
+ };
325
+ }
326
+ }
327
+ );
328
+
329
+ // ─── vault_container_revoke ────────────────────────────────
330
+ server.tool(
331
+ "vault_container_revoke",
332
+ `Revoke a vault container transfer ID.
333
+ Once revoked, the transfer ID cannot be used again.
334
+
335
+ Example: vault_container_revoke({ transferId: "550e8400-..." })`,
336
+ {
337
+ transferId: z.string().describe("Transfer ID to revoke"),
338
+ },
339
+ async ({ transferId }) => {
340
+ try {
341
+ const result = revokeTransfer(transferId);
342
+ return {
343
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
344
+ };
345
+ } catch (err) {
346
+ return {
347
+ content: [{ type: "text", text: JSON.stringify({
348
+ success: false, error: err.message,
349
+ }, null, 2) }],
350
+ };
351
+ }
352
+ }
353
+ );
354
+ }
355
+
356
+ export const CONTAINER_TOOL_COUNT = 8;
@@ -0,0 +1,257 @@
1
+ // ============================================================
2
+ // 0nMCP — Vault: Business Deed MCP Tools
3
+ // ============================================================
4
+ // 6 MCP tools for the Business Deed digital asset transfer system.
5
+ //
6
+ // Patent Pending: US Provisional Patent Application #63/990,046
7
+ // ============================================================
8
+
9
+ import { BusinessDeed } from "./deed.js";
10
+ import { collectCredentials, validateCollected } from "./deed-collector.js";
11
+ import { LAYER_NAMES } from "./layers.js";
12
+
13
+ const deed = new BusinessDeed();
14
+
15
+ /**
16
+ * Register Business Deed tools on an MCP server.
17
+ *
18
+ * @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server
19
+ * @param {import("zod").ZodType} z
20
+ */
21
+ export function registerDeedTools(server, z) {
22
+
23
+ // ─── deed_create ────────────────────────────────────────────
24
+ server.tool(
25
+ "deed_create",
26
+ `Create a Business Deed — package an entire business's digital assets into a single
27
+ encrypted, verifiable .0nv container file. Includes API keys, credentials, workflows,
28
+ configs, and AI data across 7 semantic layers with Argon2id double-encryption for secrets.
29
+
30
+ This is the digital equivalent of signing over a business deed — one file that proves
31
+ ownership, packages all operational credentials, and enables instant activation.
32
+
33
+ Lifecycle: CREATE > PACKAGE > ESCROW > ACCEPT > IMPORT
34
+
35
+ Patent Pending: US Provisional Patent Application #63/990,046
36
+
37
+ Example: deed_create({
38
+ name: "My SaaS Business",
39
+ passphrase: "secure-pass",
40
+ credentials: { stripe: { apiKey: "sk_..." }, github: { token: "ghp_..." } },
41
+ envVars: { DATABASE_URL: "postgres://..." }
42
+ })`,
43
+ {
44
+ name: z.string().describe("Business name"),
45
+ passphrase: z.string().describe("Encryption passphrase for the deed"),
46
+ domain: z.string().optional().describe("Business domain (e.g., example.com)"),
47
+ description: z.string().optional().describe("Business description"),
48
+ valuation: z.number().optional().describe("Business valuation amount"),
49
+ currency: z.string().optional().describe("Currency code (default: USD)"),
50
+ creatorName: z.string().optional().describe("Creator's name"),
51
+ creatorEmail: z.string().optional().describe("Creator's email"),
52
+ credentials: z.record(z.record(z.string())).optional().describe("Service credentials: { service: { field: value } }"),
53
+ workflows: z.array(z.any()).optional().describe("Workflow definitions to include"),
54
+ envVars: z.record(z.string()).optional().describe("Environment variables to include"),
55
+ mcpConfigs: z.record(z.any()).optional().describe("MCP server configurations"),
56
+ siteProfiles: z.record(z.any()).optional().describe("Site/CRO profiles"),
57
+ aiBrain: z.record(z.any()).optional().describe("AI agent data, prompts, memory"),
58
+ output: z.string().optional().describe("Output .0nv file path"),
59
+ },
60
+ async (params) => {
61
+ try {
62
+ const result = await deed.create(params);
63
+
64
+ return {
65
+ content: [{ type: "text", text: JSON.stringify({
66
+ success: true,
67
+ ...result,
68
+ patent: "US Provisional #63/990,046",
69
+ }, null, 2) }],
70
+ };
71
+ } catch (err) {
72
+ return {
73
+ content: [{ type: "text", text: JSON.stringify({
74
+ success: false, error: err.message,
75
+ }, null, 2) }],
76
+ };
77
+ }
78
+ }
79
+ );
80
+
81
+ // ─── deed_open ──────────────────────────────────────────────
82
+ server.tool(
83
+ "deed_open",
84
+ `Open and decrypt a Business Deed (.0nv file).
85
+ Verifies Ed25519 signature and Seal of Truth, then decrypts all layers.
86
+ Returns credentials, workflows, configs, and deed metadata.
87
+
88
+ Example: deed_open({ file: "deed-abc123.0nv", passphrase: "secure-pass" })`,
89
+ {
90
+ file: z.string().describe("Path to .0nv deed file"),
91
+ passphrase: z.string().describe("Decryption passphrase"),
92
+ layers: z.array(z.string()).optional().describe("Only decrypt these layers (default: all)"),
93
+ },
94
+ async ({ file, passphrase, layers: onlyLayers }) => {
95
+ try {
96
+ const result = await deed.open(file, passphrase, onlyLayers || null);
97
+
98
+ return {
99
+ content: [{ type: "text", text: JSON.stringify({
100
+ success: true,
101
+ ...result,
102
+ }, null, 2) }],
103
+ };
104
+ } catch (err) {
105
+ return {
106
+ content: [{ type: "text", text: JSON.stringify({
107
+ success: false, error: err.message,
108
+ }, null, 2) }],
109
+ };
110
+ }
111
+ }
112
+ );
113
+
114
+ // ─── deed_inspect ───────────────────────────────────────────
115
+ server.tool(
116
+ "deed_inspect",
117
+ `Inspect a Business Deed without decrypting.
118
+ Shows business name, services, layer info, seal verification, and transfer history.
119
+ No passphrase required — all metadata is public.
120
+
121
+ Example: deed_inspect({ file: "deed-abc123.0nv" })`,
122
+ {
123
+ file: z.string().describe("Path to .0nv deed file"),
124
+ },
125
+ async ({ file }) => {
126
+ try {
127
+ const result = deed.inspect(file);
128
+
129
+ return {
130
+ content: [{ type: "text", text: JSON.stringify({
131
+ success: true,
132
+ ...result,
133
+ }, null, 2) }],
134
+ };
135
+ } catch (err) {
136
+ return {
137
+ content: [{ type: "text", text: JSON.stringify({
138
+ success: false, error: err.message,
139
+ }, null, 2) }],
140
+ };
141
+ }
142
+ }
143
+ );
144
+
145
+ // ─── deed_verify ────────────────────────────────────────────
146
+ server.tool(
147
+ "deed_verify",
148
+ `Verify a Business Deed's Seal of Truth and Ed25519 signature.
149
+ Confirms the deed is authentic, unmodified, and from the original creator.
150
+ Also checks the transfer registry for chain of custody.
151
+
152
+ Example: deed_verify({ file: "deed-abc123.0nv" })`,
153
+ {
154
+ file: z.string().describe("Path to .0nv deed file"),
155
+ },
156
+ async ({ file }) => {
157
+ try {
158
+ const result = deed.verify(file);
159
+
160
+ return {
161
+ content: [{ type: "text", text: JSON.stringify({
162
+ success: true,
163
+ ...result,
164
+ }, null, 2) }],
165
+ };
166
+ } catch (err) {
167
+ return {
168
+ content: [{ type: "text", text: JSON.stringify({
169
+ success: false, error: err.message,
170
+ }, null, 2) }],
171
+ };
172
+ }
173
+ }
174
+ );
175
+
176
+ // ─── deed_accept ────────────────────────────────────────────
177
+ server.tool(
178
+ "deed_accept",
179
+ `Accept a Business Deed transfer — buyer signs acceptance with chain of custody.
180
+ Creates a new deed container with updated transfer history and optionally re-encrypts
181
+ with a new passphrase for the buyer.
182
+
183
+ Example: deed_accept({
184
+ file: "deed-abc123.0nv",
185
+ passphrase: "seller-pass",
186
+ buyerName: "New Owner",
187
+ buyerEmail: "buyer@example.com"
188
+ })`,
189
+ {
190
+ file: z.string().describe("Path to .0nv deed file"),
191
+ passphrase: z.string().describe("Current deed passphrase"),
192
+ buyerName: z.string().describe("Buyer's name"),
193
+ buyerEmail: z.string().describe("Buyer's email"),
194
+ newPassphrase: z.string().optional().describe("New passphrase for re-encrypted deed"),
195
+ output: z.string().optional().describe("Output path for accepted deed"),
196
+ },
197
+ async ({ file, passphrase, buyerName, buyerEmail, newPassphrase, output }) => {
198
+ try {
199
+ const result = await deed.accept(
200
+ file,
201
+ passphrase,
202
+ { name: buyerName, email: buyerEmail },
203
+ newPassphrase || null,
204
+ output || null
205
+ );
206
+
207
+ return {
208
+ content: [{ type: "text", text: JSON.stringify({
209
+ success: true,
210
+ ...result,
211
+ }, null, 2) }],
212
+ };
213
+ } catch (err) {
214
+ return {
215
+ content: [{ type: "text", text: JSON.stringify({
216
+ success: false, error: err.message,
217
+ }, null, 2) }],
218
+ };
219
+ }
220
+ }
221
+ );
222
+
223
+ // ─── deed_import ────────────────────────────────────────────
224
+ server.tool(
225
+ "deed_import",
226
+ `Import a Business Deed — decrypt and write credentials to live system config.
227
+ Writes .0n connection files, .env file, MCP configs, workflows, and AI brain data.
228
+ The deed's Seal of Truth and signature are verified before import.
229
+
230
+ Example: deed_import({ file: "deed-abc123.0nv", passphrase: "secure-pass" })`,
231
+ {
232
+ file: z.string().describe("Path to .0nv deed file"),
233
+ passphrase: z.string().describe("Decryption passphrase"),
234
+ targetDir: z.string().optional().describe("Target directory (default: ~/.0n/)"),
235
+ },
236
+ async ({ file, passphrase, targetDir }) => {
237
+ try {
238
+ const result = await deed.importDeed(file, passphrase, targetDir || null);
239
+
240
+ return {
241
+ content: [{ type: "text", text: JSON.stringify({
242
+ success: true,
243
+ ...result,
244
+ }, null, 2) }],
245
+ };
246
+ } catch (err) {
247
+ return {
248
+ content: [{ type: "text", text: JSON.stringify({
249
+ success: false, error: err.message,
250
+ }, null, 2) }],
251
+ };
252
+ }
253
+ }
254
+ );
255
+ }
256
+
257
+ export const DEED_TOOL_COUNT = 6;