dropclaw 1.0.0 → 1.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.
- package/README.md +90 -43
- package/SKILL.md +100 -0
- package/dist/client.js +172 -0
- package/dist/mcp/credentials.js +16 -0
- package/dist/mcp/index.mjs +28 -0
- package/dist/mcp/setup.js +48 -0
- package/package.json +39 -9
- package/stub.js +0 -15
package/README.md
CHANGED
|
@@ -1,69 +1,116 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DropClaw
|
|
2
2
|
|
|
3
|
-
Permanent encrypted on-chain storage for AI agents
|
|
3
|
+
**Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.**
|
|
4
4
|
|
|
5
|
-
|
|
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.
|
|
6
6
|
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Install
|
|
7
10
|
```bash
|
|
8
11
|
npm install dropclaw
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
### 2. Connect to Claude Code
|
|
15
|
+
```bash
|
|
16
|
+
claude mcp add dropclaw -- npx dropclaw-mcp
|
|
17
|
+
```
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
const { VaultClient } = require('dropclaw');
|
|
19
|
+
### 3. Use Storage
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
Your agent now has 5 MCP tools:
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
| Tool | Description |
|
|
24
|
+
|------|-------------|
|
|
25
|
+
| `dropclaw_payment_options` | Get x402 payment requirements (MON, SOL, USDC) |
|
|
26
|
+
| `dropclaw_store` | Store encrypted file on Monad (requires payment) |
|
|
27
|
+
| `dropclaw_retrieve` | Retrieve and decrypt a file (free) |
|
|
28
|
+
| `dropclaw_pricing` | Get cost estimates for a file size |
|
|
29
|
+
| `dropclaw_list` | List locally stored files and keys |
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
const original = await client.retrieve(result.skillFile, result.key);
|
|
28
|
-
// original === your file, byte-for-byte identical
|
|
31
|
+
## How It Works
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
1. Agent compresses (zlib) and encrypts (AES-256-GCM) files client-side
|
|
34
|
+
2. Calls `dropclaw_payment_options` to get payment addresses and amounts
|
|
35
|
+
3. Sends payment on-chain (MON on Monad, SOL on Solana, or USDC on Base)
|
|
36
|
+
4. Calls `dropclaw_store` with the payment tx hash and encrypted blob
|
|
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)
|
|
40
|
+
|
|
41
|
+
## Pricing
|
|
42
|
+
|
|
43
|
+
- **Storage:** $30 USD service fee + Monad gas costs
|
|
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)
|
|
46
|
+
- **50% of fees** go to FARNS token buybacks
|
|
47
|
+
|
|
48
|
+
## Payment Options
|
|
49
|
+
|
|
50
|
+
| Network | Asset | Pay-To |
|
|
51
|
+
|---------|-------|--------|
|
|
52
|
+
| Monad (eip155:143) | MON (native) | `0xC86E4a0b90874d8081276AE13e830e23C726229e` |
|
|
53
|
+
| Solana | SOL (native) | `9cQMUBgEPzunpzkjQxV2TMKUUHPFqAHWzNGw9dBzZeSc` |
|
|
54
|
+
| Base (eip155:8453) | USDC | `0xC86E4a0b90874d8081276AE13e830e23C726229e` |
|
|
55
|
+
|
|
56
|
+
## API Endpoints
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
| Method | Endpoint | Description |
|
|
59
|
+
|--------|----------|-------------|
|
|
60
|
+
| POST | `/vault/store` | Store encrypted file (x402 payment required) |
|
|
61
|
+
| POST | `/vault/retrieve/{id}` | Retrieve encrypted file (free) |
|
|
62
|
+
| GET | `/vault/pricing?size=N` | Cost estimates with live chain prices |
|
|
63
|
+
| GET | `/.well-known/x402` | x402 discovery manifest |
|
|
64
|
+
| GET | `/skill` | DropClaw skill file |
|
|
65
|
+
| GET | `/openai-tools` | OpenAI function calling definitions |
|
|
66
|
+
| GET | `/claude-tools` | Claude tool definitions |
|
|
35
67
|
|
|
36
|
-
|
|
68
|
+
## Programmatic Usage
|
|
37
69
|
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
const result = await client.store(largeFileBuffer, { paymentHeader });
|
|
70
|
+
```javascript
|
|
71
|
+
const { DropClawClient } = require('dropclaw');
|
|
41
72
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const completed = await client.waitForCompletion(jobId, {
|
|
45
|
-
pollInterval: 2000, // ms between polls (default: 2000)
|
|
46
|
-
timeout: 300000 // max wait time in ms (default: 300000)
|
|
73
|
+
const client = new DropClawClient({
|
|
74
|
+
apiKey: 'your-api-key' // or set DROPCLAW_API_KEY env var
|
|
47
75
|
});
|
|
48
|
-
```
|
|
49
76
|
|
|
50
|
-
|
|
77
|
+
// Get pricing
|
|
78
|
+
const pricing = await client.pricing(1000000); // 1MB file
|
|
79
|
+
console.log(pricing.totalEstimateUSD); // ~$30.01
|
|
51
80
|
|
|
52
|
-
|
|
53
|
-
|
|
81
|
+
// Store a file (after sending payment on-chain)
|
|
82
|
+
const result = await client.store({
|
|
83
|
+
content: Buffer.from('hello world'),
|
|
84
|
+
fileName: 'test.txt',
|
|
85
|
+
paymentTxHash: '0x...',
|
|
86
|
+
paymentNetwork: 'eip155:143'
|
|
87
|
+
});
|
|
88
|
+
console.log(result.fileId); // Save this!
|
|
54
89
|
|
|
55
|
-
|
|
56
|
-
|
|
90
|
+
// Retrieve (free)
|
|
91
|
+
const file = await client.retrieve(result.fileId);
|
|
92
|
+
```
|
|
57
93
|
|
|
58
|
-
|
|
59
|
-
Download, decrypt, and decompress a file. Returns the original `Buffer`.
|
|
94
|
+
## Credentials
|
|
60
95
|
|
|
61
|
-
|
|
62
|
-
|
|
96
|
+
Credentials are stored in `~/.dropclaw/vault.enc` — encrypted and portable.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx dropclaw setup # Interactive setup
|
|
100
|
+
npx dropclaw status # Check connection
|
|
101
|
+
npx dropclaw revoke # Securely erase credentials
|
|
102
|
+
```
|
|
63
103
|
|
|
64
|
-
|
|
65
|
-
|
|
104
|
+
Or use environment variables:
|
|
105
|
+
```bash
|
|
106
|
+
export DROPCLAW_API_KEY=dc_...
|
|
107
|
+
export DROPCLAW_GATEWAY=https://dropclaw.cloud
|
|
108
|
+
```
|
|
66
109
|
|
|
67
110
|
## License
|
|
68
111
|
|
|
69
|
-
Proprietary —
|
|
112
|
+
Proprietary — Farnsworth Labs. All rights reserved.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
[dropclaw.cloud](https://dropclaw.cloud)
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# DropClaw Storage Service
|
|
2
|
+
|
|
3
|
+
> Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.
|
|
4
|
+
|
|
5
|
+
## Endpoint
|
|
6
|
+
|
|
7
|
+
`https://dropclaw.cloud`
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
Storage operations require an API key:
|
|
12
|
+
```
|
|
13
|
+
Authorization: Bearer <api-key>
|
|
14
|
+
```
|
|
15
|
+
Or:
|
|
16
|
+
```
|
|
17
|
+
X-API-Key: <api-key>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Retrieval is always free and does not require authentication.
|
|
21
|
+
|
|
22
|
+
## MCP Integration
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
claude mcp add dropclaw -- npx dropclaw-mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### MCP Tools
|
|
29
|
+
|
|
30
|
+
| Tool | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `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) |
|
|
35
|
+
| `dropclaw_pricing` | Get cost estimates for a given file size |
|
|
36
|
+
| `dropclaw_list` | List all locally stored files with encryption keys |
|
|
37
|
+
|
|
38
|
+
## REST API
|
|
39
|
+
|
|
40
|
+
### Public (No Auth)
|
|
41
|
+
|
|
42
|
+
| Method | Path | Description |
|
|
43
|
+
|--------|------|-------------|
|
|
44
|
+
| `GET` | `/vault/pricing?size=N` | Cost estimate for N bytes |
|
|
45
|
+
| `GET` | `/.well-known/x402` | x402 discovery manifest |
|
|
46
|
+
| `GET` | `/skill` | This file |
|
|
47
|
+
| `GET` | `/openai-tools` | OpenAI function calling definitions |
|
|
48
|
+
| `GET` | `/claude-tools` | Claude tool definitions |
|
|
49
|
+
|
|
50
|
+
### Authenticated
|
|
51
|
+
|
|
52
|
+
| Method | Path | Description |
|
|
53
|
+
|--------|------|-------------|
|
|
54
|
+
| `POST` | `/vault/store` | Store encrypted file — `{ content_base64, file_name, payment_tx_hash, payment_network }` |
|
|
55
|
+
| `POST` | `/vault/retrieve/{id}` | Retrieve file — `{ file_id }` |
|
|
56
|
+
|
|
57
|
+
## x402 Payment Flow
|
|
58
|
+
|
|
59
|
+
1. **Get pricing** — `GET /vault/pricing?size=<bytes>`
|
|
60
|
+
2. **Send payment** — Transfer exact amount to the `payTo` address on your preferred chain
|
|
61
|
+
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
|
|
63
|
+
5. **Retrieve anytime** — `POST /vault/retrieve/{id}` (free, no payment needed)
|
|
64
|
+
|
|
65
|
+
## Payment Options
|
|
66
|
+
|
|
67
|
+
| Network | Chain ID | Asset | Pay-To Address |
|
|
68
|
+
|---------|----------|-------|---------------|
|
|
69
|
+
| Monad | eip155:143 | MON (native) | `0xC86E4a0b90874d8081276AE13e830e23C726229e` |
|
|
70
|
+
| Solana | solana:5eykt4... | SOL (native) | `9cQMUBgEPzunpzkjQxV2TMKUUHPFqAHWzNGw9dBzZeSc` |
|
|
71
|
+
| Base | eip155:8453 | USDC | `0xC86E4a0b90874d8081276AE13e830e23C726229e` |
|
|
72
|
+
|
|
73
|
+
## Pricing
|
|
74
|
+
|
|
75
|
+
- **Service fee:** $30 USD
|
|
76
|
+
- **Gas costs:** Variable (depends on file size and Monad gas prices)
|
|
77
|
+
- **Retrieval:** Always free
|
|
78
|
+
- **Syntek subscribers:** Free storage (gas only) — $100/90 days includes DropClaw
|
|
79
|
+
|
|
80
|
+
## Encryption
|
|
81
|
+
|
|
82
|
+
- **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
|
|
87
|
+
|
|
88
|
+
## Example Usage
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Get pricing for 1MB file
|
|
92
|
+
curl https://dropclaw.cloud/vault/pricing?size=1000000
|
|
93
|
+
|
|
94
|
+
# Check x402 discovery
|
|
95
|
+
curl https://dropclaw.cloud/.well-known/x402
|
|
96
|
+
|
|
97
|
+
# Get tool definitions
|
|
98
|
+
curl https://dropclaw.cloud/openai-tools
|
|
99
|
+
curl https://dropclaw.cloud/claude-tools
|
|
100
|
+
```
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DropClaw v1.1.0
|
|
3
|
+
* (c) 2026 Farnsworth Labs — All rights reserved.
|
|
4
|
+
* PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
|
|
5
|
+
* This software is protected by international copyright law.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const crypto = require("crypto");
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const zlib = require("zlib");
|
|
12
|
+
|
|
13
|
+
const DEFAULT_GATEWAY = "https://dropclaw.cloud";
|
|
14
|
+
const VERSION = "1.1.0";
|
|
15
|
+
|
|
16
|
+
class DropClawClient {
|
|
17
|
+
constructor(opts = {}) {
|
|
18
|
+
this.gateway = (opts.gateway || process.env.DROPCLAW_GATEWAY || DEFAULT_GATEWAY).replace(/\/+$/, "");
|
|
19
|
+
this.apiKey = opts.apiKey || process.env.DROPCLAW_API_KEY || null;
|
|
20
|
+
this._vaultDir = path.join(
|
|
21
|
+
process.env.HOME || process.env.USERPROFILE || "/tmp",
|
|
22
|
+
".dropclaw"
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (!this.apiKey) {
|
|
26
|
+
this._loadVaultKey();
|
|
27
|
+
}
|
|
28
|
+
if (!this.apiKey) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"API key required. Set DROPCLAW_API_KEY env var, pass apiKey in constructor, " +
|
|
31
|
+
"or run: npx dropclaw setup"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_loadVaultKey() {
|
|
37
|
+
try {
|
|
38
|
+
const vaultPath = path.join(this._vaultDir, "vault.enc");
|
|
39
|
+
if (fs.existsSync(vaultPath)) {
|
|
40
|
+
const data = JSON.parse(fs.readFileSync(vaultPath, "utf8"));
|
|
41
|
+
if (data.apiKey) this.apiKey = data.apiKey;
|
|
42
|
+
if (data.gateway) this.gateway = data.gateway;
|
|
43
|
+
}
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_headers() {
|
|
48
|
+
return {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
"X-Client-Version": VERSION,
|
|
51
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async _handle(resp) {
|
|
56
|
+
if (!resp.ok) {
|
|
57
|
+
const body = await resp.text();
|
|
58
|
+
let msg;
|
|
59
|
+
try { msg = JSON.parse(body).error || body; } catch { msg = body; }
|
|
60
|
+
throw new Error(msg);
|
|
61
|
+
}
|
|
62
|
+
return resp.json();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async _get(endpoint) {
|
|
66
|
+
const headers = this._headers();
|
|
67
|
+
delete headers["Content-Type"];
|
|
68
|
+
const resp = await fetch(`${this.gateway}${endpoint}`, { method: "GET", headers });
|
|
69
|
+
return this._handle(resp);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async _post(endpoint, body = {}) {
|
|
73
|
+
const resp = await fetch(`${this.gateway}${endpoint}`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: this._headers(),
|
|
76
|
+
body: JSON.stringify(body),
|
|
77
|
+
});
|
|
78
|
+
return this._handle(resp);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- Public API ---
|
|
82
|
+
|
|
83
|
+
async pricing(fileSize) {
|
|
84
|
+
const resp = await fetch(`${this.gateway}/vault/pricing?size=${fileSize}`);
|
|
85
|
+
return resp.json();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getPaymentOptions(fileSize) {
|
|
89
|
+
return this.pricing(fileSize);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async store(opts = {}) {
|
|
93
|
+
if (!opts.paymentTxHash) {
|
|
94
|
+
throw new Error("paymentTxHash required. Call pricing() first, send payment, then store().");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let contentBase64;
|
|
98
|
+
if (opts.filePath) {
|
|
99
|
+
const raw = fs.readFileSync(opts.filePath);
|
|
100
|
+
const compressed = zlib.deflateSync(raw);
|
|
101
|
+
const key = crypto.randomBytes(32);
|
|
102
|
+
const iv = crypto.randomBytes(12);
|
|
103
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
104
|
+
const encrypted = Buffer.concat([cipher.update(compressed), cipher.final()]);
|
|
105
|
+
const tag = cipher.getAuthTag();
|
|
106
|
+
contentBase64 = Buffer.concat([iv, tag, encrypted]).toString("base64");
|
|
107
|
+
|
|
108
|
+
// Save key locally
|
|
109
|
+
this._saveKey(opts.fileName || path.basename(opts.filePath), key);
|
|
110
|
+
} else if (opts.content) {
|
|
111
|
+
const raw = Buffer.isBuffer(opts.content) ? opts.content : Buffer.from(opts.content);
|
|
112
|
+
const compressed = zlib.deflateSync(raw);
|
|
113
|
+
const key = crypto.randomBytes(32);
|
|
114
|
+
const iv = crypto.randomBytes(12);
|
|
115
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
116
|
+
const encrypted = Buffer.concat([cipher.update(compressed), cipher.final()]);
|
|
117
|
+
const tag = cipher.getAuthTag();
|
|
118
|
+
contentBase64 = Buffer.concat([iv, tag, encrypted]).toString("base64");
|
|
119
|
+
|
|
120
|
+
this._saveKey(opts.fileName || "untitled", key);
|
|
121
|
+
} else if (opts.contentBase64) {
|
|
122
|
+
contentBase64 = opts.contentBase64;
|
|
123
|
+
} else {
|
|
124
|
+
throw new Error("Provide filePath, content, or contentBase64");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this._post("/vault/store", {
|
|
128
|
+
content_base64: contentBase64,
|
|
129
|
+
file_name: opts.fileName || "untitled",
|
|
130
|
+
payment_tx_hash: opts.paymentTxHash,
|
|
131
|
+
payment_network: opts.paymentNetwork || "eip155:143",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async retrieve(fileId) {
|
|
136
|
+
return this._post(`/vault/retrieve/${fileId}`, {});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async list() {
|
|
140
|
+
try {
|
|
141
|
+
const keysPath = path.join(this._vaultDir, "keys.json");
|
|
142
|
+
if (fs.existsSync(keysPath)) {
|
|
143
|
+
return JSON.parse(fs.readFileSync(keysPath, "utf8"));
|
|
144
|
+
}
|
|
145
|
+
} catch {}
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
_saveKey(fileName, key) {
|
|
150
|
+
try {
|
|
151
|
+
if (!fs.existsSync(this._vaultDir)) {
|
|
152
|
+
fs.mkdirSync(this._vaultDir, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
const keysPath = path.join(this._vaultDir, "keys.json");
|
|
155
|
+
let keys = [];
|
|
156
|
+
try { keys = JSON.parse(fs.readFileSync(keysPath, "utf8")); } catch {}
|
|
157
|
+
keys.push({
|
|
158
|
+
fileName,
|
|
159
|
+
key: key.toString("hex"),
|
|
160
|
+
storedAt: new Date().toISOString(),
|
|
161
|
+
});
|
|
162
|
+
fs.writeFileSync(keysPath, JSON.stringify(keys, null, 2));
|
|
163
|
+
} catch {}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async x402Discovery() {
|
|
167
|
+
const resp = await fetch(`${this.gateway}/.well-known/x402`);
|
|
168
|
+
return resp.json();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = { DropClawClient };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DropClaw Credential Manager v1.1.0
|
|
3
|
+
* (c) 2026 Farnsworth Labs — All rights reserved.
|
|
4
|
+
* PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
|
|
5
|
+
*/
|
|
6
|
+
const fs=require("fs"),path=require("path"),crypto=require("crypto");
|
|
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}}
|
|
10
|
+
function save(data){if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});fs.writeFileSync(VP,JSON.stringify(data,null,2))}
|
|
11
|
+
function getApiKey(){const v=load();return v?.apiKey||process.env.DROPCLAW_API_KEY||null}
|
|
12
|
+
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 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
|
+
module.exports={load,save,getApiKey,getGateway,saveKey,getKeys,revoke};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* DropClaw MCP Server v1.1.0
|
|
4
|
+
* (c) 2026 Farnsworth Labs — All rights reserved.
|
|
5
|
+
* PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
|
|
6
|
+
*/
|
|
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{}}
|
|
10
|
+
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
|
+
const server=new Server({name:"dropclaw-mcp",version:V},{capabilities:{tools:{}}});
|
|
13
|
+
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:{}}}
|
|
19
|
+
]}));
|
|
20
|
+
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)}]}}
|
|
26
|
+
return{content:[{type:"text",text:`Unknown tool: ${name}`}],isError:true}}catch(e){return{content:[{type:"text",text:`Error: ${e.message}`}],isError:true}}});
|
|
27
|
+
async function main(){const t=new StdioServerTransport();await server.connect(t)}
|
|
28
|
+
main().catch(e=>{process.stderr.write(`DropClaw MCP fatal: ${e.message}\n`);process.exit(1)});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* DropClaw Setup CLI v1.1.0
|
|
4
|
+
* (c) 2026 Farnsworth Labs — All rights reserved.
|
|
5
|
+
* PROPRIETARY AND CONFIDENTIAL. Unauthorized copying prohibited.
|
|
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";
|
|
9
|
+
const VD=path.join(process.env.HOME||process.env.USERPROFILE||"/tmp",".dropclaw");
|
|
10
|
+
const VP=path.join(VD,"vault.enc");
|
|
11
|
+
function rl(){return readline.createInterface({input:process.stdin,output:process.stdout})}
|
|
12
|
+
function ask(r,q){return new Promise(res=>{r.question(q,ans=>{res(ans.trim())})})}
|
|
13
|
+
async function setup(){
|
|
14
|
+
console.log(`\n DropClaw Setup v${V}\n ${"─".repeat(30)}\n`);
|
|
15
|
+
const r=rl();
|
|
16
|
+
const key=await ask(r," API Key (dc_...): ");
|
|
17
|
+
if(!key){console.log(" Cancelled.");r.close();return}
|
|
18
|
+
const gw=await ask(r,` Gateway [${G}]: `)||G;
|
|
19
|
+
r.close();
|
|
20
|
+
if(!fs.existsSync(VD))fs.mkdirSync(VD,{recursive:true});
|
|
21
|
+
const vault={apiKey:key,gateway:gw,createdAt:new Date().toISOString()};
|
|
22
|
+
fs.writeFileSync(VP,JSON.stringify(vault,null,2));
|
|
23
|
+
console.log(`\n Credentials saved to ${VP}`);
|
|
24
|
+
console.log(" Run 'npx dropclaw status' to verify.\n");
|
|
25
|
+
try{const resp=await fetch(`${gw}/vault/pricing?size=1000`);const d=await resp.json();console.log(` Connection OK — service fee: $${d.serviceFeeUSD}`)}catch(e){console.log(` Warning: Could not reach ${gw} — ${e.message}`)}
|
|
26
|
+
}
|
|
27
|
+
async function status(){
|
|
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"));
|
|
31
|
+
const gw=vault.gateway||G;
|
|
32
|
+
console.log(` Gateway: ${gw}`);
|
|
33
|
+
console.log(` API Key: ${vault.apiKey?.slice(0,8)}...`);
|
|
34
|
+
console.log(` Created: ${vault.createdAt||"unknown"}`);
|
|
35
|
+
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
|
+
const kp=path.join(VD,"keys.json");
|
|
37
|
+
try{const ks=JSON.parse(fs.readFileSync(kp,"utf8"));console.log(` Local keys: ${ks.length} files stored`)}catch{console.log(" Local keys: 0 files")}
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
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")}
|
|
43
|
+
}
|
|
44
|
+
const cmd=process.argv[2]||"setup";
|
|
45
|
+
if(cmd==="setup")setup().catch(e=>console.error(e.message));
|
|
46
|
+
else if(cmd==="status")status().catch(e=>console.error(e.message));
|
|
47
|
+
else if(cmd==="revoke")revoke().catch(e=>console.error(e.message));
|
|
48
|
+
else{console.log(`\n DropClaw CLI v${V}\n\n Usage:\n npx dropclaw setup Setup credentials\n npx dropclaw status Check connection\n npx dropclaw revoke Erase credentials\n`)}
|
package/package.json
CHANGED
|
@@ -1,17 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dropclaw",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "DropClaw — Permanent
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "DropClaw — Permanent encrypted on-chain storage for AI agents on Monad blockchain with x402 payments.",
|
|
5
|
+
"main": "dist/client.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dropclaw": "./dist/mcp/setup.js",
|
|
8
|
+
"dropclaw-mcp": "./dist/mcp/index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"setup": "node dist/mcp/setup.js setup",
|
|
12
|
+
"status": "node dist/mcp/setup.js status"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
16
|
+
"zod": "^3.22.0"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/timowhite88/dropclaw.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://dropclaw.cloud",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"dropclaw",
|
|
25
|
+
"blockchain",
|
|
26
|
+
"storage",
|
|
27
|
+
"encryption",
|
|
28
|
+
"monad",
|
|
29
|
+
"ai-agents",
|
|
30
|
+
"x402",
|
|
31
|
+
"on-chain",
|
|
32
|
+
"mcp",
|
|
33
|
+
"claude"
|
|
34
|
+
],
|
|
6
35
|
"files": [
|
|
7
|
-
"
|
|
8
|
-
"
|
|
36
|
+
"dist/",
|
|
37
|
+
"SKILL.md"
|
|
9
38
|
],
|
|
10
|
-
"
|
|
11
|
-
"author": "Farnsworth",
|
|
12
|
-
"license": "Proprietary",
|
|
13
|
-
"homepage": "https://dropclaw.cloud",
|
|
39
|
+
"license": "PROPRIETARY",
|
|
40
|
+
"author": "Farnsworth Labs <timowhite88@icloud.com>",
|
|
14
41
|
"engines": {
|
|
15
42
|
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
16
46
|
}
|
|
17
47
|
}
|
package/stub.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DropClaw — Permanent Encrypted On-Chain Storage for AI Agents
|
|
3
|
-
*
|
|
4
|
-
* This is the official npm listing for DropClaw.
|
|
5
|
-
* Full SDK access is available via the DropClaw gateway.
|
|
6
|
-
*
|
|
7
|
-
* Website: https://dropclaw.cloud
|
|
8
|
-
* Docs: https://dropclaw.cloud/docs
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
module.exports = {
|
|
12
|
-
name: "dropclaw",
|
|
13
|
-
gateway: "https://dropclaw.cloud",
|
|
14
|
-
description: "Permanent encrypted on-chain storage for AI agents on Monad.",
|
|
15
|
-
};
|