@n0zer0d4y/vulcan-file-ops 1.2.13 → 1.2.14
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/CHANGELOG.md +37 -27
- package/README.md +89 -89
- package/dist/server/index.js +17 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,33 +8,43 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
8
8
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
## [1.2.
|
|
13
|
-
|
|
14
|
-
### Fixed
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Removed
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
11
|
+
|
|
12
|
+
## [1.2.14] - 2026-05-16
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **CRITICAL**: Fixed initialization deadlock with `claude-ai` v0.1.0 client (Claude Desktop web client, protocol `2025-11-25`).
|
|
17
|
+
- **Root Cause**: A custom `setRequestHandler(InitializeRequestSchema, ...)` was overriding the SDK's internal `_oninitialize` handler. This broke the SDK's state machine: `_clientCapabilities` and `_clientVersion` were never set, and protocol version negotiation was bypassed — the server echoed back the client's requested version verbatim rather than responding with the highest version it actually supports. The new client's stricter handshake exposed this latent defect.
|
|
18
|
+
- **Fix**: Removed the custom initialize handler and restored the SDK's built-in `_oninitialize`. The server now correctly negotiates `2025-06-18` when a client requests `2025-11-25`, which the client accepts per the MCP spec.
|
|
19
|
+
- **Instructions**: Server instructions (`generateServerDescription()`) are now injected into the SDK's `_instructions` field after directory initialization in `runServer()`, so they remain present in the initialize response without requiring a custom handler.
|
|
20
|
+
- Fixed `oninitialized` callback blocking the MCP handshake. The `listRoots()` call inside `oninitialized` was previously awaited, creating a potential deadlock (client won't respond to `roots/list` until after `initialized` is acknowledged, but the callback blocked acknowledgement). Changed to a detached fire-and-forget promise.
|
|
21
|
+
|
|
22
|
+
## [1.2.13] - 2026-04-23
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Resolved the remaining MCP client tool discovery failure introduced after the SDK upgrade.
|
|
27
|
+
- Tool schemas exposed through `tools/list` are now normalized for stricter MCP clients.
|
|
28
|
+
- Removed client-hostile schema constructs from published tool input schemas, including `$schema`, `$ref`, `anyOf`, `oneOf`, and `allOf`.
|
|
29
|
+
- Replaced the highest-risk wire schemas with explicit compatibility-first object schemas for `attach_image` and `make_directory`.
|
|
30
|
+
- Preserved runtime backward compatibility while tightening the schemas advertised to clients.
|
|
31
|
+
- Fixed residual MCP mode detection drift so stdio mode is triggered reliably in local and `npx` execution paths.
|
|
32
|
+
- Added `zod` as a direct runtime dependency to avoid install-time fragility in clean environments and `npx` usage.
|
|
33
|
+
- Synchronized package metadata so published registry metadata and local package metadata report the same release version.
|
|
34
|
+
- Re-enabled and stabilized the previously skipped PDF-related Jest coverage.
|
|
35
|
+
- Enabled the 10 skipped document tests for PDF read, HTML-to-PDF write, mixed document batches, and PDF round-trip paths.
|
|
36
|
+
- Updated Jest PDF mocks so document tests exercise meaningful content paths instead of placeholder-only buffers.
|
|
37
|
+
- Suppressed expected negative-path test diagnostics inside tests so successful runs no longer look like runtime failures.
|
|
38
|
+
- Added a regression test to prevent incompatible tool schema shapes from reappearing in future releases.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Documented the Codex-specific MCP configuration format in the README alongside the JSON-based client examples.
|
|
43
|
+
- Updated `npx` examples to use `-y` explicitly for non-interactive client execution.
|
|
44
|
+
|
|
45
|
+
## [1.2.12] - 2026-02-21
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
38
48
|
|
|
39
49
|
- **CRITICAL**: Fixed MCP server toggle failure and "no tools configured" error caused by Node.js version incompatibility and restrictive MCP detection.
|
|
40
50
|
- **Node.js Compatibility**: Replaced `import ... with { type: "json" }` with manual `fs.readFileSync` for `package.json` to support Node.js versions earlier than 20.10.0 and 18.20.0 (including Node 14/16).
|
package/README.md
CHANGED
|
@@ -124,10 +124,10 @@ This server can be used directly with npx (recommended) or installed globally/lo
|
|
|
124
124
|
|
|
125
125
|
### Basic Configuration
|
|
126
126
|
|
|
127
|
-
Add to your MCP client configuration.
|
|
128
|
-
|
|
129
|
-
For JSON-based clients such as Claude Desktop and Cursor, use their `mcpServers` JSON format.
|
|
130
|
-
For Codex, use `C:\Users\<username>\.codex\config.toml` and the `mcp_servers` TOML table format shown below.
|
|
127
|
+
Add to your MCP client configuration.
|
|
128
|
+
|
|
129
|
+
For JSON-based clients such as Claude Desktop and Cursor, use their `mcpServers` JSON format.
|
|
130
|
+
For Codex, use `C:\Users\<username>\.codex\config.toml` and the `mcp_servers` TOML table format shown below.
|
|
131
131
|
|
|
132
132
|
#### Option 1: Using npx (Recommended - No Installation Required)
|
|
133
133
|
|
|
@@ -135,22 +135,22 @@ For Codex, use `C:\Users\<username>\.codex\config.toml` and the `mcp_servers` TO
|
|
|
135
135
|
{
|
|
136
136
|
"mcpServers": {
|
|
137
137
|
"vulcan-file-ops": {
|
|
138
|
-
"command": "npx",
|
|
139
|
-
"args": ["-y", "@n0zer0d4y/vulcan-file-ops"]
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**Codex (`config.toml`)**
|
|
146
|
-
|
|
147
|
-
```toml
|
|
148
|
-
[mcp_servers.vulcan_file_ops]
|
|
149
|
-
command = "npx"
|
|
150
|
-
args = ["-y", "@n0zer0d4y/vulcan-file-ops"]
|
|
151
|
-
enabled = true
|
|
152
|
-
startup_timeout_sec = 120.0
|
|
153
|
-
```
|
|
138
|
+
"command": "npx",
|
|
139
|
+
"args": ["-y", "@n0zer0d4y/vulcan-file-ops"]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Codex (`config.toml`)**
|
|
146
|
+
|
|
147
|
+
```toml
|
|
148
|
+
[mcp_servers.vulcan_file_ops]
|
|
149
|
+
command = "npx"
|
|
150
|
+
args = ["-y", "@n0zer0d4y/vulcan-file-ops"]
|
|
151
|
+
enabled = true
|
|
152
|
+
startup_timeout_sec = 120.0
|
|
153
|
+
```
|
|
154
154
|
|
|
155
155
|
#### Option 2: Using Global Installation
|
|
156
156
|
|
|
@@ -180,7 +180,7 @@ After running `npm install @n0zer0d4y/vulcan-file-ops` in your project:
|
|
|
180
180
|
}
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
#### Option 4: Local Repository Execution (For Developers)
|
|
183
|
+
#### Option 4: Local Repository Execution (For Developers)
|
|
184
184
|
|
|
185
185
|
If you've cloned this repository and want to run from source:
|
|
186
186
|
|
|
@@ -191,39 +191,39 @@ npm install
|
|
|
191
191
|
npm run build
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
Then configure your MCP client:
|
|
195
|
-
|
|
196
|
-
```json
|
|
197
|
-
{
|
|
198
|
-
"mcpServers": {
|
|
199
|
-
"vulcan-file-ops": {
|
|
200
|
-
"command": "node",
|
|
201
|
-
"args": [
|
|
202
|
-
"/absolute/path/to/vulcan-file-ops/dist/cli.js",
|
|
203
|
-
"--approved-folders",
|
|
204
|
-
"/path/to/your/allowed/directories"
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Codex (`config.toml`)**
|
|
212
|
-
|
|
213
|
-
```toml
|
|
214
|
-
[mcp_servers.vulcan_file_ops]
|
|
215
|
-
command = "node"
|
|
216
|
-
args = [
|
|
217
|
-
'C:\absolute\path\to\vulcan-file-ops\dist\cli.js',
|
|
218
|
-
"--approved-folders",
|
|
219
|
-
'C:\path\to\your\allowed\directories'
|
|
220
|
-
]
|
|
221
|
-
cwd = 'C:\absolute\path\to\vulcan-file-ops'
|
|
222
|
-
enabled = true
|
|
223
|
-
startup_timeout_sec = 120.0
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Note:** For local repository execution, prefer `node dist/cli.js` with an absolute path. This works reliably in Codex and avoids PATH ambiguity.
|
|
194
|
+
Then configure your MCP client:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mcpServers": {
|
|
199
|
+
"vulcan-file-ops": {
|
|
200
|
+
"command": "node",
|
|
201
|
+
"args": [
|
|
202
|
+
"/absolute/path/to/vulcan-file-ops/dist/cli.js",
|
|
203
|
+
"--approved-folders",
|
|
204
|
+
"/path/to/your/allowed/directories"
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Codex (`config.toml`)**
|
|
212
|
+
|
|
213
|
+
```toml
|
|
214
|
+
[mcp_servers.vulcan_file_ops]
|
|
215
|
+
command = "node"
|
|
216
|
+
args = [
|
|
217
|
+
'C:\absolute\path\to\vulcan-file-ops\dist\cli.js',
|
|
218
|
+
"--approved-folders",
|
|
219
|
+
'C:\path\to\your\allowed\directories'
|
|
220
|
+
]
|
|
221
|
+
cwd = 'C:\absolute\path\to\vulcan-file-ops'
|
|
222
|
+
enabled = true
|
|
223
|
+
startup_timeout_sec = 120.0
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Note:** For local repository execution, prefer `node dist/cli.js` with an absolute path. This works reliably in Codex and avoids PATH ambiguity.
|
|
227
227
|
|
|
228
228
|
### Advanced Configuration
|
|
229
229
|
|
|
@@ -237,12 +237,12 @@ Pre-configure specific directories for immediate access on server start:
|
|
|
237
237
|
{
|
|
238
238
|
"mcpServers": {
|
|
239
239
|
"vulcan-file-ops": {
|
|
240
|
-
"command": "npx",
|
|
241
|
-
"args": [
|
|
242
|
-
"-y",
|
|
243
|
-
"@n0zer0d4y/vulcan-file-ops",
|
|
244
|
-
"--approved-folders",
|
|
245
|
-
"/Users/username/projects",
|
|
240
|
+
"command": "npx",
|
|
241
|
+
"args": [
|
|
242
|
+
"-y",
|
|
243
|
+
"@n0zer0d4y/vulcan-file-ops",
|
|
244
|
+
"--approved-folders",
|
|
245
|
+
"/Users/username/projects",
|
|
246
246
|
"/Users/username/documents"
|
|
247
247
|
]
|
|
248
248
|
}
|
|
@@ -256,12 +256,12 @@ Pre-configure specific directories for immediate access on server start:
|
|
|
256
256
|
{
|
|
257
257
|
"mcpServers": {
|
|
258
258
|
"vulcan-file-ops": {
|
|
259
|
-
"command": "npx",
|
|
260
|
-
"args": [
|
|
261
|
-
"-y",
|
|
262
|
-
"@n0zer0d4y/vulcan-file-ops",
|
|
263
|
-
"--approved-folders",
|
|
264
|
-
"C:/Users/username/projects",
|
|
259
|
+
"command": "npx",
|
|
260
|
+
"args": [
|
|
261
|
+
"-y",
|
|
262
|
+
"@n0zer0d4y/vulcan-file-ops",
|
|
263
|
+
"--approved-folders",
|
|
264
|
+
"C:/Users/username/projects",
|
|
265
265
|
"C:/Users/username/documents"
|
|
266
266
|
]
|
|
267
267
|
}
|
|
@@ -269,7 +269,7 @@ Pre-configure specific directories for immediate access on server start:
|
|
|
269
269
|
}
|
|
270
270
|
```
|
|
271
271
|
|
|
272
|
-
**Alternative: Local Repository Execution**
|
|
272
|
+
**Alternative: Local Repository Execution**
|
|
273
273
|
|
|
274
274
|
For users running from a cloned repository (after `npm run build`):
|
|
275
275
|
|
|
@@ -277,32 +277,32 @@ For users running from a cloned repository (after `npm run build`):
|
|
|
277
277
|
{
|
|
278
278
|
"mcpServers": {
|
|
279
279
|
"vulcan-file-ops": {
|
|
280
|
-
"command": "vulcan-file-ops",
|
|
281
|
-
"args": [
|
|
282
|
-
"--approved-folders",
|
|
283
|
-
"/Users/username/projects",
|
|
284
|
-
"/Users/username/documents"
|
|
280
|
+
"command": "vulcan-file-ops",
|
|
281
|
+
"args": [
|
|
282
|
+
"--approved-folders",
|
|
283
|
+
"/Users/username/projects",
|
|
284
|
+
"/Users/username/documents"
|
|
285
285
|
]
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
**Codex with Approved Folders (`config.toml`)**
|
|
292
|
-
|
|
293
|
-
```toml
|
|
294
|
-
[mcp_servers.vulcan_file_ops]
|
|
295
|
-
command = "node"
|
|
296
|
-
args = [
|
|
297
|
-
'C:\absolute\path\to\vulcan-file-ops\dist\cli.js',
|
|
298
|
-
"--approved-folders",
|
|
299
|
-
'C:\Users\username\projects',
|
|
300
|
-
'C:\Users\username\documents'
|
|
301
|
-
]
|
|
302
|
-
cwd = 'C:\absolute\path\to\vulcan-file-ops'
|
|
303
|
-
enabled = true
|
|
304
|
-
startup_timeout_sec = 120.0
|
|
305
|
-
```
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Codex with Approved Folders (`config.toml`)**
|
|
292
|
+
|
|
293
|
+
```toml
|
|
294
|
+
[mcp_servers.vulcan_file_ops]
|
|
295
|
+
command = "node"
|
|
296
|
+
args = [
|
|
297
|
+
'C:\absolute\path\to\vulcan-file-ops\dist\cli.js',
|
|
298
|
+
"--approved-folders",
|
|
299
|
+
'C:\Users\username\projects',
|
|
300
|
+
'C:\Users\username\documents'
|
|
301
|
+
]
|
|
302
|
+
cwd = 'C:\absolute\path\to\vulcan-file-ops'
|
|
303
|
+
enabled = true
|
|
304
|
+
startup_timeout_sec = 120.0
|
|
305
|
+
```
|
|
306
306
|
|
|
307
307
|
**Path Format Note:**
|
|
308
308
|
|
package/dist/server/index.js
CHANGED
|
@@ -16,7 +16,7 @@ if (_isMCP) {
|
|
|
16
16
|
}
|
|
17
17
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
18
18
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
|
-
import { CallToolRequestSchema, ListToolsRequestSchema,
|
|
19
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, PingRequestSchema, RootsListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
20
20
|
import fs from "fs/promises";
|
|
21
21
|
import { readFileSync } from "fs";
|
|
22
22
|
import path from "path";
|
|
@@ -399,26 +399,11 @@ const server = new Server({
|
|
|
399
399
|
// receive "Method not found" errors, and fail to enable the toggle
|
|
400
400
|
},
|
|
401
401
|
});
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// Claude Desktop only supports 2025-06-18 and will disconnect if we return 2025-11-25
|
|
408
|
-
protocolVersion: request.params.protocolVersion,
|
|
409
|
-
capabilities: {
|
|
410
|
-
tools: {
|
|
411
|
-
listChanged: true,
|
|
412
|
-
},
|
|
413
|
-
// CRITICAL: Do NOT declare resources or prompts - we don't implement them
|
|
414
|
-
},
|
|
415
|
-
serverInfo: {
|
|
416
|
-
name: "vulcan-file-ops",
|
|
417
|
-
version: VERSION,
|
|
418
|
-
},
|
|
419
|
-
instructions: generateServerDescription(),
|
|
420
|
-
};
|
|
421
|
-
});
|
|
402
|
+
// The SDK's built-in initialize handler (_oninitialize) is left in place.
|
|
403
|
+
// Overriding it via setRequestHandler breaks the SDK's internal state machine:
|
|
404
|
+
// _clientCapabilities and _clientVersion never get set, and protocol version
|
|
405
|
+
// negotiation is bypassed (should respond with max supported ≤ client's requested).
|
|
406
|
+
// Instructions are injected at runtime in runServer() after directories initialize.
|
|
422
407
|
// Ping handler - for health checks
|
|
423
408
|
server.setRequestHandler(PingRequestSchema, async () => {
|
|
424
409
|
return {};
|
|
@@ -623,18 +608,19 @@ server.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
|
|
|
623
608
|
}
|
|
624
609
|
});
|
|
625
610
|
// Handles post-initialization setup, specifically checking for and fetching MCP roots.
|
|
626
|
-
|
|
611
|
+
// listRoots() is fired detached (no await) so it doesn't block the initialize handshake.
|
|
612
|
+
// Blocking here deadlocks: the client won't respond to roots/list until after initialize
|
|
613
|
+
// completes, but initialize won't complete until this callback returns.
|
|
614
|
+
server.oninitialized = () => {
|
|
627
615
|
const clientCapabilities = server.getClientCapabilities();
|
|
628
616
|
if (clientCapabilities?.roots) {
|
|
629
|
-
|
|
630
|
-
const response = await server.listRoots();
|
|
617
|
+
server.listRoots().then(async (response) => {
|
|
631
618
|
if (response && "roots" in response) {
|
|
632
619
|
await updateAllowedDirectoriesFromRoots(response.roots);
|
|
633
620
|
}
|
|
634
|
-
}
|
|
635
|
-
catch (error) {
|
|
621
|
+
}).catch(() => {
|
|
636
622
|
// Silently handle errors - dynamic access will work via register_directory tool
|
|
637
|
-
}
|
|
623
|
+
});
|
|
638
624
|
}
|
|
639
625
|
};
|
|
640
626
|
// Start server
|
|
@@ -658,6 +644,10 @@ export async function runServer() {
|
|
|
658
644
|
}
|
|
659
645
|
// In MCP mode, silently continue - server can work without approved folders
|
|
660
646
|
}
|
|
647
|
+
// Inject instructions now that directories are known. The SDK's built-in
|
|
648
|
+
// _oninitialize reads this._instructions when building the initialize response.
|
|
649
|
+
server._instructions =
|
|
650
|
+
generateServerDescription();
|
|
661
651
|
const transport = new StdioServerTransport();
|
|
662
652
|
await server.connect(transport);
|
|
663
653
|
// Minimal logging to avoid issues with MCP clients
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n0zer0d4y/vulcan-file-ops",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.14",
|
|
4
4
|
"mcpName": "io.github.n0zer0d4y/vulcan-file-ops",
|
|
5
5
|
"description": "MCP server for AI assistants: read, write, edit, and manage files securely on local filesystem.",
|
|
6
6
|
"license": "MIT",
|