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 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.3",
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.", {
@@ -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
- const regex = /\.([a-zA-Z_][a-zA-Z0-9_]*)|\.?(\[(\d+)\])|\.?\["([^"]+)"\]|\.?\['([^']+)'\]/g;
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
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-explorer-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server for efficiently exploring large JSON files",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",