Merge branch 'main' into main
This commit is contained in:
@@ -50,7 +50,7 @@ import { InspectorConfig } from "./lib/configurationTypes";
|
|||||||
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const PROXY_PORT = params.get("proxyPort") ?? "3000";
|
const PROXY_PORT = params.get("proxyPort") ?? "3000";
|
||||||
const PROXY_SERVER_URL = `http://localhost:${PROXY_PORT}`;
|
const PROXY_SERVER_URL = `http://${window.location.hostname}:${PROXY_PORT}`;
|
||||||
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import { Textarea } from "@/components/ui/textarea";
|
|||||||
import DynamicJsonForm, { JsonSchemaType, JsonValue } from "./DynamicJsonForm";
|
import DynamicJsonForm, { JsonSchemaType, JsonValue } from "./DynamicJsonForm";
|
||||||
import { generateDefaultValue } from "@/utils/schemaUtils";
|
import { generateDefaultValue } from "@/utils/schemaUtils";
|
||||||
import {
|
import {
|
||||||
|
CallToolResultSchema,
|
||||||
|
CompatibilityCallToolResult,
|
||||||
ListToolsResult,
|
ListToolsResult,
|
||||||
Tool,
|
Tool,
|
||||||
CallToolResultSchema,
|
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
import { AlertCircle, Send } from "lucide-react";
|
import { AlertCircle, Send } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
|
import { escapeUnicode } from "@/utils/escapeUnicode";
|
||||||
import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
|
|
||||||
const ToolsTab = ({
|
const ToolsTab = ({
|
||||||
tools,
|
tools,
|
||||||
@@ -54,7 +54,7 @@ const ToolsTab = ({
|
|||||||
<>
|
<>
|
||||||
<h4 className="font-semibold mb-2">Invalid Tool Result:</h4>
|
<h4 className="font-semibold mb-2">Invalid Tool Result:</h4>
|
||||||
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
|
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
|
||||||
{JSON.stringify(toolResult, null, 2)}
|
{escapeUnicode(toolResult)}
|
||||||
</pre>
|
</pre>
|
||||||
<h4 className="font-semibold mb-2">Errors:</h4>
|
<h4 className="font-semibold mb-2">Errors:</h4>
|
||||||
{parsedResult.error.errors.map((error, idx) => (
|
{parsedResult.error.errors.map((error, idx) => (
|
||||||
@@ -62,7 +62,7 @@ const ToolsTab = ({
|
|||||||
key={idx}
|
key={idx}
|
||||||
className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64"
|
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)}
|
||||||
</pre>
|
</pre>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@@ -101,7 +101,7 @@ const ToolsTab = ({
|
|||||||
</audio>
|
</audio>
|
||||||
) : (
|
) : (
|
||||||
<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">
|
<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">
|
||||||
{JSON.stringify(item.resource, null, 2)}
|
{escapeUnicode(item.resource)}
|
||||||
</pre>
|
</pre>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -113,7 +113,7 @@ const ToolsTab = ({
|
|||||||
<>
|
<>
|
||||||
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
|
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
|
||||||
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
|
<pre className="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 p-4 rounded text-sm overflow-auto max-h-64">
|
||||||
{JSON.stringify(toolResult.toolResult, null, 2)}
|
{escapeUnicode(toolResult.toolResult)}
|
||||||
</pre>
|
</pre>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
27
client/src/utils/__tests__/escapeUnicode.test.ts
Normal file
27
client/src/utils/__tests__/escapeUnicode.test.ts
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
16
client/src/utils/escapeUnicode.ts
Normal file
16
client/src/utils/escapeUnicode.ts
Normal file
@@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@ import { defineConfig } from "vite";
|
|||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {},
|
server: {
|
||||||
|
host: true,
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
|||||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -24,6 +24,7 @@
|
|||||||
"mcp-inspector": "bin/cli.js"
|
"mcp-inspector": "bin/cli.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"@types/shell-quote": "^1.7.5",
|
"@types/shell-quote": "^1.7.5",
|
||||||
"prettier": "3.3.3"
|
"prettier": "3.3.3"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
"ts-node": "^10.9.2"
|
"ts-node": "^10.9.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"@types/shell-quote": "^1.7.5",
|
"@types/shell-quote": "^1.7.5",
|
||||||
"prettier": "3.3.3"
|
"prettier": "3.3.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user