json-explorer-mcp 1.0.3 → 1.0.4
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/dist/index.js +1 -1
- package/dist/tools/navigation.js +1 -1
- package/dist/utils/path-helpers.js +23 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { jsonKeys, jsonGet, jsonSet } from "./tools/navigation.js";
|
|
|
7
7
|
import { jsonSearch, jsonSample, jsonStats } from "./tools/query.js";
|
|
8
8
|
const server = new McpServer({
|
|
9
9
|
name: "json-explorer",
|
|
10
|
-
version: "1.0.
|
|
10
|
+
version: "1.0.4",
|
|
11
11
|
});
|
|
12
12
|
// Tool: json_inspect - Get file overview
|
|
13
13
|
server.tool("json_inspect", "Get an overview of a JSON file including size, structure type, and a depth-limited preview. Use this first to understand what you're working with.", {
|
package/dist/tools/navigation.js
CHANGED
|
@@ -189,7 +189,7 @@ export async function jsonSet(filePath, path, value, options = {}) {
|
|
|
189
189
|
}
|
|
190
190
|
// Write to file
|
|
191
191
|
const targetFile = outputFile || filePath;
|
|
192
|
-
const jsonOutput = JSON.stringify(modifiedData, null, 2);
|
|
192
|
+
const jsonOutput = JSON.stringify(modifiedData, null, 2) + "\n";
|
|
193
193
|
await writeFile(targetFile, jsonOutput, "utf-8");
|
|
194
194
|
return {
|
|
195
195
|
success: true,
|
|
@@ -81,10 +81,20 @@ function parsePathSegments(path) {
|
|
|
81
81
|
const segments = [];
|
|
82
82
|
// Remove leading $
|
|
83
83
|
const pathWithoutRoot = normalized.slice(1);
|
|
84
|
-
// Match either .key, [index], or ["key"]
|
|
85
|
-
|
|
84
|
+
// Match either .key (including $-prefixed keys like $id), [index], or ["key"]
|
|
85
|
+
// Keys can start with letter, underscore, or $ and contain alphanumeric, underscore, or $
|
|
86
|
+
const regex = /\.([a-zA-Z_$][a-zA-Z0-9_$]*)|\.?(\[(\d+)\])|\.?\["([^"]+)"\]|\.?\['([^']+)'\]/g;
|
|
86
87
|
let match;
|
|
88
|
+
let lastIndex = 0;
|
|
87
89
|
while ((match = regex.exec(pathWithoutRoot)) !== null) {
|
|
90
|
+
// Check for gaps in parsing (unmatched content)
|
|
91
|
+
if (match.index > lastIndex) {
|
|
92
|
+
const unmatched = pathWithoutRoot.slice(lastIndex, match.index);
|
|
93
|
+
if (unmatched && unmatched !== ".") {
|
|
94
|
+
throw new Error(`Invalid path segment: could not parse "${unmatched}" in path "${path}"`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
lastIndex = regex.lastIndex;
|
|
88
98
|
if (match[1] !== undefined) {
|
|
89
99
|
// .key format
|
|
90
100
|
segments.push(match[1]);
|
|
@@ -102,6 +112,17 @@ function parsePathSegments(path) {
|
|
|
102
112
|
segments.push(match[5]);
|
|
103
113
|
}
|
|
104
114
|
}
|
|
115
|
+
// Check for trailing unmatched content
|
|
116
|
+
if (lastIndex < pathWithoutRoot.length) {
|
|
117
|
+
const unmatched = pathWithoutRoot.slice(lastIndex);
|
|
118
|
+
if (unmatched && unmatched !== ".") {
|
|
119
|
+
throw new Error(`Invalid path segment: could not parse "${unmatched}" in path "${path}"`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Safety check: if path has content but no segments were parsed, something is wrong
|
|
123
|
+
if (pathWithoutRoot.length > 0 && segments.length === 0) {
|
|
124
|
+
throw new Error(`Failed to parse path "${path}": no valid segments found`);
|
|
125
|
+
}
|
|
105
126
|
return segments;
|
|
106
127
|
}
|
|
107
128
|
/**
|