@fil-b/foc-storage-mcp 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -14
- package/dist/{mcp-server.js → stdio.js} +437 -281
- package/package.json +4 -4
- /package/dist/{mcp-server.d.ts → stdio.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -45,11 +45,24 @@ After installation, update `PRIVATE_KEY` in your config. [Learn more](https://cu
|
|
|
45
45
|
|
|
46
46
|
### Claude Code
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
Add to `.mcp.json`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"foc-storage": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["-y", "@fil-b/foc-storage-mcp"],
|
|
56
|
+
"env": {
|
|
57
|
+
"PRIVATE_KEY": "your_private_key_here",
|
|
58
|
+
"FILECOIN_NETWORK": "calibration"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
50
63
|
```
|
|
51
64
|
|
|
52
|
-
|
|
65
|
+
[Learn more](https://docs.claude.com/en/docs/claude-code/mcp)
|
|
53
66
|
|
|
54
67
|
### Claude Desktop
|
|
55
68
|
|
|
@@ -188,17 +201,6 @@ Ask naturally in Claude, Cursor, or any MCP client:
|
|
|
188
201
|
|
|
189
202
|
## Troubleshooting
|
|
190
203
|
|
|
191
|
-
**"Unexpected token 'with'" or import syntax error:**
|
|
192
|
-
|
|
193
|
-
1. Verify Node.js >= 20.10.0: `node --version`
|
|
194
|
-
2. Clear npx cache:
|
|
195
|
-
- Command: `npx clear-npx-cache`
|
|
196
|
-
- Windows: Delete `%LOCALAPPDATA%\npm-cache\_npx`
|
|
197
|
-
- Linux/Mac: Delete `~/.npm/_npx`
|
|
198
|
-
3. Force fresh install: `npx --yes @fil-b/foc-storage-mcp@latest`
|
|
199
|
-
4. Restart your IDE
|
|
200
|
-
5. If issue persists, check IDE is using correct Node version
|
|
201
|
-
|
|
202
204
|
**Server not found:** Verify `npx --version`, check JSON syntax, restart IDE
|
|
203
205
|
|
|
204
206
|
**"PRIVATE_KEY is required":** Add to `env` section, must start with `0x`
|
|
@@ -1,17 +1,437 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
+
mod
|
|
32
|
+
));
|
|
33
|
+
|
|
34
|
+
// node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/package.json
|
|
35
|
+
var require_package = __commonJS({
|
|
36
|
+
"node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/package.json"(exports, module) {
|
|
37
|
+
module.exports = {
|
|
38
|
+
name: "dotenv",
|
|
39
|
+
version: "17.2.3",
|
|
40
|
+
description: "Loads environment variables from .env file",
|
|
41
|
+
main: "lib/main.js",
|
|
42
|
+
types: "lib/main.d.ts",
|
|
43
|
+
exports: {
|
|
44
|
+
".": {
|
|
45
|
+
types: "./lib/main.d.ts",
|
|
46
|
+
require: "./lib/main.js",
|
|
47
|
+
default: "./lib/main.js"
|
|
48
|
+
},
|
|
49
|
+
"./config": "./config.js",
|
|
50
|
+
"./config.js": "./config.js",
|
|
51
|
+
"./lib/env-options": "./lib/env-options.js",
|
|
52
|
+
"./lib/env-options.js": "./lib/env-options.js",
|
|
53
|
+
"./lib/cli-options": "./lib/cli-options.js",
|
|
54
|
+
"./lib/cli-options.js": "./lib/cli-options.js",
|
|
55
|
+
"./package.json": "./package.json"
|
|
56
|
+
},
|
|
57
|
+
scripts: {
|
|
58
|
+
"dts-check": "tsc --project tests/types/tsconfig.json",
|
|
59
|
+
lint: "standard",
|
|
60
|
+
pretest: "npm run lint && npm run dts-check",
|
|
61
|
+
test: "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
|
|
62
|
+
"test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
|
|
63
|
+
prerelease: "npm test",
|
|
64
|
+
release: "standard-version"
|
|
65
|
+
},
|
|
66
|
+
repository: {
|
|
67
|
+
type: "git",
|
|
68
|
+
url: "git://github.com/motdotla/dotenv.git"
|
|
69
|
+
},
|
|
70
|
+
homepage: "https://github.com/motdotla/dotenv#readme",
|
|
71
|
+
funding: "https://dotenvx.com",
|
|
72
|
+
keywords: [
|
|
73
|
+
"dotenv",
|
|
74
|
+
"env",
|
|
75
|
+
".env",
|
|
76
|
+
"environment",
|
|
77
|
+
"variables",
|
|
78
|
+
"config",
|
|
79
|
+
"settings"
|
|
80
|
+
],
|
|
81
|
+
readmeFilename: "README.md",
|
|
82
|
+
license: "BSD-2-Clause",
|
|
83
|
+
devDependencies: {
|
|
84
|
+
"@types/node": "^18.11.3",
|
|
85
|
+
decache: "^4.6.2",
|
|
86
|
+
sinon: "^14.0.1",
|
|
87
|
+
standard: "^17.0.0",
|
|
88
|
+
"standard-version": "^9.5.0",
|
|
89
|
+
tap: "^19.2.0",
|
|
90
|
+
typescript: "^4.8.4"
|
|
91
|
+
},
|
|
92
|
+
engines: {
|
|
93
|
+
node: ">=12"
|
|
94
|
+
},
|
|
95
|
+
browser: {
|
|
96
|
+
fs: false
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
2
101
|
|
|
3
|
-
//
|
|
4
|
-
|
|
102
|
+
// node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/lib/main.js
|
|
103
|
+
var require_main = __commonJS({
|
|
104
|
+
"node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
105
|
+
"use strict";
|
|
106
|
+
var fs3 = __require("fs");
|
|
107
|
+
var path = __require("path");
|
|
108
|
+
var os = __require("os");
|
|
109
|
+
var crypto = __require("crypto");
|
|
110
|
+
var packageJson = require_package();
|
|
111
|
+
var version = packageJson.version;
|
|
112
|
+
var TIPS = [
|
|
113
|
+
"\u{1F510} encrypt with Dotenvx: https://dotenvx.com",
|
|
114
|
+
"\u{1F510} prevent committing .env to code: https://dotenvx.com/precommit",
|
|
115
|
+
"\u{1F510} prevent building .env in docker: https://dotenvx.com/prebuild",
|
|
116
|
+
"\u{1F4E1} add observability to secrets: https://dotenvx.com/ops",
|
|
117
|
+
"\u{1F465} sync secrets across teammates & machines: https://dotenvx.com/ops",
|
|
118
|
+
"\u{1F5C2}\uFE0F backup and recover secrets: https://dotenvx.com/ops",
|
|
119
|
+
"\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
|
|
120
|
+
"\u{1F504} add secrets lifecycle management: https://dotenvx.com/ops",
|
|
121
|
+
"\u{1F511} add access controls to secrets: https://dotenvx.com/ops",
|
|
122
|
+
"\u{1F6E0}\uFE0F run anywhere with `dotenvx run -- yourcommand`",
|
|
123
|
+
"\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
|
|
124
|
+
"\u2699\uFE0F enable debug logging with { debug: true }",
|
|
125
|
+
"\u2699\uFE0F override existing env vars with { override: true }",
|
|
126
|
+
"\u2699\uFE0F suppress all logs with { quiet: true }",
|
|
127
|
+
"\u2699\uFE0F write to custom object with { processEnv: myObject }",
|
|
128
|
+
"\u2699\uFE0F load multiple .env files with { path: ['.env.local', '.env'] }"
|
|
129
|
+
];
|
|
130
|
+
function _getRandomTip() {
|
|
131
|
+
return TIPS[Math.floor(Math.random() * TIPS.length)];
|
|
132
|
+
}
|
|
133
|
+
function parseBoolean(value) {
|
|
134
|
+
if (typeof value === "string") {
|
|
135
|
+
return !["false", "0", "no", "off", ""].includes(value.toLowerCase());
|
|
136
|
+
}
|
|
137
|
+
return Boolean(value);
|
|
138
|
+
}
|
|
139
|
+
function supportsAnsi() {
|
|
140
|
+
return process.stdout.isTTY;
|
|
141
|
+
}
|
|
142
|
+
function dim(text) {
|
|
143
|
+
return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
|
|
144
|
+
}
|
|
145
|
+
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
146
|
+
function parse(src) {
|
|
147
|
+
const obj = {};
|
|
148
|
+
let lines = src.toString();
|
|
149
|
+
lines = lines.replace(/\r\n?/mg, "\n");
|
|
150
|
+
let match;
|
|
151
|
+
while ((match = LINE.exec(lines)) != null) {
|
|
152
|
+
const key = match[1];
|
|
153
|
+
let value = match[2] || "";
|
|
154
|
+
value = value.trim();
|
|
155
|
+
const maybeQuote = value[0];
|
|
156
|
+
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
|
|
157
|
+
if (maybeQuote === '"') {
|
|
158
|
+
value = value.replace(/\\n/g, "\n");
|
|
159
|
+
value = value.replace(/\\r/g, "\r");
|
|
160
|
+
}
|
|
161
|
+
obj[key] = value;
|
|
162
|
+
}
|
|
163
|
+
return obj;
|
|
164
|
+
}
|
|
165
|
+
function _parseVault(options) {
|
|
166
|
+
options = options || {};
|
|
167
|
+
const vaultPath = _vaultPath(options);
|
|
168
|
+
options.path = vaultPath;
|
|
169
|
+
const result = DotenvModule.configDotenv(options);
|
|
170
|
+
if (!result.parsed) {
|
|
171
|
+
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
|
|
172
|
+
err.code = "MISSING_DATA";
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
const keys = _dotenvKey(options).split(",");
|
|
176
|
+
const length = keys.length;
|
|
177
|
+
let decrypted;
|
|
178
|
+
for (let i = 0; i < length; i++) {
|
|
179
|
+
try {
|
|
180
|
+
const key = keys[i].trim();
|
|
181
|
+
const attrs = _instructions(result, key);
|
|
182
|
+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
|
|
183
|
+
break;
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (i + 1 >= length) {
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return DotenvModule.parse(decrypted);
|
|
191
|
+
}
|
|
192
|
+
function _warn(message) {
|
|
193
|
+
console.error(`[dotenv@${version}][WARN] ${message}`);
|
|
194
|
+
}
|
|
195
|
+
function _debug(message) {
|
|
196
|
+
console.log(`[dotenv@${version}][DEBUG] ${message}`);
|
|
197
|
+
}
|
|
198
|
+
function _log(message) {
|
|
199
|
+
console.log(`[dotenv@${version}] ${message}`);
|
|
200
|
+
}
|
|
201
|
+
function _dotenvKey(options) {
|
|
202
|
+
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
203
|
+
return options.DOTENV_KEY;
|
|
204
|
+
}
|
|
205
|
+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
|
|
206
|
+
return process.env.DOTENV_KEY;
|
|
207
|
+
}
|
|
208
|
+
return "";
|
|
209
|
+
}
|
|
210
|
+
function _instructions(result, dotenvKey) {
|
|
211
|
+
let uri;
|
|
212
|
+
try {
|
|
213
|
+
uri = new URL(dotenvKey);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (error.code === "ERR_INVALID_URL") {
|
|
216
|
+
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
|
|
217
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
218
|
+
throw err;
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
const key = uri.password;
|
|
223
|
+
if (!key) {
|
|
224
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
|
|
225
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
226
|
+
throw err;
|
|
227
|
+
}
|
|
228
|
+
const environment = uri.searchParams.get("environment");
|
|
229
|
+
if (!environment) {
|
|
230
|
+
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
|
|
231
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
232
|
+
throw err;
|
|
233
|
+
}
|
|
234
|
+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
|
|
235
|
+
const ciphertext = result.parsed[environmentKey];
|
|
236
|
+
if (!ciphertext) {
|
|
237
|
+
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
|
|
238
|
+
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
return { ciphertext, key };
|
|
242
|
+
}
|
|
243
|
+
function _vaultPath(options) {
|
|
244
|
+
let possibleVaultPath = null;
|
|
245
|
+
if (options && options.path && options.path.length > 0) {
|
|
246
|
+
if (Array.isArray(options.path)) {
|
|
247
|
+
for (const filepath of options.path) {
|
|
248
|
+
if (fs3.existsSync(filepath)) {
|
|
249
|
+
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
|
|
257
|
+
}
|
|
258
|
+
if (fs3.existsSync(possibleVaultPath)) {
|
|
259
|
+
return possibleVaultPath;
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
function _resolveHome(envPath) {
|
|
264
|
+
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
265
|
+
}
|
|
266
|
+
function _configVault(options) {
|
|
267
|
+
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
268
|
+
const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
269
|
+
if (debug || !quiet) {
|
|
270
|
+
_log("Loading env from encrypted .env.vault");
|
|
271
|
+
}
|
|
272
|
+
const parsed = DotenvModule._parseVault(options);
|
|
273
|
+
let processEnv = process.env;
|
|
274
|
+
if (options && options.processEnv != null) {
|
|
275
|
+
processEnv = options.processEnv;
|
|
276
|
+
}
|
|
277
|
+
DotenvModule.populate(processEnv, parsed, options);
|
|
278
|
+
return { parsed };
|
|
279
|
+
}
|
|
280
|
+
function configDotenv(options) {
|
|
281
|
+
const dotenvPath = path.resolve(process.cwd(), ".env");
|
|
282
|
+
let encoding = "utf8";
|
|
283
|
+
let processEnv = process.env;
|
|
284
|
+
if (options && options.processEnv != null) {
|
|
285
|
+
processEnv = options.processEnv;
|
|
286
|
+
}
|
|
287
|
+
let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
288
|
+
let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
|
|
289
|
+
if (options && options.encoding) {
|
|
290
|
+
encoding = options.encoding;
|
|
291
|
+
} else {
|
|
292
|
+
if (debug) {
|
|
293
|
+
_debug("No encoding is specified. UTF-8 is used by default");
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
let optionPaths = [dotenvPath];
|
|
297
|
+
if (options && options.path) {
|
|
298
|
+
if (!Array.isArray(options.path)) {
|
|
299
|
+
optionPaths = [_resolveHome(options.path)];
|
|
300
|
+
} else {
|
|
301
|
+
optionPaths = [];
|
|
302
|
+
for (const filepath of options.path) {
|
|
303
|
+
optionPaths.push(_resolveHome(filepath));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
let lastError;
|
|
308
|
+
const parsedAll = {};
|
|
309
|
+
for (const path2 of optionPaths) {
|
|
310
|
+
try {
|
|
311
|
+
const parsed = DotenvModule.parse(fs3.readFileSync(path2, { encoding }));
|
|
312
|
+
DotenvModule.populate(parsedAll, parsed, options);
|
|
313
|
+
} catch (e) {
|
|
314
|
+
if (debug) {
|
|
315
|
+
_debug(`Failed to load ${path2} ${e.message}`);
|
|
316
|
+
}
|
|
317
|
+
lastError = e;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const populated = DotenvModule.populate(processEnv, parsedAll, options);
|
|
321
|
+
debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
|
|
322
|
+
quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
|
|
323
|
+
if (debug || !quiet) {
|
|
324
|
+
const keysCount = Object.keys(populated).length;
|
|
325
|
+
const shortPaths = [];
|
|
326
|
+
for (const filePath of optionPaths) {
|
|
327
|
+
try {
|
|
328
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
329
|
+
shortPaths.push(relative);
|
|
330
|
+
} catch (e) {
|
|
331
|
+
if (debug) {
|
|
332
|
+
_debug(`Failed to load ${filePath} ${e.message}`);
|
|
333
|
+
}
|
|
334
|
+
lastError = e;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
|
|
338
|
+
}
|
|
339
|
+
if (lastError) {
|
|
340
|
+
return { parsed: parsedAll, error: lastError };
|
|
341
|
+
} else {
|
|
342
|
+
return { parsed: parsedAll };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function config2(options) {
|
|
346
|
+
if (_dotenvKey(options).length === 0) {
|
|
347
|
+
return DotenvModule.configDotenv(options);
|
|
348
|
+
}
|
|
349
|
+
const vaultPath = _vaultPath(options);
|
|
350
|
+
if (!vaultPath) {
|
|
351
|
+
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
|
|
352
|
+
return DotenvModule.configDotenv(options);
|
|
353
|
+
}
|
|
354
|
+
return DotenvModule._configVault(options);
|
|
355
|
+
}
|
|
356
|
+
function decrypt(encrypted, keyStr) {
|
|
357
|
+
const key = Buffer.from(keyStr.slice(-64), "hex");
|
|
358
|
+
let ciphertext = Buffer.from(encrypted, "base64");
|
|
359
|
+
const nonce = ciphertext.subarray(0, 12);
|
|
360
|
+
const authTag = ciphertext.subarray(-16);
|
|
361
|
+
ciphertext = ciphertext.subarray(12, -16);
|
|
362
|
+
try {
|
|
363
|
+
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
364
|
+
aesgcm.setAuthTag(authTag);
|
|
365
|
+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
366
|
+
} catch (error) {
|
|
367
|
+
const isRange = error instanceof RangeError;
|
|
368
|
+
const invalidKeyLength = error.message === "Invalid key length";
|
|
369
|
+
const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
|
|
370
|
+
if (isRange || invalidKeyLength) {
|
|
371
|
+
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
|
|
372
|
+
err.code = "INVALID_DOTENV_KEY";
|
|
373
|
+
throw err;
|
|
374
|
+
} else if (decryptionFailed) {
|
|
375
|
+
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
|
|
376
|
+
err.code = "DECRYPTION_FAILED";
|
|
377
|
+
throw err;
|
|
378
|
+
} else {
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function populate(processEnv, parsed, options = {}) {
|
|
384
|
+
const debug = Boolean(options && options.debug);
|
|
385
|
+
const override = Boolean(options && options.override);
|
|
386
|
+
const populated = {};
|
|
387
|
+
if (typeof parsed !== "object") {
|
|
388
|
+
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
|
|
389
|
+
err.code = "OBJECT_REQUIRED";
|
|
390
|
+
throw err;
|
|
391
|
+
}
|
|
392
|
+
for (const key of Object.keys(parsed)) {
|
|
393
|
+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
|
|
394
|
+
if (override === true) {
|
|
395
|
+
processEnv[key] = parsed[key];
|
|
396
|
+
populated[key] = parsed[key];
|
|
397
|
+
}
|
|
398
|
+
if (debug) {
|
|
399
|
+
if (override === true) {
|
|
400
|
+
_debug(`"${key}" is already defined and WAS overwritten`);
|
|
401
|
+
} else {
|
|
402
|
+
_debug(`"${key}" is already defined and was NOT overwritten`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
processEnv[key] = parsed[key];
|
|
407
|
+
populated[key] = parsed[key];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return populated;
|
|
411
|
+
}
|
|
412
|
+
var DotenvModule = {
|
|
413
|
+
configDotenv,
|
|
414
|
+
_configVault,
|
|
415
|
+
_parseVault,
|
|
416
|
+
config: config2,
|
|
417
|
+
decrypt,
|
|
418
|
+
parse,
|
|
419
|
+
populate
|
|
420
|
+
};
|
|
421
|
+
module.exports.configDotenv = DotenvModule.configDotenv;
|
|
422
|
+
module.exports._configVault = DotenvModule._configVault;
|
|
423
|
+
module.exports._parseVault = DotenvModule._parseVault;
|
|
424
|
+
module.exports.config = DotenvModule.config;
|
|
425
|
+
module.exports.decrypt = DotenvModule.decrypt;
|
|
426
|
+
module.exports.parse = DotenvModule.parse;
|
|
427
|
+
module.exports.populate = DotenvModule.populate;
|
|
428
|
+
module.exports = DotenvModule;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
5
431
|
|
|
6
|
-
// src/mastra/
|
|
7
|
-
import { Mastra } from "@mastra/core/mastra";
|
|
8
|
-
import { PinoLogger } from "@mastra/loggers";
|
|
9
|
-
import { LibSQLStore } from "@mastra/libsql";
|
|
432
|
+
// src/mastra/stdio.ts
|
|
10
433
|
import { MCPServer } from "@mastra/mcp";
|
|
11
434
|
|
|
12
|
-
// src/mastra/agents/foc-storage-agent.ts
|
|
13
|
-
import { Agent } from "@mastra/core/agent";
|
|
14
|
-
|
|
15
435
|
// src/mastra/tools/dataset-tools.ts
|
|
16
436
|
import { createTool } from "@mastra/core";
|
|
17
437
|
|
|
@@ -19,10 +439,10 @@ import { createTool } from "@mastra/core";
|
|
|
19
439
|
import { z as z2 } from "zod";
|
|
20
440
|
|
|
21
441
|
// src/config/index.ts
|
|
442
|
+
var import_dotenv = __toESM(require_main(), 1);
|
|
22
443
|
import { calibration, mainnet } from "@filoz/synapse-core/chains";
|
|
23
|
-
import { config } from "dotenv";
|
|
24
444
|
import { z } from "zod";
|
|
25
|
-
config();
|
|
445
|
+
(0, import_dotenv.config)();
|
|
26
446
|
var EnvSchema = z.object({
|
|
27
447
|
PRIVATE_KEY: z.string().min(1, "PRIVATE_KEY is required"),
|
|
28
448
|
FILECOIN_NETWORK: z.enum(["mainnet", "calibration"]).default("calibration"),
|
|
@@ -1565,219 +1985,6 @@ var focStorageTools = {
|
|
|
1565
1985
|
};
|
|
1566
1986
|
var focStorageToolsArray = Object.values(focStorageTools);
|
|
1567
1987
|
|
|
1568
|
-
// src/mastra/workflows/e2e-file-upload.ts
|
|
1569
|
-
import { createStep, createWorkflow } from "@mastra/core/workflows";
|
|
1570
|
-
import { z as z4 } from "zod";
|
|
1571
|
-
var e2eFileUploadInputSchema = z4.object({
|
|
1572
|
-
filePath: z4.string().describe("Absolute path to the file to upload"),
|
|
1573
|
-
datasetId: z4.string().optional().describe("Existing dataset ID to use"),
|
|
1574
|
-
withCDN: z4.boolean().optional().describe("Enable CDN for faster retrieval").default(false),
|
|
1575
|
-
persistenceDays: z4.number().optional().describe("Storage duration in days (default: 180)").default(env.PERSISTENCE_PERIOD_DAYS),
|
|
1576
|
-
notificationThresholdDays: z4.number().optional().describe("Notification threshold in days (default: 10)").default(env.RUNOUT_NOTIFICATION_THRESHOLD_DAYS),
|
|
1577
|
-
fileMetadata: z4.record(z4.string(), z4.string()).optional().describe("Metadata for the file (max 4 key-value pairs)")
|
|
1578
|
-
});
|
|
1579
|
-
var checkBalanceStep = createStep({
|
|
1580
|
-
id: "checkBalance",
|
|
1581
|
-
description: "Check current FIL/USDFC balances and storage metrics",
|
|
1582
|
-
inputSchema: e2eFileUploadInputSchema,
|
|
1583
|
-
outputSchema: z4.object({
|
|
1584
|
-
balances: z4.any(),
|
|
1585
|
-
needsPayment: z4.boolean(),
|
|
1586
|
-
depositNeeded: z4.number()
|
|
1587
|
-
}),
|
|
1588
|
-
execute: async ({ inputData, runtimeContext }) => {
|
|
1589
|
-
console.log("\u{1F4CA} STEP 1: Checking balances and storage metrics...");
|
|
1590
|
-
const fileInfo = await validateFilePath(inputData.filePath);
|
|
1591
|
-
const expectedStorageBytes = fileInfo.size;
|
|
1592
|
-
const { getBalances: getBalances2 } = focStorageTools;
|
|
1593
|
-
const result = await getBalances2.execute({
|
|
1594
|
-
context: { storageCapacityBytes: expectedStorageBytes, persistencePeriodDays: inputData.persistenceDays, notificationThresholdDays: inputData.notificationThresholdDays },
|
|
1595
|
-
runtimeContext
|
|
1596
|
-
});
|
|
1597
|
-
if (result.success === false) {
|
|
1598
|
-
throw new Error(`Balance check failed: ${result.error || "Unknown error"}`);
|
|
1599
|
-
}
|
|
1600
|
-
if (!result.checkStorageBalanceResult) {
|
|
1601
|
-
throw new Error(`Balance check returned invalid structure`);
|
|
1602
|
-
}
|
|
1603
|
-
return {
|
|
1604
|
-
balances: result.checkStorageBalanceResult,
|
|
1605
|
-
needsPayment: !result.checkStorageBalanceResult.isRateSufficient || !result.checkStorageBalanceResult.isLockupSufficient || Number(result.checkStorageBalanceResult.depositNeeded) > 0,
|
|
1606
|
-
depositNeeded: Number(result.checkStorageBalanceResult.depositNeeded) || 0
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
});
|
|
1610
|
-
var processPaymentStep = createStep({
|
|
1611
|
-
id: "processPayment",
|
|
1612
|
-
description: "Deposit USDFC if insufficient balance detected",
|
|
1613
|
-
inputSchema: z4.object({
|
|
1614
|
-
balances: z4.any(),
|
|
1615
|
-
needsPayment: z4.boolean(),
|
|
1616
|
-
depositNeeded: z4.number()
|
|
1617
|
-
}),
|
|
1618
|
-
outputSchema: z4.object({
|
|
1619
|
-
skipped: z4.boolean(),
|
|
1620
|
-
txHash: z4.string().optional(),
|
|
1621
|
-
depositAmount: z4.string().optional(),
|
|
1622
|
-
message: z4.string().optional()
|
|
1623
|
-
}),
|
|
1624
|
-
execute: async ({ getStepResult, getInitData, runtimeContext }) => {
|
|
1625
|
-
const balanceInfo = getStepResult("checkBalance");
|
|
1626
|
-
const initData = getInitData();
|
|
1627
|
-
const persistenceDays = initData.persistenceDays || 180;
|
|
1628
|
-
if (!balanceInfo.needsPayment) {
|
|
1629
|
-
console.log("\u2705 STEP 2: Balance and allowances are sufficient, skipping payment");
|
|
1630
|
-
return {
|
|
1631
|
-
skipped: true,
|
|
1632
|
-
message: "Payment not needed - balance and allowances sufficient"
|
|
1633
|
-
};
|
|
1634
|
-
}
|
|
1635
|
-
console.log("\u{1F4B0} STEP 2: Processing payment and/or setting allowances...");
|
|
1636
|
-
if (balanceInfo.depositNeeded > 0) {
|
|
1637
|
-
console.log(` Deposit needed: ${fromBaseUnits(balanceInfo.depositNeeded, 18)} USDFC`);
|
|
1638
|
-
} else {
|
|
1639
|
-
console.log(` Deposit sufficient, but allowances need to be set`);
|
|
1640
|
-
}
|
|
1641
|
-
console.log(` Persistence period: ${persistenceDays} days`);
|
|
1642
|
-
const { processPayment: processPayment2 } = focStorageTools;
|
|
1643
|
-
const result = await processPayment2.execute({
|
|
1644
|
-
context: {
|
|
1645
|
-
depositAmount: Number(balanceInfo.depositNeeded)
|
|
1646
|
-
},
|
|
1647
|
-
runtimeContext
|
|
1648
|
-
});
|
|
1649
|
-
if (result.success === false || result.error) {
|
|
1650
|
-
throw new Error(`Payment failed: ${result.error || "Unknown error"}`);
|
|
1651
|
-
}
|
|
1652
|
-
console.log(`\u2705 Payment/allowances processed successfully`);
|
|
1653
|
-
if (result.txHash) {
|
|
1654
|
-
console.log(` TX Hash: ${result.txHash}`);
|
|
1655
|
-
}
|
|
1656
|
-
if (result.depositAmount) {
|
|
1657
|
-
console.log(` Deposit Amount: ${result.depositAmount}`);
|
|
1658
|
-
}
|
|
1659
|
-
if (result.message) {
|
|
1660
|
-
console.log(` ${result.message}`);
|
|
1661
|
-
}
|
|
1662
|
-
return {
|
|
1663
|
-
skipped: false,
|
|
1664
|
-
txHash: result.txHash ?? void 0,
|
|
1665
|
-
depositAmount: result.depositAmount ?? void 0,
|
|
1666
|
-
message: result.message ?? "Payment processed"
|
|
1667
|
-
};
|
|
1668
|
-
}
|
|
1669
|
-
});
|
|
1670
|
-
var uploadFileStep = createStep({
|
|
1671
|
-
id: "uploadFile",
|
|
1672
|
-
description: "Upload file to Filecoin storage",
|
|
1673
|
-
inputSchema: z4.object({
|
|
1674
|
-
skipped: z4.boolean(),
|
|
1675
|
-
txHash: z4.string().optional(),
|
|
1676
|
-
depositAmount: z4.string().optional(),
|
|
1677
|
-
message: z4.string().optional()
|
|
1678
|
-
}),
|
|
1679
|
-
outputSchema: z4.object({
|
|
1680
|
-
pieceCid: z4.string(),
|
|
1681
|
-
txHash: z4.string().optional(),
|
|
1682
|
-
fileName: z4.string(),
|
|
1683
|
-
fileSize: z4.number(),
|
|
1684
|
-
progressLog: z4.array(z4.string()).optional()
|
|
1685
|
-
}),
|
|
1686
|
-
execute: async ({ getInitData, runtimeContext }) => {
|
|
1687
|
-
const initData = getInitData();
|
|
1688
|
-
console.log("\u{1F4E4} STEP 3: Uploading file to Filecoin...");
|
|
1689
|
-
console.log(` File: ${initData.filePath}`);
|
|
1690
|
-
const { uploadFile: uploadFile2 } = focStorageTools;
|
|
1691
|
-
const result = await uploadFile2.execute({
|
|
1692
|
-
context: {
|
|
1693
|
-
filePath: initData.filePath,
|
|
1694
|
-
datasetId: initData.datasetId,
|
|
1695
|
-
withCDN: initData.withCDN || false,
|
|
1696
|
-
autoPayment: false,
|
|
1697
|
-
// Already handled in step 2
|
|
1698
|
-
metadata: initData.fileMetadata
|
|
1699
|
-
},
|
|
1700
|
-
runtimeContext
|
|
1701
|
-
});
|
|
1702
|
-
if (result.success === false || result.error) {
|
|
1703
|
-
throw new Error(`File upload failed: ${result.error || "Unknown error"}`);
|
|
1704
|
-
}
|
|
1705
|
-
console.log(`\u2705 File uploaded successfully`);
|
|
1706
|
-
console.log(` Piece CID: ${result.pieceCid}`);
|
|
1707
|
-
console.log(` File Name: ${result.fileName}`);
|
|
1708
|
-
console.log(` File Size: ${result.fileSize} bytes`);
|
|
1709
|
-
return {
|
|
1710
|
-
pieceCid: result.pieceCid,
|
|
1711
|
-
txHash: result.txHash,
|
|
1712
|
-
fileName: result.fileName,
|
|
1713
|
-
fileSize: result.fileSize,
|
|
1714
|
-
progressLog: result.progressLog
|
|
1715
|
-
};
|
|
1716
|
-
}
|
|
1717
|
-
});
|
|
1718
|
-
var summaryStep = createStep({
|
|
1719
|
-
id: "summary",
|
|
1720
|
-
description: "Generate final summary of the upload process",
|
|
1721
|
-
inputSchema: z4.object({
|
|
1722
|
-
pieceCid: z4.string(),
|
|
1723
|
-
txHash: z4.string().optional(),
|
|
1724
|
-
fileName: z4.string(),
|
|
1725
|
-
fileSize: z4.number(),
|
|
1726
|
-
progressLog: z4.array(z4.string()).optional()
|
|
1727
|
-
}),
|
|
1728
|
-
outputSchema: z4.object({
|
|
1729
|
-
success: z4.boolean(),
|
|
1730
|
-
summary: z4.object({
|
|
1731
|
-
balance: z4.any(),
|
|
1732
|
-
payment: z4.any(),
|
|
1733
|
-
upload: z4.any()
|
|
1734
|
-
})
|
|
1735
|
-
}),
|
|
1736
|
-
execute: async ({ getStepResult }) => {
|
|
1737
|
-
const balanceInfo = getStepResult("checkBalance");
|
|
1738
|
-
const paymentInfo = getStepResult("processPayment");
|
|
1739
|
-
const uploadInfo = getStepResult("uploadFile");
|
|
1740
|
-
console.log("\n\u{1F389} ============================================");
|
|
1741
|
-
console.log(" E2E FILE UPLOAD COMPLETED SUCCESSFULLY");
|
|
1742
|
-
console.log("============================================");
|
|
1743
|
-
console.log(`\u{1F4CA} Initial Balance: ${balanceInfo.balances.accountStatusMessage}`);
|
|
1744
|
-
if (!paymentInfo.skipped) {
|
|
1745
|
-
console.log(`\u{1F4B0} Payment Processed: ${paymentInfo.depositAmount} USDFC`);
|
|
1746
|
-
console.log(` TX: ${paymentInfo.txHash}`);
|
|
1747
|
-
} else {
|
|
1748
|
-
console.log(`\u{1F4B0} Payment: Not needed (sufficient balance)`);
|
|
1749
|
-
}
|
|
1750
|
-
console.log(`\u{1F4E4} File Uploaded: ${uploadInfo.fileName}`);
|
|
1751
|
-
console.log(` Size: ${uploadInfo.fileSize} bytes`);
|
|
1752
|
-
console.log(` Piece CID: ${uploadInfo.pieceCid}`);
|
|
1753
|
-
if (uploadInfo.txHash) {
|
|
1754
|
-
console.log(` TX: ${uploadInfo.txHash}`);
|
|
1755
|
-
}
|
|
1756
|
-
console.log("============================================\n");
|
|
1757
|
-
return {
|
|
1758
|
-
success: true,
|
|
1759
|
-
summary: {
|
|
1760
|
-
balance: balanceInfo.balances,
|
|
1761
|
-
payment: paymentInfo,
|
|
1762
|
-
upload: uploadInfo
|
|
1763
|
-
}
|
|
1764
|
-
};
|
|
1765
|
-
}
|
|
1766
|
-
});
|
|
1767
|
-
var e2eFileUploadWorkflow = createWorkflow({
|
|
1768
|
-
id: "e2eFileUpload",
|
|
1769
|
-
description: "Upload a file to Filecoin storage",
|
|
1770
|
-
inputSchema: e2eFileUploadInputSchema,
|
|
1771
|
-
outputSchema: z4.object({
|
|
1772
|
-
success: z4.boolean(),
|
|
1773
|
-
summary: z4.object({
|
|
1774
|
-
balance: z4.any(),
|
|
1775
|
-
payment: z4.any(),
|
|
1776
|
-
upload: z4.any()
|
|
1777
|
-
})
|
|
1778
|
-
})
|
|
1779
|
-
}).then(checkBalanceStep).then(processPaymentStep).then(uploadFileStep).then(summaryStep).commit();
|
|
1780
|
-
|
|
1781
1988
|
// src/mastra/resources/instructions.ts
|
|
1782
1989
|
var instructions = `You are an AI agent specialized in managing decentralized file storage operations on the Filecoin network using the FOC-Synapse SDK. Your role is to help users store, retrieve, and manage files on Filecoin in a simple, efficient manner.
|
|
1783
1990
|
|
|
@@ -2011,18 +2218,6 @@ ERROR RESPONSES:
|
|
|
2011
2218
|
|
|
2012
2219
|
Remember: Your goal is to make decentralized storage as simple as traditional cloud storage, while educating users about the benefits of Filecoin's decentralized approach.`;
|
|
2013
2220
|
|
|
2014
|
-
// src/mastra/agents/foc-storage-agent.ts
|
|
2015
|
-
var focStorageAgent = new Agent({
|
|
2016
|
-
name: "FOCStorageAgent",
|
|
2017
|
-
description: "AI agent for managing decentralized file storage on Filecoin via FOC-Synapse SDK. Handles file uploads, dataset management, balance checking, and storage operations.",
|
|
2018
|
-
instructions,
|
|
2019
|
-
model: "openai/gpt-5-mini",
|
|
2020
|
-
tools: focStorageTools,
|
|
2021
|
-
workflows: {
|
|
2022
|
-
e2eFileUpload: e2eFileUploadWorkflow
|
|
2023
|
-
}
|
|
2024
|
-
});
|
|
2025
|
-
|
|
2026
2221
|
// src/mastra/resources/index.ts
|
|
2027
2222
|
var myResources = [
|
|
2028
2223
|
{ uri: "file://instructions", name: "Instructions", mimeType: "application/markdown" }
|
|
@@ -2049,10 +2244,10 @@ var focStorageResources = {
|
|
|
2049
2244
|
resourceTemplates: async () => myResourceTemplates
|
|
2050
2245
|
};
|
|
2051
2246
|
|
|
2052
|
-
// src/mastra/
|
|
2053
|
-
var
|
|
2247
|
+
// src/mastra/stdio.ts
|
|
2248
|
+
var server = new MCPServer({
|
|
2054
2249
|
name: "FOC Storage MCP",
|
|
2055
|
-
version: "0.
|
|
2250
|
+
version: "0.2.0",
|
|
2056
2251
|
description: "Professional-grade MCP server for decentralized file storage on Filecoin Onchain Cloud. Powered by the FOC-Synapse SDK, this server provides AI agents with seamless access to Filecoin's distributed storage network. Upload files with automatic payment handling, organize content in datasets, monitor storage balances, and manage providers - all through intuitive MCP tools. Supports both standard storage and CDN-enabled fast retrieval. Perfect for building AI applications that need persistent, censorship-resistant storage.",
|
|
2057
2252
|
tools: focStorageTools,
|
|
2058
2253
|
repository: {
|
|
@@ -2065,46 +2260,7 @@ var mcpServer = new MCPServer({
|
|
|
2065
2260
|
packageCanonical: "npm",
|
|
2066
2261
|
resources: focStorageResources
|
|
2067
2262
|
});
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
},
|
|
2072
|
-
workflows: {
|
|
2073
|
-
e2eFileUpload: e2eFileUploadWorkflow
|
|
2074
|
-
},
|
|
2075
|
-
mcpServers: {
|
|
2076
|
-
focStorageServer: mcpServer
|
|
2077
|
-
},
|
|
2078
|
-
storage: new LibSQLStore({
|
|
2079
|
-
url: ":memory:"
|
|
2080
|
-
}),
|
|
2081
|
-
logger: new PinoLogger({
|
|
2082
|
-
name: "Mastra",
|
|
2083
|
-
level: "silent"
|
|
2084
|
-
}),
|
|
2085
|
-
bundler: {
|
|
2086
|
-
externals: ["@filoz/synapse-sdk"]
|
|
2087
|
-
}
|
|
2088
|
-
});
|
|
2089
|
-
|
|
2090
|
-
// src/mcp-server.ts
|
|
2091
|
-
config2();
|
|
2092
|
-
async function startMCPServer() {
|
|
2093
|
-
try {
|
|
2094
|
-
await mcpServer.startStdio();
|
|
2095
|
-
} catch (error) {
|
|
2096
|
-
console.error("Error starting MCP server:", error);
|
|
2097
|
-
process.exit(1);
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
process.on("SIGINT", async () => {
|
|
2101
|
-
console.error("Shutting down MCP server...");
|
|
2102
|
-
await mcpServer.close();
|
|
2103
|
-
process.exit(0);
|
|
2104
|
-
});
|
|
2105
|
-
process.on("SIGTERM", async () => {
|
|
2106
|
-
console.error("Shutting down MCP server...");
|
|
2107
|
-
await mcpServer.close();
|
|
2108
|
-
process.exit(0);
|
|
2263
|
+
server.startStdio().catch((error) => {
|
|
2264
|
+
console.error("Error running MCP server:", error);
|
|
2265
|
+
process.exit(1);
|
|
2109
2266
|
});
|
|
2110
|
-
startMCPServer();
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fil-b/foc-storage-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"main": "dist/mcp-server.js",
|
|
5
|
-
"bin": "
|
|
5
|
+
"bin": "dist/stdio.js",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"build:mcp": "tsup src/mastra/stdio.ts --format esm --no-splitting --dts && chmod +x dist/stdio.js",
|
|
7
8
|
"dev": "mastra dev",
|
|
8
9
|
"build": "mastra build",
|
|
9
10
|
"start": "mastra start",
|
|
10
11
|
"mcp": "tsx src/mcp-server.ts",
|
|
11
|
-
"start:mcp": "tsx src/mcp-server.ts"
|
|
12
|
-
"build:mcp": "tsup"
|
|
12
|
+
"start:mcp": "tsx src/mcp-server.ts"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
15
|
"filecoin",
|
|
File without changes
|