Skip to content

Commit 008204f

Browse files
authored
Merge pull request #193 from seuros/main
feat: Add utility function to escape Unicode characters in tool results
2 parents 043f604 + af44efb commit 008204f

File tree

5 files changed

+52
-7
lines changed

5 files changed

+52
-7
lines changed

client/src/components/ToolsTab.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import { Textarea } from "@/components/ui/textarea";
88
import DynamicJsonForm, { JsonSchemaType, JsonValue } from "./DynamicJsonForm";
99
import { generateDefaultValue } from "@/utils/schemaUtils";
1010
import {
11+
CallToolResultSchema,
12+
CompatibilityCallToolResult,
1113
ListToolsResult,
1214
Tool,
13-
CallToolResultSchema,
1415
} from "@modelcontextprotocol/sdk/types.js";
1516
import { AlertCircle, Send } from "lucide-react";
1617
import { useEffect, useState } from "react";
1718
import ListPane from "./ListPane";
18-
19-
import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js";
19+
import { escapeUnicode } from "@/utils/escapeUnicode";
2020

2121
const ToolsTab = ({
2222
tools,
@@ -54,15 +54,15 @@ const ToolsTab = ({
5454
<>
5555
<h4 className="font-semibold mb-2">Invalid Tool Result:</h4>
5656
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
57-
{JSON.stringify(toolResult, null, 2)}
57+
{escapeUnicode(toolResult)}
5858
</pre>
5959
<h4 className="font-semibold mb-2">Errors:</h4>
6060
{parsedResult.error.errors.map((error, idx) => (
6161
<pre
6262
key={idx}
6363
className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64"
6464
>
65-
{JSON.stringify(error, null, 2)}
65+
{escapeUnicode(error)}
6666
</pre>
6767
))}
6868
</>
@@ -101,7 +101,7 @@ const ToolsTab = ({
101101
</audio>
102102
) : (
103103
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 whitespace-pre-wrap break-words p-4 rounded text-sm overflow-auto max-h-64">
104-
{JSON.stringify(item.resource, null, 2)}
104+
{escapeUnicode(item.resource)}
105105
</pre>
106106
))}
107107
</div>
@@ -113,7 +113,7 @@ const ToolsTab = ({
113113
<>
114114
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
115115
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
116-
{JSON.stringify(toolResult.toolResult, null, 2)}
116+
{escapeUnicode(toolResult.toolResult)}
117117
</pre>
118118
</>
119119
);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { escapeUnicode } from "../escapeUnicode";
2+
3+
describe("escapeUnicode", () => {
4+
it("should escape Unicode characters in a string", () => {
5+
const input = { text: "你好世界" };
6+
const expected = '{\n "text": "\\\\u4f60\\\\u597d\\\\u4e16\\\\u754c"\n}';
7+
expect(escapeUnicode(input)).toBe(expected);
8+
});
9+
10+
it("should handle empty strings", () => {
11+
const input = { text: "" };
12+
const expected = '{\n "text": ""\n}';
13+
expect(escapeUnicode(input)).toBe(expected);
14+
});
15+
16+
it("should handle null and undefined values", () => {
17+
const input = { text: null, value: undefined };
18+
const expected = '{\n "text": null\n}';
19+
expect(escapeUnicode(input)).toBe(expected);
20+
});
21+
22+
it("should handle numbers and booleans", () => {
23+
const input = { number: 123, boolean: true };
24+
const expected = '{\n "number": 123,\n "boolean": true\n}';
25+
expect(escapeUnicode(input)).toBe(expected);
26+
});
27+
});

client/src/utils/escapeUnicode.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Utility function to escape Unicode characters
2+
export function escapeUnicode(obj: unknown): string {
3+
return JSON.stringify(
4+
obj,
5+
(_key: string, value) => {
6+
if (typeof value === "string") {
7+
// Replace non-ASCII characters with their Unicode escape sequences
8+
return value.replace(/[^\0-\x7F]/g, (char) => {
9+
return "\\u" + ("0000" + char.charCodeAt(0).toString(16)).slice(-4);
10+
});
11+
}
12+
return value;
13+
},
14+
2,
15+
);
16+
}

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"ts-node": "^10.9.2"
4343
},
4444
"devDependencies": {
45+
"@types/jest": "^29.5.14",
4546
"@types/node": "^22.7.5",
4647
"@types/shell-quote": "^1.7.5",
4748
"prettier": "3.3.3"

0 commit comments

Comments
 (0)