filemayor-mcp 4.0.6 → 4.0.7
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 +12 -8
- package/index.mjs +63 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**The FileMayor MCP server.** Drive your intelligent filesystem clerk from Claude, Cursor, Zed, or any [Model Context Protocol](https://modelcontextprotocol.io) client.
|
|
4
4
|
|
|
5
|
-
`v4.0.
|
|
5
|
+
`v4.0.7` · Node ≥20 · [filemayor.com/mcp](https://filemayor.com/mcp)
|
|
6
6
|
|
|
7
7
|
[](https://smithery.ai/server/filemayor-mcp)
|
|
8
8
|
|
|
@@ -103,9 +103,9 @@ Doesn't apply. FileMayor MCP is **Node.js**, not Python. Its single runtime depe
|
|
|
103
103
|
|
|
104
104
|
This is the supply-chain risk that applies to *every* MCP server in principle, ours included. Our mitigations:
|
|
105
105
|
|
|
106
|
-
- The whole server is one file: [`mcp/index.mjs`](https://github.com/Hrypopo/FileMayor/blob/main/mcp/index.mjs) — ~
|
|
106
|
+
- The whole server is one file: [`mcp/index.mjs`](https://github.com/Hrypopo/FileMayor/blob/main/mcp/index.mjs) — ~580 lines. Tool declarations and their `case` handlers sit side-by-side. You can read it end-to-end in about 15 minutes. (`--audit` prints the exact current line count under `verifyBy`, so the number can't drift out of date.)
|
|
107
107
|
- `grep -E "fetch\(|http\.request|https\.request|net\." mcp/index.mjs` returns nothing. The server makes no outbound network calls of its own.
|
|
108
|
-
- The *only* off-machine egress path is the optional AI call inside `filemayor_plan`, gated by an AI provider key (`ANTHROPIC_API_KEY
|
|
108
|
+
- The *only* off-machine egress path is the optional AI call inside `filemayor_plan`, gated by an AI provider key (`ANTHROPIC_API_KEY` → Claude, `GEMINI_API_KEY` → Gemini, or `OPENAI_API_KEY` → GPT-4o-mini). The first key present wins. Without any key, the tool returns an error and nothing is sent. With a key, only directory metadata (paths, sizes, extensions) is sent — no file contents. When Claude is the MCP client, `filemayor_plan` is not needed at all.
|
|
109
109
|
- The GitHub repo is the canonical source.
|
|
110
110
|
|
|
111
111
|
### What `--audit` reports
|
|
@@ -113,16 +113,20 @@ This is the supply-chain risk that applies to *every* MCP server in principle, o
|
|
|
113
113
|
```json
|
|
114
114
|
{
|
|
115
115
|
"package": "filemayor-mcp",
|
|
116
|
-
"version": "4.0.
|
|
116
|
+
"version": "4.0.7",
|
|
117
117
|
"transport": { "type": "stdio", "networkListeners": false, "ports": [] },
|
|
118
118
|
"outbound": {
|
|
119
119
|
"defaultEgress": "none",
|
|
120
120
|
"optionalEgress": {
|
|
121
121
|
"enabled": false,
|
|
122
|
-
"
|
|
122
|
+
"destinations": [
|
|
123
|
+
"https://api.anthropic.com",
|
|
124
|
+
"https://generativelanguage.googleapis.com",
|
|
125
|
+
"https://api.openai.com"
|
|
126
|
+
],
|
|
123
127
|
"trigger": "filemayor_plan tool only (not used when Claude is the MCP client)",
|
|
124
128
|
"payload": "directory metadata only — no file contents",
|
|
125
|
-
"gatedBy": "ANTHROPIC_API_KEY
|
|
129
|
+
"gatedBy": "one of ANTHROPIC_API_KEY / GEMINI_API_KEY / OPENAI_API_KEY (none currently set)"
|
|
126
130
|
}
|
|
127
131
|
},
|
|
128
132
|
"runtimeSafeguards": {
|
|
@@ -136,7 +140,7 @@ This is the supply-chain risk that applies to *every* MCP server in principle, o
|
|
|
136
140
|
"dependencies": { "runtime": ["@modelcontextprotocol/sdk"], "python": false, "starlette": false, "fastapi": false },
|
|
137
141
|
"source": "https://github.com/Hrypopo/FileMayor/blob/main/mcp/index.mjs",
|
|
138
142
|
"verifyBy": [
|
|
139
|
-
"Read mcp/index.mjs end-to-end —
|
|
143
|
+
"Read mcp/index.mjs end-to-end — the report prints the exact current line count here.",
|
|
140
144
|
"grep for outbound calls: rg \"fetch\\(|http\\.request|https\\.request|net\\.\" mcp/index.mjs",
|
|
141
145
|
"Run `npm view filemayor-mcp` and compare the published shasum to the GitHub tag.",
|
|
142
146
|
"Run this same `--audit` after upgrading to detect changes to transport / egress / tool list."
|
|
@@ -148,7 +152,7 @@ This is the supply-chain risk that applies to *every* MCP server in principle, o
|
|
|
148
152
|
|
|
149
153
|
A viral tutorial recommended `pip install mcp-audit && mcp-audit scan` to audit installed MCP servers. As of this release, `mcp-audit` is **not published on PyPI**, and the `mcp-audit` package on npm is a 408-byte hello-world stub (v0.0.1, published April 2025, no functional code). The tutorial directs viewers to comment on a social-media post to receive the "real" tool by direct message — that's a social-engineering pattern, not a verifiable tool. Be skeptical of any installer not on a public registry under a known maintainer.
|
|
150
154
|
|
|
151
|
-
If a real, signed, open-source MCP scanner emerges, we'll link to it from this section and publish the verdict against `filemayor-mcp`. Until then, `--audit` + reading the
|
|
155
|
+
If a real, signed, open-source MCP scanner emerges, we'll link to it from this section and publish the verdict against `filemayor-mcp`. Until then, `--audit` + reading the ~580 lines of source is the trustworthy path.
|
|
152
156
|
|
|
153
157
|
### Hardened-runtime safeguards (the engine, not just the MCP shell)
|
|
154
158
|
|
package/index.mjs
CHANGED
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
*
|
|
17
17
|
* When Claude is the MCP client, Claude IS the AI — no external API key
|
|
18
18
|
* is needed. filemayor_plan is available for non-Claude clients (Cursor,
|
|
19
|
-
* Zed, scripts) and picks up whichever key is set in the environment
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Zed, scripts) and picks up whichever key is set in the environment, in
|
|
20
|
+
* this priority order:
|
|
21
|
+
* ANTHROPIC_API_KEY → Claude (claude-haiku-4-5-20251001)
|
|
22
|
+
* GEMINI_API_KEY → Gemini (gemini-2.0-flash)
|
|
22
23
|
* OPENAI_API_KEY → GPT-4o-mini
|
|
24
|
+
* The key selects the provider; the core planner (cli/core/ai) dispatches
|
|
25
|
+
* the actual call. See detectAiProvider() below.
|
|
23
26
|
* ═══════════════════════════════════════════════════════════════════
|
|
24
27
|
*/
|
|
25
28
|
|
|
@@ -82,6 +85,24 @@ function checkDir(p) {
|
|
|
82
85
|
return { resolved: v.resolved };
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
// Pick the external AI provider for filemayor_plan from whichever key is
|
|
89
|
+
// set, in priority order. The core planner (cli/core/ai) dispatches on
|
|
90
|
+
// FM_AI_PROVIDER + FM_AI_API_KEY, so the keys below are the single source
|
|
91
|
+
// of truth for what the tool actually supports. Returns null if no key.
|
|
92
|
+
const AI_PROVIDERS = [
|
|
93
|
+
{ env: 'ANTHROPIC_API_KEY', provider: 'anthropic', label: 'Claude (claude-haiku-4-5-20251001)' },
|
|
94
|
+
{ env: 'GEMINI_API_KEY', provider: 'gemini', label: 'Gemini (gemini-2.0-flash)' },
|
|
95
|
+
{ env: 'OPENAI_API_KEY', provider: 'openai', label: 'GPT-4o-mini' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
function detectAiProvider() {
|
|
99
|
+
for (const p of AI_PROVIDERS) {
|
|
100
|
+
const apiKey = process.env[p.env];
|
|
101
|
+
if (apiKey) return { ...p, apiKey };
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
85
106
|
// ─── Tool definitions ──────────────────────────────────────────────
|
|
86
107
|
|
|
87
108
|
const TOOLS = [
|
|
@@ -134,7 +155,7 @@ const TOOLS = [
|
|
|
134
155
|
},
|
|
135
156
|
{
|
|
136
157
|
name: 'filemayor_apply',
|
|
137
|
-
description: 'Execute a move plan and journal every operation for rollback. Two modes: (1) Claude-native — pass a "moves" array of {src, dst} objects that you generated yourself after calling filemayor_explain; (2)
|
|
158
|
+
description: 'Execute a move plan and journal every operation for rollback. Two modes: (1) Claude-native — pass a "moves" array of {src, dst} objects that you generated yourself after calling filemayor_explain; (2) external-AI — call filemayor_plan first (Anthropic / Gemini / OpenAI, by key), then call this with no arguments to execute that plan. The journal is written to disk so filemayor_rollback can undo it.',
|
|
138
159
|
inputSchema: {
|
|
139
160
|
type: 'object',
|
|
140
161
|
properties: {
|
|
@@ -276,19 +297,35 @@ async function handleTool(name, args) {
|
|
|
276
297
|
const c = checkDir(args.path);
|
|
277
298
|
if (c.error) return err(c.error);
|
|
278
299
|
if (!args.prompt) return err('prompt is required');
|
|
279
|
-
const
|
|
280
|
-
if (!
|
|
300
|
+
const ai = detectAiProvider();
|
|
301
|
+
if (!ai) {
|
|
281
302
|
return err(
|
|
282
|
-
'filemayor_plan
|
|
303
|
+
'filemayor_plan needs an AI provider key for non-Claude clients. Set one of:\n' +
|
|
304
|
+
' ANTHROPIC_API_KEY → Claude (claude-haiku-4-5-20251001)\n' +
|
|
305
|
+
' GEMINI_API_KEY → Gemini (gemini-2.0-flash)\n' +
|
|
306
|
+
' OPENAI_API_KEY → GPT-4o-mini\n\n' +
|
|
283
307
|
'If Claude is your MCP client you do NOT need this tool — Claude is already the AI. ' +
|
|
284
308
|
'Instead: call filemayor_explain to audit the folder, reason about the moves yourself, ' +
|
|
285
309
|
'then pass them directly to filemayor_apply as the "moves" parameter.'
|
|
286
310
|
);
|
|
287
311
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
// Route the core planner to the selected provider. Restore the
|
|
313
|
+
// previous env afterwards so we never leak state between calls.
|
|
314
|
+
const prevProvider = process.env.FM_AI_PROVIDER;
|
|
315
|
+
const prevKey = process.env.FM_AI_API_KEY;
|
|
316
|
+
process.env.FM_AI_PROVIDER = ai.provider;
|
|
317
|
+
process.env.FM_AI_API_KEY = ai.apiKey;
|
|
318
|
+
try {
|
|
319
|
+
const engine = new CureEngine(c.resolved, ai.apiKey);
|
|
320
|
+
const plan = await engine.generatePlan(args.prompt);
|
|
321
|
+
activeCureEngine = engine;
|
|
322
|
+
return ok({ provider: ai.label, ...plan });
|
|
323
|
+
} finally {
|
|
324
|
+
if (prevProvider === undefined) delete process.env.FM_AI_PROVIDER;
|
|
325
|
+
else process.env.FM_AI_PROVIDER = prevProvider;
|
|
326
|
+
if (prevKey === undefined) delete process.env.FM_AI_API_KEY;
|
|
327
|
+
else process.env.FM_AI_API_KEY = prevKey;
|
|
328
|
+
}
|
|
292
329
|
}
|
|
293
330
|
|
|
294
331
|
case 'filemayor_apply': {
|
|
@@ -452,9 +489,16 @@ if (process.argv.includes('--audit')) {
|
|
|
452
489
|
'filemayor_undo_last',
|
|
453
490
|
]);
|
|
454
491
|
|
|
492
|
+
const activeProvider = detectAiProvider();
|
|
493
|
+
const PROVIDER_ENDPOINTS = {
|
|
494
|
+
anthropic: 'https://api.anthropic.com',
|
|
495
|
+
gemini: 'https://generativelanguage.googleapis.com',
|
|
496
|
+
openai: 'https://api.openai.com',
|
|
497
|
+
};
|
|
498
|
+
|
|
455
499
|
const report = {
|
|
456
500
|
package: 'filemayor-mcp',
|
|
457
|
-
version:
|
|
501
|
+
version: PKG_VERSION,
|
|
458
502
|
node: process.version,
|
|
459
503
|
platform: `${process.platform}-${process.arch}`,
|
|
460
504
|
transport: {
|
|
@@ -465,20 +509,21 @@ if (process.argv.includes('--audit')) {
|
|
|
465
509
|
},
|
|
466
510
|
outbound: {
|
|
467
511
|
defaultEgress: 'none',
|
|
468
|
-
optionalEgress:
|
|
512
|
+
optionalEgress: activeProvider
|
|
469
513
|
? {
|
|
470
514
|
enabled: true,
|
|
471
|
-
destination:
|
|
515
|
+
destination: PROVIDER_ENDPOINTS[activeProvider.provider],
|
|
516
|
+
provider: activeProvider.label,
|
|
472
517
|
trigger: 'filemayor_plan tool only',
|
|
473
518
|
payload: 'directory metadata (paths, sizes, extensions). No file contents.',
|
|
474
|
-
gatedBy:
|
|
519
|
+
gatedBy: `${activeProvider.env} environment variable`,
|
|
475
520
|
}
|
|
476
521
|
: {
|
|
477
522
|
enabled: false,
|
|
478
|
-
|
|
523
|
+
destinations: Object.values(PROVIDER_ENDPOINTS),
|
|
479
524
|
trigger: 'filemayor_plan tool only',
|
|
480
525
|
payload: 'directory metadata only — no file contents',
|
|
481
|
-
gatedBy: 'GEMINI_API_KEY
|
|
526
|
+
gatedBy: 'one of ANTHROPIC_API_KEY / GEMINI_API_KEY / OPENAI_API_KEY (none currently set)',
|
|
482
527
|
},
|
|
483
528
|
},
|
|
484
529
|
runtimeSafeguards: {
|
|
@@ -503,7 +548,7 @@ if (process.argv.includes('--audit')) {
|
|
|
503
548
|
},
|
|
504
549
|
source: 'https://github.com/Hrypopo/FileMayor/blob/main/mcp/index.mjs',
|
|
505
550
|
verifyBy: [
|
|
506
|
-
|
|
551
|
+
`Read mcp/index.mjs end-to-end — it's ${(() => { try { return fs.readFileSync(new URL(import.meta.url)).toString().split('\n').length; } catch { return 'a few hundred'; } })()} lines.`,
|
|
507
552
|
"grep for outbound calls: rg \"fetch\\(|http\\.request|https\\.request|net\\.\" mcp/index.mjs",
|
|
508
553
|
"Run `npm view filemayor-mcp` and compare the published shasum to the GitHub tag.",
|
|
509
554
|
"Run this same `--audit` after upgrading to detect changes to transport / egress / tool list.",
|