dropclaw 1.1.0 → 1.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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.**
4
4
 
5
- DropClaw gives AI agents a way to store files permanently on-chain. Files are compressed and encrypted client-side (AES-256-GCM) before upload — the server never sees plaintext. It's a blind encrypted relay.
5
+ DropClaw gives AI agents a way to store files permanently on-chain. Files are compressed and encrypted client-side (AES-256-GCM) before upload — the server never sees plaintext. It's a blind encrypted relay. Files go directly on-chain as Monad calldata — DropClaw never stores user files. Encryption keys stay with the user.
6
6
 
7
7
  ## Quick Start
8
8
 
@@ -35,14 +35,14 @@ Your agent now has 5 MCP tools:
35
35
  3. Sends payment on-chain (MON on Monad, SOL on Solana, or USDC on Base)
36
36
  4. Calls `dropclaw_store` with the payment tx hash and encrypted blob
37
37
  5. DropClaw chunks the blob into segments and stores each as calldata on Monad
38
- 6. Agent receives a file ID and encryption key save both securely
39
- 7. Call `dropclaw_retrieve` anytime to get the file back (free)
38
+ 6. Agent receives a file ID encryption key is saved locally in `~/.dropclaw/keys.json`
39
+ 7. Call `dropclaw_retrieve` with the file ID to fetch and decrypt (free)
40
40
 
41
41
  ## Pricing
42
42
 
43
43
  - **Storage:** $30 USD service fee + Monad gas costs
44
44
  - **Retrieval:** Always free
