@utilix-tech/mcp 0.21.0 → 0.22.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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Full release notes for all Utilix surfaces (browser tools, REST API, SDKs, MCP server) live at [utilix.tech/changelog](https://utilix.tech/changelog). This file tracks just this package.
4
4
 
5
+ ## 0.22.0
6
+ - Add `calculate_percentage_change` tool: percentage change between two numbers, with absolute change, direction, and multiplier.
7
+ - Add `resolve_json_pointer` tool: resolve an RFC 6901 JSON Pointer against a document, with ~0/~1 escaping and not-found reasons.
8
+
5
9
  ## 0.21.0
6
10
  - Add `build_cache_control` tool: build and explain a `Cache-Control` response header from directives.
7
11
  - Add `detect_filler_words` tool: scan text for filler words, hedge phrases, and clichés.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/mcp
2
2
 
3
- MCP server exposing 130 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
3
+ MCP server exposing 132 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
4
4
 
5
5
  No API key required. All tools run locally. Requires Node.js 18 or later.
6
6
 
@@ -75,7 +75,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
75
75
 
76
76
  ## Tools
77
77
 
78
- ### JSON (13 tools)
78
+ ### JSON (14 tools)
79
79
  | Tool | Description |
80
80
  |------|-------------|
81
81
  | `format_json` | Pretty-print and validate a JSON string |
@@ -84,6 +84,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
84
84
  | `json_to_csv` | Convert a JSON array of objects to CSV |
85
85
  | `csv_to_json` | Convert CSV text to a JSON array |
86
86
  | `jsonpath` | Evaluate a JSONPath expression |
87
+ | `resolve_json_pointer` | Resolve an RFC 6901 JSON Pointer against a JSON document |
87
88
  | `validate_json` | Validate JSON against a JSON Schema |
88
89
  | `yaml_to_json` | Convert YAML to JSON |
89
90
  | `json_to_yaml` | Convert JSON to YAML |
@@ -150,7 +151,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
150
151
  | `date_diff` | Calculate the difference between two dates |
151
152
  | `convert_timezone` | Convert a date/time between timezones |
152
153
 
153
- ### Units (12 tools)
154
+ ### Units (13 tools)
154
155
  | Tool | Description |
155
156
  |------|-------------|
156
157
  | `convert_bytes` | Convert between B, KB, MB, GB, TB, KiB, MiB, GiB, TiB |
@@ -165,6 +166,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
165
166
  | `calculate_tip_split` | Compute a tip on a bill amount and split the bill, tip, and total evenly across N people |
166
167
  | `calculate_simple_interest` | Compute simple (non-compounding) interest as principal x rate x time, plus the total payoff |
167
168
  | `calculate_time_value` | Convert between present and future value (time value of money) in either direction |
169
+ | `calculate_percentage_change` | Compute the percentage change between two numbers, with absolute change, direction, and multiplier |
168
170
 
169
171
  ### API / Network (10 tools)
170
172
  | Tool | Description |
package/dist/index.js CHANGED
@@ -3825,5 +3825,92 @@ server.tool(
3825
3825
  return text(JSON.stringify(_detectFillerWordsMcp(input), null, 2));
3826
3826
  }
3827
3827
  );
