From 3488bdb613fa8d0a5f7aed01ec0911f57c3b8805 Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Tue, 18 Mar 2025 10:07:43 +0000 Subject: [PATCH 1/2] feat: Add utility function to escape Unicode characters in tool results --- client/src/components/ToolsTab.tsx | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index ee9a4f9..ff4044f 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -8,15 +8,31 @@ import { Textarea } from "@/components/ui/textarea"; import DynamicJsonForm, { JsonSchemaType, JsonValue } from "./DynamicJsonForm"; import { generateDefaultValue } from "@/utils/schemaUtils"; import { + CallToolResultSchema, + CompatibilityCallToolResult, ListToolsResult, Tool, - CallToolResultSchema, } from "@modelcontextprotocol/sdk/types.js"; import { AlertCircle, Send } from "lucide-react"; import { useEffect, useState } from "react"; import ListPane from "./ListPane"; -import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js"; +// Utility function to escape Unicode characters +function escapeUnicode(obj: any): string { + return JSON.stringify( + obj, + (_key: string, value) => { + if (typeof value === "string") { + // Replace non-ASCII characters with their Unicode escape sequences + return value.replace(/[^\0-\x7F]/g, (char) => { + return "\\u" + ("0000" + char.charCodeAt(0).toString(16)).slice(-4); + }); + } + return value; + }, + 2, + ); +} const ToolsTab = ({ tools, @@ -54,7 +70,7 @@ const ToolsTab = ({ <>

Invalid Tool Result:

-              {JSON.stringify(toolResult, null, 2)}
+              {escapeUnicode(toolResult)}
             

Errors:

{parsedResult.error.errors.map((error, idx) => ( @@ -62,7 +78,7 @@ const ToolsTab = ({ key={idx} className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64" > - {JSON.stringify(error, null, 2)} + {escapeUnicode(error)} ))} @@ -101,7 +117,7 @@ const ToolsTab = ({ ) : (
-                    {JSON.stringify(item.resource, null, 2)}
+                    {escapeUnicode(item.resource)}
                   
))} @@ -113,7 +129,7 @@ const ToolsTab = ({ <>

Tool Result (Legacy):

-            {JSON.stringify(toolResult.toolResult, null, 2)}
+            {escapeUnicode(toolResult.toolResult)}
           
); From af44efb2362ed399ede821583415d2fa58d3c9f6 Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Fri, 21 Mar 2025 22:30:34 +0000 Subject: [PATCH 2/2] chore: extract utils escapeUnicode --- client/src/components/ToolsTab.tsx | 18 +------------ .../src/utils/__tests__/escapeUnicode.test.ts | 27 +++++++++++++++++++ client/src/utils/escapeUnicode.ts | 16 +++++++++++ package-lock.json | 1 + package.json | 1 + 5 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 client/src/utils/__tests__/escapeUnicode.test.ts create mode 100644 client/src/utils/escapeUnicode.ts diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index ff4044f..82ebdb0 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -16,23 +16,7 @@ import { import { AlertCircle, Send } from "lucide-react"; import { useEffect, useState } from "react"; import ListPane from "./ListPane"; - -// Utility function to escape Unicode characters -function escapeUnicode(obj: any): string { - return JSON.stringify( - obj, - (_key: string, value) => { - if (typeof value === "string") { - // Replace non-ASCII characters with their Unicode escape sequences - return value.replace(/[^\0-\x7F]/g, (char) => { - return "\\u" + ("0000" + char.charCodeAt(0).toString(16)).slice(-4); - }); - } - return value; - }, - 2, - ); -} +import { escapeUnicode } from "@/utils/escapeUnicode"; const ToolsTab = ({ tools, diff --git a/client/src/utils/__tests__/escapeUnicode.test.ts b/client/src/utils/__tests__/escapeUnicode.test.ts new file mode 100644 index 0000000..b2eb130 --- /dev/null +++ b/client/src/utils/__tests__/escapeUnicode.test.ts @@ -0,0 +1,27 @@ +import { escapeUnicode } from "../escapeUnicode"; + +describe("escapeUnicode", () => { + it("should escape Unicode characters in a string", () => { + const input = { text: "你好世界" }; + const expected = '{\n "text": "\\\\u4f60\\\\u597d\\\\u4e16\\\\u754c"\n}'; + expect(escapeUnicode(input)).toBe(expected); + }); + + it("should handle empty strings", () => { + const input = { text: "" }; + const expected = '{\n "text": ""\n}'; + expect(escapeUnicode(input)).toBe(expected); + }); + + it("should handle null and undefined values", () => { + const input = { text: null, value: undefined }; + const expected = '{\n "text": null\n}'; + expect(escapeUnicode(input)).toBe(expected); + }); + + it("should handle numbers and booleans", () => { + const input = { number: 123, boolean: true }; + const expected = '{\n "number": 123,\n "boolean": true\n}'; + expect(escapeUnicode(input)).toBe(expected); + }); +}); diff --git a/client/src/utils/escapeUnicode.ts b/client/src/utils/escapeUnicode.ts new file mode 100644 index 0000000..ed6fbd9 --- /dev/null +++ b/client/src/utils/escapeUnicode.ts @@ -0,0 +1,16 @@ +// Utility function to escape Unicode characters +export function escapeUnicode(obj: unknown): string { + return JSON.stringify( + obj, + (_key: string, value) => { + if (typeof value === "string") { + // Replace non-ASCII characters with their Unicode escape sequences + return value.replace(/[^\0-\x7F]/g, (char) => { + return "\\u" + ("0000" + char.charCodeAt(0).toString(16)).slice(-4); + }); + } + return value; + }, + 2, + ); +} diff --git a/package-lock.json b/package-lock.json index 21c9c30..68929c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "mcp-inspector": "bin/cli.js" }, "devDependencies": { + "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/shell-quote": "^1.7.5", "prettier": "3.3.3" diff --git a/package.json b/package.json index 3f40d2e..e3bce92 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "ts-node": "^10.9.2" }, "devDependencies": { + "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/shell-quote": "^1.7.5", "prettier": "3.3.3"