45
- - **Free with Syntek:** [Syntek](https://github.com/timowhite88/farnsworth-syntek) subscribers ($100/90 days) get free DropClaw storage (gas only)
45
+ - **Syntek subscribers:** [Syntek](https://github.com/timowhite88/farnsworth-syntek) subscribers ($100/90 days) get DropClaw access for Syntek memory uploads (gas only, no service fee)
46
46
  - **50% of fees** go to FARNS token buybacks
47
47
 
48
48
  ## Payment Options
@@ -93,7 +93,7 @@ const file = await client.retrieve(result.fileId);
93
93
 
94
94
  ## Credentials
95
95
 
96
- Credentials are stored in `~/.dropclaw/vault.enc` encrypted and portable.
96
+ Credentials are stored in `~/.dropclaw/vault.json`. Encryption keys are saved in `~/.dropclaw/keys.json`.
97
97
 
98
98
  ```bash
99
99
  npx dropclaw setup # Interactive setup
package/SKILL.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  > Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.
4
4
 
5
+ ## How It Works
6
+
7
+ DropClaw is a blind encrypted relay — **files go directly on-chain as Monad calldata**. We never store user files. The flow is:
8
+
9
+ 1. Client compresses (zlib) and encrypts (AES-256-GCM) the file locally
10
+ 2. Encrypted blob is chunked and written as calldata transactions on Monad
11
+ 3. The encryption key stays with YOU — DropClaw never sees it
12
+ 4. To retrieve: fetch the encrypted blob from chain, decrypt locally with your key
13
+
5
14
  ## Endpoint
6
15
 
7
16
  `https://dropclaw.cloud`
@@ -12,10 +21,6 @@ Storage operations require an API key:
12
21
  ```
13
22
  Authorization: Bearer <api-key>
14
23
  ```
15
- Or:
16
- ```
17
- X-API-Key: <api-key>
18
- ```
19
24
 
20
25
  Retrieval is always free and does not require authentication.
21
26
 
@@ -30,10 +35,20 @@ claude mcp add dropclaw -- npx dropclaw-mcp
30
35
  | Tool | Description |
31
36
  |------|-------------|
32
37
  | `dropclaw_payment_options` | Get x402 payment requirements before storing a file |
33
- | `dropclaw_store` | Store encrypted file on Monad with payment tx hash |
34
- | `dropclaw_retrieve` | Retrieve and decrypt a stored file (free) |
38
+ | `dropclaw_store` | Encrypt and store file on Monad blockchain (requires payment tx hash) |
39
+ | `dropclaw_retrieve` | Retrieve and decrypt a stored file using your encryption key (free) |
35
40
  | `dropclaw_pricing` | Get cost estimates for a given file size |
36
- | `dropclaw_list` | List all locally stored files with encryption keys |
41
+ | `dropclaw_list` | List locally stored file IDs and encryption keys |
42
+
43
+ ### Key Management
44
+
45
+ When you store a file, `dropclaw_store` returns a `file_id` and saves the encryption key locally to `~/.dropclaw/keys.json`. **Both the file_id and key stay with you** — DropClaw does not store your keys. If you lose them, your data cannot be recovered.
46
+
47
+ When you retrieve a file, `dropclaw_retrieve` will:
48
+ 1. Fetch the encrypted blob from Monad blockchain
49
+ 2. Look up the encryption key in your local `keys.json` (or use the `encryption_key` parameter you provide)
50
+ 3. Decrypt (AES-256-GCM) and decompress (zlib inflate) the data
51
+ 4. Return the original plaintext content
37
52
 
38
53
  ## REST API
39
54
 
@@ -52,14 +67,14 @@ claude mcp add dropclaw -- npx dropclaw-mcp
52
67
  | Method | Path | Description |
53
68
  |--------|------|-------------|
54
69
  | `POST` | `/vault/store` | Store encrypted file — `{ content_base64, file_name, payment_tx_hash, payment_network }` |
55
- | `POST` | `/vault/retrieve/{id}` | Retrieve file `{ file_id }` |
70
+ | `POST` | `/vault/retrieve/{id}` | Retrieve encrypted blob from chain (free) |
56
71
 
57
72
  ## x402 Payment Flow
58
73
 
59
74
  1. **Get pricing** — `GET /vault/pricing?size=<bytes>`
60
75
  2. **Send payment** — Transfer exact amount to the `payTo` address on your preferred chain
61
76
  3. **Store file** — `POST /vault/store` with `payment_tx_hash` and `payment_network`
62
- 4. **Save credentials** — Store the returned `file_id` and local encryption key
77
+ 4. **Save your keys** — Store the returned `file_id` and your local encryption key securely
63
78
  5. **Retrieve anytime** — `POST /vault/retrieve/{id}` (free, no payment needed)
64
79
 
65
80
  ## Payment Options
@@ -72,18 +87,22 @@ claude mcp add dropclaw -- npx dropclaw-mcp
72
87
 
73
88
  ## Pricing
74
89
 
75
- - **Service fee:** $30 USD
90
+ - **Service fee:** $30 USD + gas costs
76
91
  - **Gas costs:** Variable (depends on file size and Monad gas prices)
77
92
  - **Retrieval:** Always free
78
- - **Syntek subscribers:** Free storage (gas only) — $100/90 days includes DropClaw
93
+ - **Syntek subscribers:** Gas only (no service fee) — Syntek subscription ($100/90 days) includes DropClaw access for Syntek memory uploads. Users still pay Monad gas fees.
94
+ - **50% of service fees** go to FARNS token buybacks
79
95
 
80
96
  ## Encryption
81
97
 
82
98
  - **Algorithm:** AES-256-GCM
83
- - **Key generation:** Client-side, never transmitted
84
- - **Compression:** zlib before encryption
85
- - **Storage:** Encrypted blob chunked into segments, stored as Monad calldata
86
- - **Zero-knowledge:** Server never sees plaintext data
99
+ - **Key generation:** Client-side, 32-byte random key — never transmitted to DropClaw
100
+ - **IV:** 12-byte random — prepended to ciphertext
101
+ - **Auth tag:** 16-byte GCM tag prepended after IV
102
+ - **Compression:** zlib deflate before encryption
103
+ - **Wire format:** `[IV (12 bytes) | AuthTag (16 bytes) | Ciphertext]` → base64
104
+ - **On-chain storage:** Encrypted blob chunked into segments, stored as Monad calldata
105
+ - **Zero-knowledge:** Server never sees plaintext data or encryption keys
87
106
 
88
107
  ## Example Usage
89
108
 
package/dist/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * DropClaw v1.1.0
2
+ * DropClaw v1.2.0
3
3
  * (c) 2026 Farnsworth Labs — All rights reserved.
4
4
  * PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
5
5
  * This software is protected by international copyright law.
@@ -11,7 +11,7 @@ const path = require("path");
11
11
  const zlib = require("zlib");
12
12
 
13
13
  const DEFAULT_GATEWAY = "https://dropclaw.cloud";
14
- const VERSION = "1.1.0";
14
+ const VERSION = "1.2.0";
15
15
 
16
16
  class DropClawClient {
17
17
  constructor(opts = {}) {
@@ -35,7 +35,11 @@ class DropClawClient {
35
35
 
36
36
  _loadVaultKey() {
37
37
  try {
38
- const vaultPath = path.join(this._vaultDir, "vault.enc");
38
+ // Try new name first, fall back to legacy
39
+ let vaultPath = path.join(this._vaultDir, "vault.json");
40
+ if (!fs.existsSync(vaultPath)) {
41
+ vaultPath = path.join(this._vaultDir, "vault.enc");
42
+ }
39
43
  if (fs.existsSync(vaultPath)) {
40
44
  const data = JSON.parse(fs.readFileSync(vaultPath, "utf8"));
41
45
  if (data.apiKey) this.apiKey = data.apiKey;
@@ -82,7 +86,7 @@ class DropClawClient {
82
86
 
83
87
  async pricing(fileSize) {
84
88
  const resp = await fetch(`${this.gateway}/vault/pricing?size=${fileSize}`);
85
- return resp.json();
89
+ return this._handle(resp);
86
90
  }
87
91
 
88
92
  async getPaymentOptions(fileSize) {
@@ -93,8 +97,14 @@ class DropClawClient {
93
97
  if (!opts.paymentTxHash) {
94
98
  throw new Error("paymentTxHash required. Call pricing() first, send payment, then store().");
95
99
  }
100
+ if (!opts.filePath && !opts.content && !opts.contentBase64) {
101
+ throw new Error("Provide filePath, content, or contentBase64");
102
+ }
96
103
 
97
104
  let contentBase64;
105
+ let keyHex = null;
106
+ const fileName = opts.fileName || (opts.filePath ? path.basename(opts.filePath) : "untitled");
107
+
98
108
  if (opts.filePath) {
99
109
  const raw = fs.readFileSync(opts.filePath);
100
110
  const compressed = zlib.deflateSync(raw);
@@ -104,9 +114,7 @@ class DropClawClient {
104
114
  const encrypted = Buffer.concat([cipher.update(compressed), cipher.final()]);
105
115
  const tag = cipher.getAuthTag();
106
116
  contentBase64 = Buffer.concat([iv, tag, encrypted]).toString("base64");
107
-
108
- // Save key locally
109
- this._saveKey(opts.fileName || path.basename(opts.filePath), key);
117
+ keyHex = key.toString("hex");
110
118
  } else if (opts.content) {
111
119
  const raw = Buffer.isBuffer(opts.content) ? opts.content : Buffer.from(opts.content);
112
120
  const compressed = zlib.deflateSync(raw);
@@ -116,20 +124,25 @@ class DropClawClient {
116
124
  const encrypted = Buffer.concat([cipher.update(compressed), cipher.final()]);
117
125
  const tag = cipher.getAuthTag();
118
126
  contentBase64 = Buffer.concat([iv, tag, encrypted]).toString("base64");
119
-
120
- this._saveKey(opts.fileName || "untitled", key);
127
+ keyHex = key.toString("hex");
121
128
  } else if (opts.contentBase64) {
122
129
  contentBase64 = opts.contentBase64;
123
- } else {
124
- throw new Error("Provide filePath, content, or contentBase64");
125
130
  }
126
131
 
127
- return this._post("/vault/store", {
132
+ const result = await this._post("/vault/store", {
128
133
  content_base64: contentBase64,
129
- file_name: opts.fileName || "untitled",
134
+ file_name: fileName,
130
135
  payment_tx_hash: opts.paymentTxHash,
131
136
  payment_network: opts.paymentNetwork || "eip155:143",
132
137
  });
138
+
139
+ // Save key with file_id AFTER successful API response
140
+ if (keyHex) {
141
+ const fileId = result.fileId || result.file_id || null;
142
+ this._saveKey(fileName, keyHex, fileId);
143
+ }
144
+
145
+ return result;
133
146
  }
134
147
 
135
148
  async retrieve(fileId) {
@@ -146,7 +159,7 @@ class DropClawClient {
146
159
  return [];
147
160
  }
148
161
 
149
- _saveKey(fileName, key) {
162
+ _saveKey(fileName, keyHex, fileId) {
150
163
  try {
151
164
  if (!fs.existsSync(this._vaultDir)) {
152
165
  fs.mkdirSync(this._vaultDir, { recursive: true });
@@ -155,17 +168,22 @@ class DropClawClient {
155
168
  let keys = [];
156
169
  try { keys = JSON.parse(fs.readFileSync(keysPath, "utf8")); } catch {}
157
170
  keys.push({
171
+ fileId: fileId || null,
158
172
  fileName,
159
- key: key.toString("hex"),
173
+ key: keyHex,
160
174
  storedAt: new Date().toISOString(),
161
175
  });
162
176
  fs.writeFileSync(keysPath, JSON.stringify(keys, null, 2));
163
- } catch {}
177
+ } catch (e) {
178
+ console.error("WARNING: Failed to save encryption key locally:", e.message);
179
+ console.error("Your encryption key is:", keyHex);
180
+ console.error("SAVE THIS KEY — without it, your data cannot be recovered.");
181
+ }
164
182
  }
165
183
 
166
184
  async x402Discovery() {
167
185
  const resp = await fetch(`${this.gateway}/.well-known/x402`);
168
- return resp.json();
186
+ return this._handle(resp);
169
187
  }
170
188
  }
171
189
 
@@ -1,16 +1,17 @@
1
1
  /**
2
- * DropClaw Credential Manager v1.1.0
2
+ * DropClaw Credential Manager v1.2.0
3
3
  * (c) 2026 Farnsworth Labs — All rights reserved.
4
4
  * PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
5
5
  */
6
- const fs=require("fs"),path=require("path"),crypto=require("crypto");
6
+ const fs=require("fs"),path=require("path");
7
7
  const VD=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw");
8
- const VP=path.join(VD,"vault.enc");
9
- function load(){try{if(fs.existsSync(VP))return JSON.parse(fs.readFileSync(VP,"utf8"));return null}catch{return null}}
8
+ const VP=path.join(VD,"vault.json");
9
+ const VP_LEGACY=path.join(VD,"vault.enc");
10
+ function load(){try{if(fs.existsSync(VP))return JSON.parse(fs.readFileSync(VP,"utf8"));if(fs.existsSync(VP_LEGACY))return JSON.parse(fs.readFileSync(VP_LEGACY,"utf8"));return null}catch{return null}}
10
11
  function save(data){if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});fs.writeFileSync(VP,JSON.stringify(data,null,2))}
11
12
  function getApiKey(){const v=load();return v?.apiKey||process.env.DROPCLAW_API_KEY||null}
12
13
  function getGateway(){const v=load();return v?.gateway||process.env.DROPCLAW_GATEWAY||"https://dropclaw.cloud"}
13
- function saveKey(fileName,keyHex){const kp=path.join(VD,"keys.json");let ks=[];try{ks=JSON.parse(fs.readFileSync(kp,"utf8"))}catch{}ks.push({fileName,key:keyHex,storedAt:new Date().toISOString()});if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});fs.writeFileSync(kp,JSON.stringify(ks,null,2))}
14
+ function saveKey(fileName,keyHex,fileId){if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});const kp=path.join(VD,"keys.json");let ks=[];try{ks=JSON.parse(fs.readFileSync(kp,"utf8"))}catch{}ks.push({fileId:fileId||null,fileName,key:keyHex,storedAt:new Date().toISOString()});fs.writeFileSync(kp,JSON.stringify(ks,null,2))}
14
15
  function getKeys(){const kp=path.join(VD,"keys.json");try{return JSON.parse(fs.readFileSync(kp,"utf8"))}catch{return[]}}
15
- function revoke(){if(fs.existsSync(VP)){crypto.randomFillSync(Buffer.alloc(256));fs.unlinkSync(VP)}const kp=path.join(VD,"keys.json");if(fs.existsSync(kp))fs.unlinkSync(kp)}
16
+ function revoke(){const files=[VP,VP_LEGACY,path.join(VD,"keys.json")];for(const f of files){if(fs.existsSync(f))fs.unlinkSync(f)}}
16
17
  module.exports={load,save,getApiKey,getGateway,saveKey,getKeys,revoke};
@@ -1,28 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * DropClaw MCP Server v1.1.0
3
+ * DropClaw MCP Server v1.2.0
4
4
  * (c) 2026 Farnsworth Labs — All rights reserved.
5
5
  * PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
6
6
  */
7
7
  import{Server}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema,ListToolsRequestSchema}from"@modelcontextprotocol/sdk/types.js";import fs from"fs";import path from"path";import crypto from"crypto";import zlib from"zlib";
8
- const G=process.env.DROPCLAW_GATEWAY||"https://dropclaw.cloud";const V="1.1.0";
9
- function lk(){try{const p=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw","vault.enc");if(fs.existsSync(p)){return JSON.parse(fs.readFileSync(p,"utf8"))}}catch{}return{}}
8
+ const G=process.env.DROPCLAW_GATEWAY||"https://dropclaw.cloud";const V="1.2.0";
9
+ const VD=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw");
10
+ function lk(){try{const p=path.join(VD,"vault.json");if(fs.existsSync(p)){return JSON.parse(fs.readFileSync(p,"utf8"))}}catch{}try{const p=path.join(VD,"vault.enc");if(fs.existsSync(p)){return JSON.parse(fs.readFileSync(p,"utf8"))}}catch{}return{}}
10
11
  function hd(){const v=lk();const h={"Content-Type":"application/json","X-Client-Version":V};if(v.apiKey)h["Authorization"]=`Bearer ${v.apiKey}`;if(process.env.DROPCLAW_API_KEY)h["Authorization"]=`Bearer ${process.env.DROPCLAW_API_KEY}`;return h}
11
- async function api(m,p,b){const u=`${G}${p}`;const o={method:m,headers:hd()};if(b)o.body=JSON.stringify(b);const r=await fetch(u,o);return r.json()}
12
+ async function api(m,p,b){const u=`${G}${p}`;const o={method:m,headers:hd()};if(m==="GET")delete o.headers["Content-Type"];if(b)o.body=JSON.stringify(b);const r=await fetch(u,o);if(!r.ok){const t=await r.text();let msg;try{msg=JSON.parse(t).error||t}catch{msg=t}throw new Error(`${r.status}: ${msg}`)}return r.json()}
13
+ function saveKey(fileName,keyHex,fileId){if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});const kp=path.join(VD,"keys.json");let ks=[];try{ks=JSON.parse(fs.readFileSync(kp,"utf8"))}catch{}ks.push({fileId:fileId||null,fileName,key:keyHex,storedAt:new Date().toISOString()});fs.writeFileSync(kp,JSON.stringify(ks,null,2))}
14
+ function getKeys(){const kp=path.join(VD,"keys.json");try{return JSON.parse(fs.readFileSync(kp,"utf8"))}catch{return[]}}
12
15
  const server=new Server({name:"dropclaw-mcp",version:V},{capabilities:{tools:{}}});
13
16
  server.setRequestHandler(ListToolsRequestSchema,async()=>({tools:[
14
- {name:"dropclaw_payment_options",description:"STEP 1: Get x402 payment requirements before storing a file. Returns exact amounts in MON, SOL, and USDC with pay-to addresses.",inputSchema:{type:"object",properties:{file_size:{type:"number",description:"File size in bytes"}},required:["file_size"]}},
15
- {name:"dropclaw_store",description:"STEP 2: Store a file permanently on Monad blockchain. Requires payment first. The file is compressed and encrypted locally. Save the returned file ID and encryption key.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to file to store"},content_base64:{type:"string",description:"Base64-encoded content (alternative to file_path)"},file_name:{type:"string",description:"Original filename"},payment_tx_hash:{type:"string",description:"Transaction hash of on-chain payment"},payment_network:{type:"string",enum:["eip155:143","solana","eip155:8453"],description:"Payment network",default:"eip155:143"}},required:["payment_tx_hash"]}},
16
- {name:"dropclaw_retrieve",description:"Retrieve a file from Monad blockchain. FREE — no payment required.",inputSchema:{type:"object",properties:{file_id:{type:"string",description:"File ID from dropclaw_store"},save_to:{type:"string",description:"Path to save file (optional)"}},required:["file_id"]}},
17
- {name:"dropclaw_pricing",description:"Get cost estimates for storing a file. Returns $30 service fee plus estimated gas costs.",inputSchema:{type:"object",properties:{file_size:{type:"number",description:"File size in bytes"}},required:["file_size"]}},
18
- {name:"dropclaw_list",description:"List all files stored via DropClaw that have encryption keys saved locally.",inputSchema:{type:"object",properties:{}}}
17
+ {name:"dropclaw_payment_options",description:"STEP 1: Get x402 payment requirements before storing a file. Returns exact amounts in MON, SOL, and USDC with pay-to addresses. Regular usage: $30 + gas. Syntek subscribers: gas only.",inputSchema:{type:"object",properties:{file_size:{type:"number",description:"File size in bytes"}},required:["file_size"]}},
18
+ {name:"dropclaw_store",description:"STEP 2: Store a file permanently on Monad blockchain. Files go DIRECTLY on-chain as calldata — DropClaw never stores user files. The file is compressed (zlib) and encrypted (AES-256-GCM) client-side before upload. You MUST save the returned file_id and encryption key — these stay with YOU and are the only way to retrieve and decrypt later.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to file to store"},content_base64:{type:"string",description:"Base64-encoded content (alternative to file_path — must be pre-encrypted)"},file_name:{type:"string",description:"Original filename"},payment_tx_hash:{type:"string",description:"Transaction hash of on-chain payment"},payment_network:{type:"string",enum:["eip155:143","solana","eip155:8453"],description:"Payment network",default:"eip155:143"}},required:["payment_tx_hash"]}},
19
+ {name:"dropclaw_retrieve",description:"Retrieve an encrypted file from Monad blockchain. FREE — no payment required. Returns the encrypted blob (base64). Decrypt with your encryption key using the wire format in SKILL.md.",inputSchema:{type:"object",properties:{file_id:{type:"string",description:"File ID returned from dropclaw_store"},save_to:{type:"string",description:"Path to save encrypted blob (optional)"}},required:["file_id"]}},
20
+ {name:"dropclaw_pricing",description:"Get cost estimates for storing a file. Returns $30 USD service fee plus estimated gas costs. Syntek subscribers pay gas only.",inputSchema:{type:"object",properties:{file_size:{type:"number",description:"File size in bytes"}},required:["file_size"]}},
21
+ {name:"dropclaw_list",description:"List all files stored via DropClaw with their encryption keys and file IDs saved locally.",inputSchema:{type:"object",properties:{}}}
19
22
  ]}));
20
23
  server.setRequestHandler(CallToolRequestSchema,async(req)=>{const{name,arguments:args}=req.params;try{
21
- if(name==="dropclaw_payment_options"||name==="dropclaw_pricing"){const r=await api("GET",`/vault/pricing?size=${args.file_size||1000000}`);return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}
22
- if(name==="dropclaw_store"){let cb64=args.content_base64;if(args.file_path&&!cb64){const raw=fs.readFileSync(args.file_path);const comp=zlib.deflateSync(raw);const key=crypto.randomBytes(32);const iv=crypto.randomBytes(12);const c=crypto.createCipheriv("aes-256-gcm",key,iv);const enc=Buffer.concat([c.update(comp),c.final()]);const tag=c.getAuthTag();cb64=Buffer.concat([iv,tag,enc]).toString("base64");const vd=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw");if(!fs.existsSync(vd))fs.mkdirSync(vd,{recursive:true});const kp=path.join(vd,"keys.json");let ks=[];try{ks=JSON.parse(fs.readFileSync(kp,"utf8"))}catch{}ks.push({fileName:args.file_name||path.basename(args.file_path),key:key.toString("hex"),storedAt:new Date().toISOString()});fs.writeFileSync(kp,JSON.stringify(ks,null,2))}
23
- const r=await api("POST","/vault/store",{content_base64:cb64,file_name:args.file_name||"untitled",payment_tx_hash:args.payment_tx_hash,payment_network:args.payment_network||"eip155:143"});return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}
24
- if(name==="dropclaw_retrieve"){const r=await api("POST",`/vault/retrieve/${args.file_id}`,{});if(args.save_to&&r.content_base64){fs.writeFileSync(args.save_to,Buffer.from(r.content_base64,"base64"))}return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}
25
- if(name==="dropclaw_list"){const vd=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw","keys.json");let ks=[];try{ks=JSON.parse(fs.readFileSync(vd,"utf8"))}catch{}return{content:[{type:"text",text:JSON.stringify(ks,null,2)}]}}
24
+ if(name==="dropclaw_payment_options"||name==="dropclaw_pricing"){const sz=args.file_size!==undefined?args.file_size:1000000;const r=await api("GET",`/vault/pricing?size=${sz}`);return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}
25
+ if(name==="dropclaw_store"){if(!args.file_path&&!args.content_base64){return{content:[{type:"text",text:"Error: Provide either file_path or content_base64"}],isError:true}}let cb64=args.content_base64;let keyHex=null;const fn=args.file_name||(args.file_path?path.basename(args.file_path):"untitled");if(args.file_path&&!cb64){const raw=fs.readFileSync(args.file_path);const comp=zlib.deflateSync(raw);const key=crypto.randomBytes(32);const iv=crypto.randomBytes(12);const c=crypto.createCipheriv("aes-256-gcm",key,iv);const enc=Buffer.concat([c.update(comp),c.final()]);const tag=c.getAuthTag();cb64=Buffer.concat([iv,tag,enc]).toString("base64");keyHex=key.toString("hex")}
26
+ const r=await api("POST","/vault/store",{content_base64:cb64,file_name:fn,payment_tx_hash:args.payment_tx_hash,payment_network:args.payment_network||"eip155:143"});if(keyHex&&r.fileId){saveKey(fn,keyHex,r.fileId)}else if(keyHex){saveKey(fn,keyHex,r.file_id||null)}
27
+ return{content:[{type:"text",text:JSON.stringify(r,null,2)+"\n\n⚠️ IMPORTANT: Save the file_id and encryption key. These stay with YOU — DropClaw does not store your keys. Without them, your data cannot be recovered."}]}}
28
+ if(name==="dropclaw_retrieve"){const r=await api("POST",`/vault/retrieve/${args.file_id}`,{});if(r.content_base64&&args.save_to){fs.writeFileSync(args.save_to,Buffer.from(r.content_base64,"base64"))}return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}
29
+ if(name==="dropclaw_list"){return{content:[{type:"text",text:JSON.stringify(getKeys(),null,2)}]}}
26
30
  return{content:[{type:"text",text:`Unknown tool: ${name}`}],isError:true}}catch(e){return{content:[{type:"text",text:`Error: ${e.message}`}],isError:true}}});
27
31
  async function main(){const t=new StdioServerTransport();await server.connect(t)}
28
32
  main().catch(e=>{process.stderr.write(`DropClaw MCP fatal: ${e.message}\n`);process.exit(1)});
package/dist/mcp/setup.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * DropClaw Setup CLI v1.1.0
3
+ * DropClaw Setup CLI v1.2.0
4
4
  * (c) 2026 Farnsworth Labs — All rights reserved.
5
5
  * PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
6
6
  */
7
- const fs=require("fs"),path=require("path"),crypto=require("crypto"),readline=require("readline");
8
- const V="1.1.0",G="https://dropclaw.cloud";
7
+ const fs=require("fs"),path=require("path"),readline=require("readline");
8
+ const V="1.2.0",G="https://dropclaw.cloud";
9
9
  const VD=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw");
10
- const VP=path.join(VD,"vault.enc");
10
+ const VP=path.join(VD,"vault.json");
11
11
  function rl(){return readline.createInterface({input:process.stdin,output:process.stdout})}
12
12
  function ask(r,q){return new Promise(res=>{r.question(q,ans=>{res(ans.trim())})})}
13
13
  async function setup(){
@@ -26,11 +26,12 @@ try{const resp=await fetch(`${gw}/vault/pricing?size=1000`);const d=await resp.j
26
26
  }
27
27
  async function status(){
28
28
  console.log(`\n DropClaw Status v${V}\n ${"─".repeat(30)}\n`);
29
- if(!fs.existsSync(VP)){console.log(" No credentials found. Run: npx dropclaw setup\n");return}
30
- const vault=JSON.parse(fs.readFileSync(VP,"utf8"));
29
+ if(!fs.existsSync(VP)){const legacy=path.join(VD,"vault.enc");if(!fs.existsSync(legacy)){console.log(" No credentials found. Run: npx dropclaw setup\n");return}}
30
+ let vault;
31
+ try{vault=JSON.parse(fs.readFileSync(fs.existsSync(VP)?VP:path.join(VD,"vault.enc"),"utf8"))}catch(e){console.log(` Error reading credentials: ${e.message}\n`);return}
31
32
  const gw=vault.gateway||G;
32
33
  console.log(` Gateway: ${gw}`);
33
- console.log(` API Key: ${vault.apiKey?.slice(0,8)}...`);
34
+ console.log(` API Key: ${vault.apiKey?.slice(0,6)}...`);
34
35
  console.log(` Created: ${vault.createdAt||"unknown"}`);
35
36
  try{const resp=await fetch(`${gw}/vault/pricing?size=1000000`);const d=await resp.json();console.log(` Service: Online`);console.log(` Fee: $${d.serviceFeeUSD} + gas`);console.log(` Chains: MON, SOL, USDC`)}catch(e){console.log(` Service: Offline (${e.message})`)}
36
37
  const kp=path.join(VD,"keys.json");
@@ -38,8 +39,11 @@ try{const ks=JSON.parse(fs.readFileSync(kp,"utf8"));console.log(` Local keys: $
38
39
  console.log();
39
40
  }
40
41
  async function revoke(){
41
- if(fs.existsSync(VP)){crypto.randomFillSync(Buffer.alloc(256));fs.unlinkSync(VP);console.log("\n Credentials securely erased.\n")}
42
- else{console.log("\n No credentials found.\n")}
42
+ const files=[VP,path.join(VD,"vault.enc"),path.join(VD,"keys.json")];
43
+ let erased=false;
44
+ for(const f of files){if(fs.existsSync(f)){fs.unlinkSync(f);erased=true}}
45
+ if(erased){console.log("\n Local credentials removed.");console.log(" Note: On-chain data is immutable and cannot be deleted.");console.log(" If you removed keys.json, encrypted on-chain files are unrecoverable.\n")}
46
+ else console.log("\n No credentials found.\n");
43
47
  }
44
48
  const cmd=process.argv[2]||"setup";
45
49
  if(cmd==="setup")setup().catch(e=>console.error(e.message));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dropclaw",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "DropClaw — Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.",
5
5
  "main": "dist/client.js",
6
6
  "bin": {