@utilix-tech/mcp 0.57.0 → 0.58.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.58.0
6
+ - Add `apply_json_merge_patch` tool: apply an RFC 7396 JSON Merge Patch document to a target JSON document, with null-valued patch keys removing the matching target key.
7
+ - Add `generate_csp_nonce` tool: generate a cryptographically random, base64-encoded Content-Security-Policy nonce with ready-to-paste header directive and script/style tag snippets.
8
+
5
9
  ## 0.57.0
6
10
  - Add `build_accept_language`, `parse_accept_language` tools: build an Accept-Language request-header value from locale/quality pairs sorted by descending preference, or parse an existing one into its ranked entries.
7
11
  - Add `calculate_blended_loan_rate` tool: compute the single weighted-average interest rate across a list of loan balances, plus combined monthly and annual interest accrual.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/mcp
2
2
 
3
- MCP server exposing 203 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
3
+ MCP server exposing 205 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 (15 tools)
78
+ ### JSON (16 tools)
79
79
  | Tool | Description |
80
80
  |------|-------------|
81
81
  | `format_json` | Pretty-print and validate a JSON string |
@@ -85,6 +85,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
85
85
  | `csv_to_json` | Convert CSV text to a JSON array |
86
86
  | `jsonpath` | Evaluate a JSONPath expression |
87
87
  | `resolve_json_pointer` | Resolve an RFC 6901 JSON Pointer against a JSON document |
88
+ | `apply_json_merge_patch` | Apply an RFC 7396 JSON Merge Patch document to a target JSON document |
88
89
  | `validate_json` | Validate JSON against a JSON Schema |
89
90
  | `yaml_to_json` | Convert YAML to JSON |
90
91
  | `json_to_yaml` | Convert JSON to YAML |
@@ -120,7 +121,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
120
121
  | `generate_sri_hash` | Compute a Subresource Integrity hash (SHA-256/384/512) for a script or stylesheet's content, formatted for an HTML `integrity` attribute |
121
122
  | `generate_etag` | Compute a content-hash ETag (MD5/SHA-1/SHA-256) for a response header, with an optional weak-validator prefix |
122
123
 
123
- ### Generators (6 tools)
124
+ ### Generators (7 tools)
124
125
  | Tool | Description |
125
126
  |------|-------------|
126
127
  | `generate_uuid` | Generate UUID v4 or v7 |
@@ -129,6 +130,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
129
130
  | `estimate_password_entropy` | Estimate a password's entropy in bits, strength label, and crack-time estimates |
130
131
  | `generate_qr` | Generate a QR code as an SVG string |
131
132
  | `generate_random_data` | Generate random mock data: names, emails, UUIDs, IPs, etc. |
133
+ | `generate_csp_nonce` | Generate a cryptographically random CSP nonce with ready-to-paste header directive and script/style tag snippets |
132
134
 
133
135
  ### Text (16 tools)
134
136
  | Tool | Description |
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import { z } from "zod";
7
- import { createHash } from "crypto";
7
+ import { createHash, randomBytes } from "crypto";
8
8
  import * as yaml from "js-yaml";
9
9
  import {
10
10
  parseJson,
@@ -4655,6 +4655,45 @@ server.tool(
4655
4655
  return text(JSON.stringify(result, null, 2));
4656
4656
  }
4657
4657
  );
4658
+ function _isMergePatchObjectMcp(value) {
4659
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4660
+ }
4661
+ function _mergeJsonPatchMcp(target, patch) {
4662
+ if (!_isMergePatchObjectMcp(patch)) return patch;
4663
+ const result = _isMergePatchObjectMcp(target) ? { ...target } : {};
4664
+ for (const key of Object.keys(patch)) {
4665
+ const value = patch[key];
4666
+ if (value === null) {
4667
+ delete result[key];
4668
+ } else {
4669
+ result[key] = _mergeJsonPatchMcp(result[key], value);
4670
+ }
4671
+ }
4672
+ return result;
4673
+ }
4674
+ server.tool(
4675
+ "apply_json_merge_patch",
4676
+ "Apply an RFC 7396 JSON Merge Patch document to a target JSON document and return the merged result. A null-valued key in the patch removes that key from the target; a patch that is not itself a JSON object replaces the target wholesale, which is how arrays are replaced rather than merged element by element.",
4677
+ {
4678
+ target: z.string().describe("The target JSON document, as a JSON string"),
4679
+ patch: z.string().describe("The RFC 7396 JSON Merge Patch document, as a JSON string")
4680
+ },
4681
+ async ({ target, patch }) => {
4682
+ let targetParsed;
4683
+ try {
4684
+ targetParsed = JSON.parse(target);
4685
+ } catch {
4686
+ return errText({ error: "Target is not valid JSON" });
4687
+ }
4688
+ let patchParsed;
4689
+ try {
4690
+ patchParsed = JSON.parse(patch);
4691
+ } catch {
4692
+ return errText({ error: "Patch is not valid JSON" });
4693
+ }
4694
+ return text(JSON.stringify({ result: _mergeJsonPatchMcp(targetParsed, patchParsed) }, null, 2));
4695
+ }
4696
+ );
4658
4697
  function _convertAprApyMcp(rate, compoundsPerYear, direction) {
4659
4698
  if (!Number.isFinite(rate) || rate < 0) return { error: "Rate must be zero or a positive number" };
4660
4699
  if (!Number.isInteger(compoundsPerYear) || compoundsPerYear <= 0) return { error: "Compounding frequency must be a positive whole number of periods per year" };
@@ -9461,5 +9500,24 @@ server.tool(
9461
9500
  return text(JSON.stringify(result, null, 2));
9462
9501
  }
9463
9502
  );
9503
+ server.tool(
9504
+ "generate_csp_nonce",
9505
+ 'Generate a cryptographically random, base64-encoded nonce for a Content-Security-Policy script-src or style-src directive, along with ready-to-paste header directive and <script>/<style nonce="..."> tag snippets. Generates a fresh, unique value on every call.',
9506
+ {
9507
+ byteLength: z.number().int().min(8).max(64).optional().describe("Number of random bytes to encode (default 16 = 128 bits, the CSP spec's recommended minimum)")
9508
+ },
9509
+ async ({ byteLength }) => {
9510
+ const length = byteLength ?? 16;
9511
+ const nonce = randomBytes(length).toString("base64");
9512
+ return text(JSON.stringify({
9513
+ nonce,
9514
+ byteLength: length,
9515
+ scriptSrcDirective: `script-src 'nonce-${nonce}'`,
9516
+ styleSrcDirective: `style-src 'nonce-${nonce}'`,
9517
+ scriptTag: `<script nonce="${nonce}">`,
9518
+ styleTag: `<style nonce="${nonce}">`
9519
+ }, null, 2));
9520
+ }
9521
+ );
9464
9522
  var transport = new StdioServerTransport();
9465
9523
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilix-tech/mcp",
3
- "version": "0.57.0",
3
+ "version": "0.58.0",
4
4
  "description": "MCP server exposing 198 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",