3828
+ function _calculatePercentageChangeMcp(oldValue, newValue) {
3829
+ if (!Number.isFinite(oldValue)) return { error: "Original value must be a finite number" };
3830
+ if (!Number.isFinite(newValue)) return { error: "New value must be a finite number" };
3831
+ if (oldValue === 0 && newValue !== 0) return { error: "Percentage change from zero is undefined (division by zero); use a nonzero original value" };
3832
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
3833
+ const absoluteChange = newValue - oldValue;
3834
+ const percentChange = oldValue === 0 ? 0 : absoluteChange / Math.abs(oldValue) * 100;
3835
+ const multiplier = oldValue === 0 ? 1 : newValue / oldValue;
3836
+ let direction;
3837
+ if (absoluteChange > 0) direction = "increase";
3838
+ else if (absoluteChange < 0) direction = "decrease";
3839
+ else direction = "no change";
3840
+ return {
3841
+ oldValue,
3842
+ newValue,
3843
+ absoluteChange: round4(absoluteChange),
3844
+ percentChange: round4(percentChange),
3845
+ direction,
3846
+ multiplier: round4(multiplier)
3847
+ };
3848
+ }
3849
+ server.tool(
3850
+ "calculate_percentage_change",
3851
+ "Compute the percentage change from an original value to a new value as ((new - old) / |old|) * 100, plus the absolute difference, the direction (increase/decrease/no change), and the multiplier (new / old). The original value cannot be zero unless the new value is also zero.",
3852
+ {
3853
+ oldValue: z.number().describe("The original / starting value"),
3854
+ newValue: z.number().describe("The new / ending value")
3855
+ },
3856
+ async ({ oldValue, newValue }) => {
3857
+ const result = _calculatePercentageChangeMcp(oldValue, newValue);
3858
+ if ("error" in result) return errText(result);
3859
+ return text(JSON.stringify(result, null, 2));
3860
+ }
3861
+ );
3862
+ function _unescapePointerTokenMcp(token) {
3863
+ return token.replace(/~1/g, "/").replace(/~0/g, "~");
3864
+ }
3865
+ function _resolveJsonPointerMcp(json, pointer) {
3866
+ let parsed;
3867
+ try {
3868
+ parsed = JSON.parse(json);
3869
+ } catch {
3870
+ return { pointer, found: false, tokens: [], error: "Invalid JSON input" };
3871
+ }
3872
+ let ptr = pointer;
3873
+ if (ptr.startsWith("#")) {
3874
+ ptr = ptr.slice(1);
3875
+ try {
3876
+ ptr = decodeURIComponent(ptr);
3877
+ } catch {
3878
+ return { pointer, found: false, tokens: [], error: "Invalid percent-encoding in URI-fragment pointer" };
3879
+ }
3880
+ }
3881
+ if (ptr === "") return { pointer, found: true, value: parsed, tokens: [] };
3882
+ if (!ptr.startsWith("/")) return { pointer, found: false, tokens: [], error: "Pointer must be empty or start with '/' (RFC 6901)" };
3883
+ const tokens = ptr.split("/").slice(1).map(_unescapePointerTokenMcp);
3884
+ let current = parsed;
3885
+ for (const token of tokens) {
3886
+ if (Array.isArray(current)) {
3887
+ if (token === "-") return { pointer, found: false, tokens, failedAt: token, reason: '"-" refers to the nonexistent element after the end of the array' };
3888
+ if (!/^(0|[1-9][0-9]*)$/.test(token)) return { pointer, found: false, tokens, failedAt: token, reason: `"${token}" is not a valid array index` };
3889
+ const idx = Number(token);
3890
+ if (idx >= current.length) return { pointer, found: false, tokens, failedAt: token, reason: `array index ${idx} is out of bounds (length ${current.length})` };
3891
+ current = current[idx];
3892
+ } else if (current !== null && typeof current === "object") {
3893
+ const obj = current;
3894
+ if (!Object.prototype.hasOwnProperty.call(obj, token)) return { pointer, found: false, tokens, failedAt: token, reason: `key "${token}" not found` };
3895
+ current = obj[token];
3896
+ } else {
3897
+ return { pointer, found: false, tokens, failedAt: token, reason: `cannot descend into ${current === null ? "null" : typeof current} at "${token}"` };
3898
+ }
3899
+ }
3900
+ return { pointer, found: true, value: current, tokens };
3901
+ }
3902
+ server.tool(
3903
+ "resolve_json_pointer",
3904
+ 'Resolve an RFC 6901 JSON Pointer against a JSON document, in both the plain form ("" for the whole document, or "/foo/0") and the URI-fragment form ("#/foo/0"). Handles ~1 -> / and ~0 -> ~ escaping, and distinguishes an invalid document / malformed pointer from a syntactically valid pointer whose target is simply absent.',
3905
+ {
3906
+ json: z.string().describe("The JSON document to resolve against"),
3907
+ pointer: z.string().describe("The RFC 6901 JSON Pointer, e.g. /users/0/name")
3908
+ },
3909
+ async ({ json, pointer }) => {
3910
+ const result = _resolveJsonPointerMcp(json, pointer);
3911
+ if ("error" in result) return errText(result);
3912
+ return text(JSON.stringify(result, null, 2));
3913
+ }
3914
+ );
3828
3915
  var transport = new StdioServerTransport();
3829
3916
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilix-tech/mcp",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "MCP server exposing 125 Utilix developer tools to Claude, Cursor, VS Code Copilot, and any MCP-compatible AI assistant.",
5
5
  "author": "Utilix <hello@utilix.tech>",
6
6
  "license": "MIT",