From d7cc0fae2a230141f9fd50f5182958ca5586542d Mon Sep 17 00:00:00 2001 From: Baruch Odem Date: Fri, 30 May 2025 15:08:40 +0300 Subject: [PATCH 01/91] chore: Add .node-version file and update workflows to use it --- .github/workflows/main.yml | 4 ++-- .node-version | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .node-version diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8efb6773..54addc87 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 18 + node-version-file: .node-version cache: npm # Working around https://github.com/npm/cli/issues/4828 @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version-file: .node-version cache: npm registry-url: "https://registry.npmjs.org" diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..980f29c2 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22.x.x From b555e41c0b3c87cbc08cade9a92e587ee4912155 Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 09:03:02 -0700 Subject: [PATCH 02/91] Address the schema architecture crisis --- client/src/components/DynamicJsonForm.tsx | 89 ++++++++++++++++++----- client/src/components/ToolsTab.tsx | 8 +- client/src/utils/jsonUtils.ts | 2 +- client/src/utils/schemaUtils.ts | 55 +++++++++----- 4 files changed, 114 insertions(+), 40 deletions(-) diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index 6a5993c3..bd8c6cfd 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -113,6 +113,8 @@ const DynamicJsonForm = ({ currentValue: JsonValue, path: string[] = [], depth: number = 0, + parentSchema?: JsonSchemaType, + propertyName?: string, ) => { if ( depth >= maxDepth && @@ -122,7 +124,7 @@ const DynamicJsonForm = ({ return ( { const val = e.target.value; - // Allow clearing non-required fields by setting undefined - // This preserves the distinction between empty string and unset - if (!val && !propSchema.required) { - handleFieldChange(path, undefined); - } else { - handleFieldChange(path, val); - } + // Always allow setting string values, including empty strings + handleFieldChange(path, val); }} placeholder={propSchema.description} - required={propSchema.required} + required={isRequired} /> ); case "number": @@ -167,9 +167,7 @@ const DynamicJsonForm = ({ value={(currentValue as number)?.toString() ?? ""} onChange={(e) => { const val = e.target.value; - // Allow clearing non-required number fields - // This preserves the distinction between 0 and unset - if (!val && !propSchema.required) { + if (!val && !isRequired) { handleFieldChange(path, undefined); } else { const num = Number(val); @@ -179,7 +177,7 @@ const DynamicJsonForm = ({ } }} placeholder={propSchema.description} - required={propSchema.required} + required={isRequired} /> ); case "integer": @@ -190,9 +188,7 @@ const DynamicJsonForm = ({ value={(currentValue as number)?.toString() ?? ""} onChange={(e) => { const val = e.target.value; - // Allow clearing non-required integer fields - // This preserves the distinction between 0 and unset - if (!val && !propSchema.required) { + if (!val && !isRequired) { handleFieldChange(path, undefined); } else { const num = Number(val); @@ -203,7 +199,7 @@ const DynamicJsonForm = ({ } }} placeholder={propSchema.description} - required={propSchema.required} + required={isRequired} /> ); case "boolean": @@ -213,7 +209,64 @@ const DynamicJsonForm = ({ checked={(currentValue as boolean) ?? false} onChange={(e) => handleFieldChange(path, e.target.checked)} className="w-4 h-4" - required={propSchema.required} + required={isRequired} + /> + ); + case "object": + if (!propSchema.properties) { + return ( + { + try { + const parsed = JSON.parse(newValue); + handleFieldChange(path, parsed); + setJsonError(undefined); + } catch (err) { + setJsonError(err instanceof Error ? err.message : "Invalid JSON"); + } + }} + error={jsonError} + /> + ); + } + + return ( +
+ {Object.entries(propSchema.properties).map(([key, subSchema]) => ( +
+ + {renderFormFields( + subSchema as JsonSchemaType, + (currentValue as Record)?.[key], + [...path, key], + depth + 1, + propSchema, + key, + )} +
+ ))} +
+ ); + case "array": + return ( + { + try { + const parsed = JSON.parse(newValue); + handleFieldChange(path, parsed); + setJsonError(undefined); + } catch (err) { + setJsonError(err instanceof Error ? err.message : "Invalid JSON"); + } + }} + error={jsonError} /> ); default: diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 8a7f6578..93073da3 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -7,7 +7,7 @@ import { TabsContent } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; import DynamicJsonForm from "./DynamicJsonForm"; import type { JsonValue, JsonSchemaType } from "@/utils/jsonUtils"; -import { generateDefaultValue } from "@/utils/schemaUtils"; +import { generateDefaultValue, isPropertyRequired } from "@/utils/schemaUtils"; import { CompatibilityCallToolResult, ListToolsResult, @@ -48,7 +48,7 @@ const ToolsTab = ({ selectedTool?.inputSchema.properties ?? [], ).map(([key, value]) => [ key, - generateDefaultValue(value as JsonSchemaType), + generateDefaultValue(value as JsonSchemaType, key, selectedTool?.inputSchema as JsonSchemaType), ]); setParams(Object.fromEntries(params)); }, [selectedTool]); @@ -92,13 +92,15 @@ const ToolsTab = ({ {Object.entries(selectedTool.inputSchema.properties ?? []).map( ([key, value]) => { const prop = value as JsonSchemaType; + const inputSchema = selectedTool.inputSchema as JsonSchemaType; + const required = isPropertyRequired(key, inputSchema); return (
{prop.type === "boolean" ? (
diff --git a/client/src/utils/jsonUtils.ts b/client/src/utils/jsonUtils.ts index 28cbf303..83317938 100644 --- a/client/src/utils/jsonUtils.ts +++ b/client/src/utils/jsonUtils.ts @@ -17,7 +17,7 @@ export type JsonSchemaType = { | "object" | "null"; description?: string; - required?: boolean; + required?: string[]; default?: JsonValue; properties?: Record; items?: JsonSchemaType; diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index 30210532..fe643b95 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -81,46 +81,65 @@ export function hasOutputSchema(toolName: string): boolean { /** * Generates a default value based on a JSON schema type * @param schema The JSON schema definition - * @returns A default value matching the schema type, or null for non-required fields + * @param propertyName Optional property name for checking if it's required in parent schema + * @param parentSchema Optional parent schema to check required array + * @returns A default value matching the schema type */ -export function generateDefaultValue(schema: JsonSchemaType): JsonValue { - if ("default" in schema) { +export function generateDefaultValue( + schema: JsonSchemaType, + propertyName?: string, + parentSchema?: JsonSchemaType +): JsonValue { + if ("default" in schema && schema.default !== undefined) { return schema.default; } - if (!schema.required) { - if (schema.type === "array") return []; - if (schema.type === "object") return {}; - return undefined; - } + // Check if this property is required in the parent schema + const isRequired = parentSchema?.required?.includes(propertyName || "") ?? false; switch (schema.type) { case "string": - return ""; + return isRequired ? "" : undefined; case "number": case "integer": - return 0; + return isRequired ? 0 : undefined; case "boolean": - return false; + return isRequired ? false : undefined; case "array": return []; case "object": { if (!schema.properties) return {}; const obj: JsonObject = {}; - Object.entries(schema.properties) - .filter(([, prop]) => prop.required) - .forEach(([key, prop]) => { - const value = generateDefaultValue(prop); - obj[key] = value; - }); + // Only include properties that are required according to the schema's required array + Object.entries(schema.properties).forEach(([key, prop]) => { + const isPropertyRequired = schema.required?.includes(key) ?? false; + if (isPropertyRequired) { + const value = generateDefaultValue(prop, key, schema); + if (value !== undefined) { + obj[key] = value; + } + } + }); return obj; } - default: + case "null": return null; + default: + return undefined; } } +/** + * Helper function to check if a property is required in a schema + * @param propertyName The name of the property to check + * @param schema The parent schema containing the required array + * @returns true if the property is required, false otherwise + */ +export function isPropertyRequired(propertyName: string, schema: JsonSchemaType): boolean { + return schema.required?.includes(propertyName) ?? false; +} + /** * Formats a field key into a human-readable label * @param key The field key to format From daa863ddfcd38c61a2d4dddfea574571d0f26b02 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Sun, 1 Jun 2025 13:27:16 -0500 Subject: [PATCH 03/91] feat: add transport option to cli --- cli/src/index.ts | 48 +++++++++++++++++++++++++++++++++++++++++--- cli/src/transport.ts | 20 ++++++++++++++++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/cli/src/index.ts b/cli/src/index.ts index bda1e8f7..5d5dcf8b 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -29,9 +29,13 @@ type Args = { logLevel?: LogLevel; toolName?: string; toolArg?: Record; + transport?: "sse" | "stdio" | "http"; }; -function createTransportOptions(target: string[]): TransportOptions { +function createTransportOptions( + target: string[], + transport?: "sse" | "stdio" | "http", +): TransportOptions { if (target.length === 0) { throw new Error( "Target is required. Specify a URL or a command to execute.", @@ -50,8 +54,30 @@ function createTransportOptions(target: string[]): TransportOptions { throw new Error("Arguments cannot be passed to a URL-based MCP server."); } + let transportType: "sse" | "stdio" | "http"; + if (transport) { + if (!isUrl && transport !== "stdio") { + throw new Error("Only stdio transport can be used with local commands."); + } + if (isUrl && transport === "stdio") { + throw new Error("stdio transport cannot be used with URLs."); + } + transportType = transport; + } else if (isUrl) { + const url = new URL(command); + if (url.pathname.endsWith("/mcp")) { + transportType = "http"; + } else if (url.pathname.endsWith("/sse")) { + transportType = "sse"; + } else { + transportType = "sse"; + } + } else { + transportType = "stdio"; + } + return { - transportType: isUrl ? "sse" : "stdio", + transportType, command: isUrl ? undefined : command, args: isUrl ? undefined : commandArgs, url: isUrl ? command : undefined, @@ -59,7 +85,7 @@ function createTransportOptions(target: string[]): TransportOptions { } async function callMethod(args: Args): Promise { - const transportOptions = createTransportOptions(args.target); + const transportOptions = createTransportOptions(args.target, args.transport); const transport = createTransport(transportOptions); const client = new Client({ name: "inspector-cli", @@ -214,6 +240,22 @@ function parseArgs(): Args { return value as LogLevel; }, + ) + // + // Transport options + // + .option( + "--transport ", + "Transport type (sse, http, or stdio). Auto-detected from URL: /mcp → http, /sse → sse, commands → stdio", + (value: string) => { + const validTransports = ["sse", "http", "stdio"]; + if (!validTransports.includes(value)) { + throw new Error( + `Invalid transport type: ${value}. Valid types are: ${validTransports.join(", ")}`, + ); + } + return value as "sse" | "http" | "stdio"; + }, ); // Parse only the arguments before -- diff --git a/cli/src/transport.ts b/cli/src/transport.ts index e693f246..e0d67b4e 100644 --- a/cli/src/transport.ts +++ b/cli/src/transport.ts @@ -3,11 +3,12 @@ import { getDefaultEnvironment, StdioClientTransport, } from "@modelcontextprotocol/sdk/client/stdio.js"; +import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; import { findActualExecutable } from "spawn-rx"; export type TransportOptions = { - transportType: "sse" | "stdio"; + transportType: "sse" | "stdio" | "http"; command?: string; args?: string[]; url?: string; @@ -15,11 +16,22 @@ export type TransportOptions = { function createSSETransport(options: TransportOptions): Transport { const baseUrl = new URL(options.url ?? ""); - const sseUrl = new URL("/sse", baseUrl); + const sseUrl = baseUrl.pathname.endsWith("/sse") + ? baseUrl + : new URL("/sse", baseUrl); return new SSEClientTransport(sseUrl); } +function createHTTPTransport(options: TransportOptions): Transport { + const baseUrl = new URL(options.url ?? ""); + const mcpUrl = baseUrl.pathname.endsWith("/mcp") + ? baseUrl + : new URL("/mcp", baseUrl); + + return new StreamableHTTPClientTransport(mcpUrl); +} + function createStdioTransport(options: TransportOptions): Transport { let args: string[] = []; @@ -67,6 +79,10 @@ export function createTransport(options: TransportOptions): Transport { return createSSETransport(options); } + if (transportType === "http") { + return createHTTPTransport(options); + } + throw new Error(`Unsupported transport type: ${transportType}`); } catch (error) { throw new Error( From 5b674cfe351b76f976bef8bac03f6619167d14a2 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Sun, 1 Jun 2025 13:44:19 -0500 Subject: [PATCH 04/91] feat: update README with example for http transport --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d5017dc..56b4f59b 100644 --- a/README.md +++ b/README.md @@ -252,9 +252,12 @@ npx @modelcontextprotocol/inspector --cli node build/index.js --method resources # List available prompts npx @modelcontextprotocol/inspector --cli node build/index.js --method prompts/list -# Connect to a remote MCP server +# Connect to a remote MCP server (default is SSE transport) npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com +# Connect to a remote MCP server (with Streamable HTTP transport) +npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --transport http + # Call a tool on a remote server npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --method tools/call --tool-name remotetool --tool-arg param=value From 990bc0f7fdae85c91300ffd6b086ae55e5b6e52c Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 15:41:30 -0700 Subject: [PATCH 05/91] Fix formatting --- client/src/components/DynamicJsonForm.tsx | 16 +++++++++++----- client/src/components/ToolsTab.tsx | 14 +++++++++++--- client/src/utils/schemaUtils.ts | 10 +++++++--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index bd8c6cfd..0a73a989 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -124,7 +124,8 @@ const DynamicJsonForm = ({ return ( ); } - + return (
{Object.entries(propSchema.properties).map(([key, subSchema]) => ( @@ -263,7 +267,9 @@ const DynamicJsonForm = ({ handleFieldChange(path, parsed); setJsonError(undefined); } catch (err) { - setJsonError(err instanceof Error ? err.message : "Invalid JSON"); + setJsonError( + err instanceof Error ? err.message : "Invalid JSON", + ); } }} error={jsonError} diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 93073da3..cf85e4eb 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -48,7 +48,11 @@ const ToolsTab = ({ selectedTool?.inputSchema.properties ?? [], ).map(([key, value]) => [ key, - generateDefaultValue(value as JsonSchemaType, key, selectedTool?.inputSchema as JsonSchemaType), + generateDefaultValue( + value as JsonSchemaType, + key, + selectedTool?.inputSchema as JsonSchemaType, + ), ]); setParams(Object.fromEntries(params)); }, [selectedTool]); @@ -92,7 +96,8 @@ const ToolsTab = ({ {Object.entries(selectedTool.inputSchema.properties ?? []).map( ([key, value]) => { const prop = value as JsonSchemaType; - const inputSchema = selectedTool.inputSchema as JsonSchemaType; + const inputSchema = + selectedTool.inputSchema as JsonSchemaType; const required = isPropertyRequired(key, inputSchema); return (
@@ -100,7 +105,10 @@ const ToolsTab = ({ htmlFor={key} className="block text-sm font-medium text-gray-700 dark:text-gray-300" > - {key}{required && *} + {key} + {required && ( + * + )} {prop.type === "boolean" ? (
diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index fe643b95..c47022e0 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -88,14 +88,15 @@ export function hasOutputSchema(toolName: string): boolean { export function generateDefaultValue( schema: JsonSchemaType, propertyName?: string, - parentSchema?: JsonSchemaType + parentSchema?: JsonSchemaType, ): JsonValue { if ("default" in schema && schema.default !== undefined) { return schema.default; } // Check if this property is required in the parent schema - const isRequired = parentSchema?.required?.includes(propertyName || "") ?? false; + const isRequired = + parentSchema?.required?.includes(propertyName || "") ?? false; switch (schema.type) { case "string": @@ -136,7 +137,10 @@ export function generateDefaultValue( * @param schema The parent schema containing the required array * @returns true if the property is required, false otherwise */ -export function isPropertyRequired(propertyName: string, schema: JsonSchemaType): boolean { +export function isPropertyRequired( + propertyName: string, + schema: JsonSchemaType, +): boolean { return schema.required?.includes(propertyName) ?? false; } From 06af321530a541d469e7683acbbbc372bcdbd87a Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 16:07:45 -0700 Subject: [PATCH 06/91] Fix tests --- .../src/utils/__tests__/schemaUtils.test.ts | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/client/src/utils/__tests__/schemaUtils.test.ts b/client/src/utils/__tests__/schemaUtils.test.ts index ca6b65ca..ed2c50f9 100644 --- a/client/src/utils/__tests__/schemaUtils.test.ts +++ b/client/src/utils/__tests__/schemaUtils.test.ts @@ -11,60 +11,64 @@ import type { Tool } from "@modelcontextprotocol/sdk/types.js"; describe("generateDefaultValue", () => { test("generates default string", () => { - expect(generateDefaultValue({ type: "string", required: true })).toBe(""); + const parentSchema = { type: "object" as const, required: ["testProp"] }; + expect(generateDefaultValue({ type: "string" }, "testProp", parentSchema)).toBe(""); }); test("generates default number", () => { - expect(generateDefaultValue({ type: "number", required: true })).toBe(0); + const parentSchema = { type: "object" as const, required: ["testProp"] }; + expect(generateDefaultValue({ type: "number" }, "testProp", parentSchema)).toBe(0); }); test("generates default integer", () => { - expect(generateDefaultValue({ type: "integer", required: true })).toBe(0); + const parentSchema = { type: "object" as const, required: ["testProp"] }; + expect(generateDefaultValue({ type: "integer" }, "testProp", parentSchema)).toBe(0); }); test("generates default boolean", () => { - expect(generateDefaultValue({ type: "boolean", required: true })).toBe( + const parentSchema = { type: "object" as const, required: ["testProp"] }; + expect(generateDefaultValue({ type: "boolean" }, "testProp", parentSchema)).toBe( false, ); }); test("generates default array", () => { - expect(generateDefaultValue({ type: "array", required: true })).toEqual([]); + expect(generateDefaultValue({ type: "array" })).toEqual([]); }); test("generates default empty object", () => { - expect(generateDefaultValue({ type: "object", required: true })).toEqual( + expect(generateDefaultValue({ type: "object" })).toEqual( {}, ); }); test("generates default null for unknown types", () => { // @ts-expect-error Testing with invalid type - expect(generateDefaultValue({ type: "unknown", required: true })).toBe( - null, + expect(generateDefaultValue({ type: "unknown" })).toBe( + undefined, ); }); test("generates empty array for non-required array", () => { - expect(generateDefaultValue({ type: "array", required: false })).toEqual( + expect(generateDefaultValue({ type: "array" })).toEqual( [], ); }); test("generates empty object for non-required object", () => { - expect(generateDefaultValue({ type: "object", required: false })).toEqual( + expect(generateDefaultValue({ type: "object" })).toEqual( {}, ); }); - test("generates null for non-required primitive types", () => { - expect(generateDefaultValue({ type: "string", required: false })).toBe( + test("generates undefined for non-required primitive types", () => { + expect(generateDefaultValue({ type: "string" })).toBe( undefined, ); - expect(generateDefaultValue({ type: "number", required: false })).toBe( + expect(generateDefaultValue({ type: "number" })).toBe( undefined, ); - expect(generateDefaultValue({ type: "boolean", required: false })).toBe( + expect(generateDefaultValue({ type: "boolean" })).toBe( undefined, ); }); @@ -72,11 +76,11 @@ describe("generateDefaultValue", () => { test("generates object with properties", () => { const schema: JsonSchemaType = { type: "object", - required: true, + required: ["name", "age", "isActive"], properties: { - name: { type: "string", required: true }, - age: { type: "number", required: true }, - isActive: { type: "boolean", required: true }, + name: { type: "string" }, + age: { type: "number" }, + isActive: { type: "boolean" }, }, }; expect(generateDefaultValue(schema)).toEqual({ @@ -89,18 +93,18 @@ describe("generateDefaultValue", () => { test("handles nested objects", () => { const schema: JsonSchemaType = { type: "object", - required: true, + required: ["user"], properties: { user: { type: "object", - required: true, + required: ["name", "address"], properties: { - name: { type: "string", required: true }, + name: { type: "string" }, address: { type: "object", - required: true, + required: ["city"], properties: { - city: { type: "string", required: true }, + city: { type: "string" }, }, }, }, From e5e2edc4a1c223960980878be56318822ad8772e Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 16:11:20 -0700 Subject: [PATCH 07/91] Fix formatting --- .../src/utils/__tests__/schemaUtils.test.ts | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/client/src/utils/__tests__/schemaUtils.test.ts b/client/src/utils/__tests__/schemaUtils.test.ts index ed2c50f9..133e25ec 100644 --- a/client/src/utils/__tests__/schemaUtils.test.ts +++ b/client/src/utils/__tests__/schemaUtils.test.ts @@ -12,24 +12,30 @@ import type { Tool } from "@modelcontextprotocol/sdk/types.js"; describe("generateDefaultValue", () => { test("generates default string", () => { const parentSchema = { type: "object" as const, required: ["testProp"] }; - expect(generateDefaultValue({ type: "string" }, "testProp", parentSchema)).toBe(""); + expect( + generateDefaultValue({ type: "string" }, "testProp", parentSchema), + ).toBe(""); }); test("generates default number", () => { const parentSchema = { type: "object" as const, required: ["testProp"] }; - expect(generateDefaultValue({ type: "number" }, "testProp", parentSchema)).toBe(0); + expect( + generateDefaultValue({ type: "number" }, "testProp", parentSchema), + ).toBe(0); }); test("generates default integer", () => { const parentSchema = { type: "object" as const, required: ["testProp"] }; - expect(generateDefaultValue({ type: "integer" }, "testProp", parentSchema)).toBe(0); + expect( + generateDefaultValue({ type: "integer" }, "testProp", parentSchema), + ).toBe(0); }); test("generates default boolean", () => { const parentSchema = { type: "object" as const, required: ["testProp"] }; - expect(generateDefaultValue({ type: "boolean" }, "testProp", parentSchema)).toBe( - false, - ); + expect( + generateDefaultValue({ type: "boolean" }, "testProp", parentSchema), + ).toBe(false); }); test("generates default array", () => { @@ -37,40 +43,26 @@ describe("generateDefaultValue", () => { }); test("generates default empty object", () => { - expect(generateDefaultValue({ type: "object" })).toEqual( - {}, - ); + expect(generateDefaultValue({ type: "object" })).toEqual({}); }); test("generates default null for unknown types", () => { // @ts-expect-error Testing with invalid type - expect(generateDefaultValue({ type: "unknown" })).toBe( - undefined, - ); + expect(generateDefaultValue({ type: "unknown" })).toBe(undefined); }); test("generates empty array for non-required array", () => { - expect(generateDefaultValue({ type: "array" })).toEqual( - [], - ); + expect(generateDefaultValue({ type: "array" })).toEqual([]); }); test("generates empty object for non-required object", () => { - expect(generateDefaultValue({ type: "object" })).toEqual( - {}, - ); + expect(generateDefaultValue({ type: "object" })).toEqual({}); }); test("generates undefined for non-required primitive types", () => { - expect(generateDefaultValue({ type: "string" })).toBe( - undefined, - ); - expect(generateDefaultValue({ type: "number" })).toBe( - undefined, - ); - expect(generateDefaultValue({ type: "boolean" })).toBe( - undefined, - ); + expect(generateDefaultValue({ type: "string" })).toBe(undefined); + expect(generateDefaultValue({ type: "number" })).toBe(undefined); + expect(generateDefaultValue({ type: "boolean" })).toBe(undefined); }); test("generates object with properties", () => { From 3475670f1d2e2c08ddb4df070a087d75fb7debbb Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 20:53:17 -0700 Subject: [PATCH 08/91] Incorporate nested logic again --- client/src/components/DynamicJsonForm.tsx | 105 ++++++- .../__tests__/DynamicJsonForm.array.test.tsx | 256 ++++++++++++++++++ 2 files changed, 356 insertions(+), 5 deletions(-) create mode 100644 client/src/components/__tests__/DynamicJsonForm.array.test.tsx diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index 0a73a989..f799afbb 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -16,10 +16,39 @@ interface DynamicJsonFormProps { const isSimpleObject = (schema: JsonSchemaType): boolean => { const supportedTypes = ["string", "number", "integer", "boolean", "null"]; if (supportedTypes.includes(schema.type)) return true; - if (schema.type !== "object") return false; - return Object.values(schema.properties ?? {}).every((prop) => - supportedTypes.includes(prop.type), - ); + if (schema.type === "object") { + return Object.values(schema.properties ?? {}).every((prop) => + supportedTypes.includes(prop.type), + ); + } + if (schema.type === "array") { + return !!schema.items && isSimpleObject(schema.items); + } + return false; +}; + +const getArrayItemDefault = (schema: JsonSchemaType): JsonValue => { + if ("default" in schema && schema.default !== undefined) { + return schema.default; + } + + switch (schema.type) { + case "string": + return ""; + case "number": + case "integer": + return 0; + case "boolean": + return false; + case "array": + return []; + case "object": + return {}; + case "null": + return null; + default: + return null; + } }; const DynamicJsonForm = ({ @@ -257,7 +286,72 @@ const DynamicJsonForm = ({ ))}
); - case "array": + case "array": { + const arrayValue = Array.isArray(currentValue) ? currentValue : []; + if (!propSchema.items) return null; + + // If the array items are simple, render as form fields, otherwise use JSON editor + if (isSimpleObject(propSchema.items)) { + return ( +
+ {propSchema.description && ( +

{propSchema.description}

+ )} + + {propSchema.items?.description && ( +

+ Items: {propSchema.items.description} +

+ )} + +
+ {arrayValue.map((item, index) => ( +
+ {renderFormFields( + propSchema.items as JsonSchemaType, + item, + [...path, index.toString()], + depth + 1, + )} + +
+ ))} + +
+
+ ); + } + + // For complex arrays, fall back to JSON editor return ( ); + } default: return null; } diff --git a/client/src/components/__tests__/DynamicJsonForm.array.test.tsx b/client/src/components/__tests__/DynamicJsonForm.array.test.tsx new file mode 100644 index 00000000..00a324bf --- /dev/null +++ b/client/src/components/__tests__/DynamicJsonForm.array.test.tsx @@ -0,0 +1,256 @@ +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, jest } from "@jest/globals"; +import DynamicJsonForm from "../DynamicJsonForm"; +import type { JsonSchemaType } from "@/utils/jsonUtils"; + +describe("DynamicJsonForm Array Fields", () => { + const renderSimpleArrayForm = (props = {}) => { + const defaultProps = { + schema: { + type: "array" as const, + description: "Test array field", + items: { + type: "string" as const, + description: "Array item", + }, + } satisfies JsonSchemaType, + value: [], + onChange: jest.fn(), + }; + return render(); + }; + + const renderComplexArrayForm = (props = {}) => { + const defaultProps = { + schema: { + type: "array" as const, + description: "Test complex array field", + items: { + type: "object" as const, + properties: { + nested: { type: "object" as const }, + }, + }, + } satisfies JsonSchemaType, + value: [], + onChange: jest.fn(), + }; + return render(); + }; + + describe("Simple Array Rendering", () => { + it("should render form fields for simple array items", () => { + renderSimpleArrayForm({ value: ["item1", "item2"] }); + + // Should show array description + expect(screen.getByText("Test array field")).toBeDefined(); + expect(screen.getByText("Items: Array item")).toBeDefined(); + + // Should show input fields for each item + const inputs = screen.getAllByRole("textbox"); + expect(inputs).toHaveLength(2); + expect(inputs[0]).toHaveProperty("value", "item1"); + expect(inputs[1]).toHaveProperty("value", "item2"); + + // Should show remove buttons + const removeButtons = screen.getAllByText("Remove"); + expect(removeButtons).toHaveLength(2); + + // Should show add button + expect(screen.getByText("Add Item")).toBeDefined(); + }); + + it("should add new items when Add Item button is clicked", () => { + const onChange = jest.fn(); + renderSimpleArrayForm({ value: ["item1"], onChange }); + + const addButton = screen.getByText("Add Item"); + fireEvent.click(addButton); + + expect(onChange).toHaveBeenCalledWith(["item1", ""]); + }); + + it("should remove items when Remove button is clicked", () => { + const onChange = jest.fn(); + renderSimpleArrayForm({ value: ["item1", "item2"], onChange }); + + const removeButtons = screen.getAllByText("Remove"); + fireEvent.click(removeButtons[0]); + + expect(onChange).toHaveBeenCalledWith(["item2"]); + }); + + it("should update item values when input changes", () => { + const onChange = jest.fn(); + renderSimpleArrayForm({ value: ["item1"], onChange }); + + const input = screen.getByRole("textbox"); + fireEvent.change(input, { target: { value: "updated item" } }); + + expect(onChange).toHaveBeenCalledWith(["updated item"]); + }); + + it("should handle empty arrays", () => { + renderSimpleArrayForm({ value: [] }); + + // Should show description and add button but no items + expect(screen.getByText("Test array field")).toBeDefined(); + expect(screen.getByText("Add Item")).toBeDefined(); + expect(screen.queryByText("Remove")).toBeNull(); + }); + }); + + describe("Complex Array Fallback", () => { + it("should render JSON editor for complex arrays", () => { + renderComplexArrayForm(); + + // Should render as JSON editor (textarea) + const textarea = screen.getByRole("textbox"); + expect(textarea).toHaveProperty("type", "textarea"); + + // Should not show form-specific array controls + expect(screen.queryByText("Add Item")).toBeNull(); + expect(screen.queryByText("Remove")).toBeNull(); + }); + }); + + describe("Array Type Detection", () => { + it("should detect string arrays as simple", () => { + const schema = { + type: "array" as const, + items: { type: "string" as const }, + }; + renderSimpleArrayForm({ schema, value: ["test"] }); + + // Should render form fields, not JSON editor + expect(screen.getByRole("textbox")).not.toHaveProperty( + "type", + "textarea", + ); + }); + + it("should detect number arrays as simple", () => { + const schema = { + type: "array" as const, + items: { type: "number" as const }, + }; + renderSimpleArrayForm({ schema, value: [1, 2] }); + + // Should render form fields (number inputs) + const inputs = screen.getAllByRole("spinbutton"); + expect(inputs).toHaveLength(2); + }); + + it("should detect boolean arrays as simple", () => { + const schema = { + type: "array" as const, + items: { type: "boolean" as const }, + }; + renderSimpleArrayForm({ schema, value: [true, false] }); + + // Should render form fields (checkboxes) + const checkboxes = screen.getAllByRole("checkbox"); + expect(checkboxes).toHaveLength(2); + }); + + it("should detect simple object arrays as simple", () => { + const schema = { + type: "array" as const, + items: { + type: "object" as const, + properties: { + name: { type: "string" as const }, + age: { type: "number" as const }, + }, + }, + }; + renderSimpleArrayForm({ schema, value: [{ name: "John", age: 30 }] }); + + // Should render form fields for simple objects + expect(screen.getByText("Add Item")).toBeDefined(); + expect(screen.getByText("Remove")).toBeDefined(); + }); + }); + + describe("Array with Different Item Types", () => { + it("should handle integer array items", () => { + const schema = { + type: "array" as const, + items: { type: "integer" as const }, + }; + const onChange = jest.fn(); + renderSimpleArrayForm({ schema, value: [1, 2], onChange }); + + const inputs = screen.getAllByRole("spinbutton"); + expect(inputs).toHaveLength(2); + expect(inputs[0]).toHaveProperty("value", "1"); + expect(inputs[1]).toHaveProperty("value", "2"); + + // Test adding new integer item + const addButton = screen.getByText("Add Item"); + fireEvent.click(addButton); + expect(onChange).toHaveBeenCalledWith([1, 2, 0]); + }); + + it("should handle boolean array items", () => { + const schema = { + type: "array" as const, + items: { type: "boolean" as const }, + }; + const onChange = jest.fn(); + renderSimpleArrayForm({ schema, value: [true, false], onChange }); + + const checkboxes = screen.getAllByRole("checkbox"); + expect(checkboxes).toHaveLength(2); + expect(checkboxes[0]).toHaveProperty("checked", true); + expect(checkboxes[1]).toHaveProperty("checked", false); + + // Test adding new boolean item + const addButton = screen.getByText("Add Item"); + fireEvent.click(addButton); + expect(onChange).toHaveBeenCalledWith([true, false, false]); + }); + }); + + describe("Array Item Descriptions", () => { + it("should show item description when available", () => { + const schema = { + type: "array" as const, + description: "List of names", + items: { + type: "string" as const, + description: "Person name", + }, + }; + renderSimpleArrayForm({ schema }); + + expect(screen.getByText("List of names")).toBeDefined(); + expect(screen.getByText("Items: Person name")).toBeDefined(); + }); + + it("should use item description in add button title", () => { + const schema = { + type: "array" as const, + items: { + type: "string" as const, + description: "Email address", + }, + }; + renderSimpleArrayForm({ schema }); + + const addButton = screen.getByText("Add Item"); + expect(addButton).toHaveProperty("title", "Add new Email address"); + }); + + it("should use default title when no item description", () => { + const schema = { + type: "array" as const, + items: { type: "string" as const }, + }; + renderSimpleArrayForm({ schema }); + + const addButton = screen.getByText("Add Item"); + expect(addButton).toHaveProperty("title", "Add new item"); + }); + }); +}); From 0a1de24fdff629adddc3df4f1fbab0e47b0b6ac1 Mon Sep 17 00:00:00 2001 From: olaservo Date: Sun, 1 Jun 2025 21:05:33 -0700 Subject: [PATCH 09/91] Fix formatting --- client/src/components/DynamicJsonForm.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index f799afbb..081a7d3b 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -31,7 +31,7 @@ const getArrayItemDefault = (schema: JsonSchemaType): JsonValue => { if ("default" in schema && schema.default !== undefined) { return schema.default; } - + switch (schema.type) { case "string": return ""; @@ -289,13 +289,15 @@ const DynamicJsonForm = ({ case "array": { const arrayValue = Array.isArray(currentValue) ? currentValue : []; if (!propSchema.items) return null; - + // If the array items are simple, render as form fields, otherwise use JSON editor if (isSimpleObject(propSchema.items)) { return (
{propSchema.description && ( -

{propSchema.description}

+

+ {propSchema.description} +

)} {propSchema.items?.description && ( @@ -333,10 +335,7 @@ const DynamicJsonForm = ({ const defaultValue = getArrayItemDefault( propSchema.items as JsonSchemaType, ); - handleFieldChange(path, [ - ...arrayValue, - defaultValue, - ]); + handleFieldChange(path, [...arrayValue, defaultValue]); }} title={ propSchema.items?.description @@ -350,7 +349,7 @@ const DynamicJsonForm = ({
); } - + // For complex arrays, fall back to JSON editor return ( Date: Tue, 27 May 2025 18:33:05 -0700 Subject: [PATCH 10/91] Add a Playwright e2e test --- client/e2e/transport-type-dropdown.spec.ts | 22 ++++++++ package-lock.json | 64 ++++++++++++++++++++++ package.json | 1 + 3 files changed, 87 insertions(+) create mode 100644 client/e2e/transport-type-dropdown.spec.ts diff --git a/client/e2e/transport-type-dropdown.spec.ts b/client/e2e/transport-type-dropdown.spec.ts new file mode 100644 index 00000000..003420d2 --- /dev/null +++ b/client/e2e/transport-type-dropdown.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; + +// Adjust the URL if your dev server runs on a different port +const APP_URL = 'http://localhost:6274/'; + +test.describe('Transport Type Dropdown', () => { + test('should have options for STDIO, SSE, and Streamable HTTP', async ({ page }) => { + await page.goto(APP_URL); + + // Wait for the Transport Type dropdown to be visible + const selectTrigger = page.getByLabel('Transport Type'); + await expect(selectTrigger).toBeVisible(); + + // Open the dropdown + await selectTrigger.click(); + + // Check for the three options + await expect(page.getByRole('option', { name: 'STDIO' })).toBeVisible(); + await expect(page.getByRole('option', { name: 'SSE' })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Streamable HTTP' })).toBeVisible(); + }); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 846d2eaa..25a242fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "mcp-inspector": "cli/build/cli.js" }, "devDependencies": { + "@playwright/test": "^1.52.0", "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/shell-quote": "^1.7.5", @@ -2070,6 +2071,22 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -8519,6 +8536,53 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", diff --git a/package.json b/package.json index 8742cc8b..0e5cc4c2 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "zod": "^3.23.8" }, "devDependencies": { + "@playwright/test": "^1.52.0", "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/shell-quote": "^1.7.5", From 69da70acb7316a04baa811f740c3b8d08063644f Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 27 May 2025 18:35:22 -0700 Subject: [PATCH 11/91] npm run prettier-fix --- client/e2e/transport-type-dropdown.spec.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/client/e2e/transport-type-dropdown.spec.ts b/client/e2e/transport-type-dropdown.spec.ts index 003420d2..7ca55655 100644 --- a/client/e2e/transport-type-dropdown.spec.ts +++ b/client/e2e/transport-type-dropdown.spec.ts @@ -1,22 +1,26 @@ -import { test, expect } from '@playwright/test'; +import { test, expect } from "@playwright/test"; // Adjust the URL if your dev server runs on a different port -const APP_URL = 'http://localhost:6274/'; +const APP_URL = "http://localhost:6274/"; -test.describe('Transport Type Dropdown', () => { - test('should have options for STDIO, SSE, and Streamable HTTP', async ({ page }) => { +test.describe("Transport Type Dropdown", () => { + test("should have options for STDIO, SSE, and Streamable HTTP", async ({ + page, + }) => { await page.goto(APP_URL); // Wait for the Transport Type dropdown to be visible - const selectTrigger = page.getByLabel('Transport Type'); + const selectTrigger = page.getByLabel("Transport Type"); await expect(selectTrigger).toBeVisible(); // Open the dropdown await selectTrigger.click(); // Check for the three options - await expect(page.getByRole('option', { name: 'STDIO' })).toBeVisible(); - await expect(page.getByRole('option', { name: 'SSE' })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Streamable HTTP' })).toBeVisible(); + await expect(page.getByRole("option", { name: "STDIO" })).toBeVisible(); + await expect(page.getByRole("option", { name: "SSE" })).toBeVisible(); + await expect( + page.getByRole("option", { name: "Streamable HTTP" }), + ).toBeVisible(); }); -}); \ No newline at end of file +}); From 8a13526c8b24c12f169152675b9754c7d8d9f6cd Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 27 May 2025 18:38:20 -0700 Subject: [PATCH 12/91] Exclude e2e from Jest --- client/jest.config.cjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/jest.config.cjs b/client/jest.config.cjs index b4d81cfc..8652eda5 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -21,6 +21,7 @@ module.exports = { "/node_modules/", "/dist/", "/bin/", + "/e2e/", "\\.config\\.(js|ts|cjs|mjs)$", ], // Exclude the same patterns from coverage reports @@ -28,6 +29,7 @@ module.exports = { "/node_modules/", "/dist/", "/bin/", + "/e2e/", "\\.config\\.(js|ts|cjs|mjs)$", ], }; From 8babc44f0b04a6037deee2de205710eda7c3b023 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 27 May 2025 18:43:29 -0700 Subject: [PATCH 13/91] Make `npm run test:e2e` work --- client/package.json | 3 ++- package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/package.json b/client/package.json index daf549fc..9eb49574 100644 --- a/client/package.json +++ b/client/package.json @@ -20,7 +20,8 @@ "lint": "eslint .", "preview": "vite preview --port 6274", "test": "jest --config jest.config.cjs", - "test:watch": "jest --config jest.config.cjs --watch" + "test:watch": "jest --config jest.config.cjs --watch", + "test:e2e": "playwright test e2e" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", diff --git a/package.json b/package.json index 0e5cc4c2..1e7a931e 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "prettier-check": "prettier --check .", "lint": "prettier --check . && cd client && npm run lint", "prepare": "npm run build", - "publish-all": "npm publish --workspaces --access public && npm publish --access public" + "publish-all": "npm publish --workspaces --access public && npm publish --access public", + "test:e2e": "npm run test:e2e --workspace=client" }, "dependencies": { "@modelcontextprotocol/inspector-cli": "^0.14.0", From 3a28efe5861f9416d41abb472e75059bf4f3c605 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 27 May 2025 19:21:06 -0700 Subject: [PATCH 14/91] Mention `npm run test:e2e` in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72502f96..1eeeb864 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ Thanks for your interest in contributing! This guide explains how to get involve 1. Create a new branch for your changes 2. Make your changes following existing code style and conventions. You can run `npm run prettier-check` and `npm run prettier-fix` as applicable. -3. Test changes locally by running `npm test` +3. Test changes locally by running `npm test` and `npm run test:e2e` 4. Update documentation as needed 5. Use clear commit messages explaining your changes 6. Verify all changes work as expected From 89e1efc443614aed0075958168c7db27db4d6f2a Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 3 Jun 2025 23:29:33 -0700 Subject: [PATCH 15/91] Add more Playwright tests --- client/e2e/transport-type-dropdown.spec.ts | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/client/e2e/transport-type-dropdown.spec.ts b/client/e2e/transport-type-dropdown.spec.ts index 7ca55655..e4ac8fbb 100644 --- a/client/e2e/transport-type-dropdown.spec.ts +++ b/client/e2e/transport-type-dropdown.spec.ts @@ -23,4 +23,91 @@ test.describe("Transport Type Dropdown", () => { page.getByRole("option", { name: "Streamable HTTP" }), ).toBeVisible(); }); + + test("should show Command and Arguments fields and hide URL field when Transport Type is STDIO", async ({ + page, + }) => { + await page.goto(APP_URL); + + // Wait for the Transport Type dropdown to be visible + const selectTrigger = page.getByLabel("Transport Type"); + await expect(selectTrigger).toBeVisible(); + + // Open the dropdown and select STDIO + await selectTrigger.click(); + await page.getByRole("option", { name: "STDIO" }).click(); + + // Wait for the form to update + await page.waitForTimeout(100); + + // Check that Command and Arguments fields are visible + await expect(page.locator("#command-input")).toBeVisible(); + await expect(page.locator("#arguments-input")).toBeVisible(); + + // Check that URL field is not visible + await expect(page.locator("#sse-url-input")).not.toBeVisible(); + + // Also verify the labels are present + await expect(page.getByText("Command")).toBeVisible(); + await expect(page.getByText("Arguments")).toBeVisible(); + await expect(page.getByText("URL")).not.toBeVisible(); + }); + + test("should show URL field and hide Command and Arguments fields when Transport Type is SSE", async ({ + page, + }) => { + await page.goto(APP_URL); + + // Wait for the Transport Type dropdown to be visible + const selectTrigger = page.getByLabel("Transport Type"); + await expect(selectTrigger).toBeVisible(); + + // Open the dropdown and select SSE + await selectTrigger.click(); + await page.getByRole("option", { name: "SSE" }).click(); + + // Wait for the form to update + await page.waitForTimeout(100); + + // Check that URL field is visible + await expect(page.locator("#sse-url-input")).toBeVisible(); + + // Check that Command and Arguments fields are not visible + await expect(page.locator("#command-input")).not.toBeVisible(); + await expect(page.locator("#arguments-input")).not.toBeVisible(); + + // Also verify the labels are present/absent + await expect(page.getByText("URL")).toBeVisible(); + await expect(page.getByText("Command")).not.toBeVisible(); + await expect(page.getByText("Arguments")).not.toBeVisible(); + }); + + test("should show URL field and hide Command and Arguments fields when Transport Type is Streamable HTTP", async ({ + page, + }) => { + await page.goto(APP_URL); + + // Wait for the Transport Type dropdown to be visible + const selectTrigger = page.getByLabel("Transport Type"); + await expect(selectTrigger).toBeVisible(); + + // Open the dropdown and select Streamable HTTP + await selectTrigger.click(); + await page.getByRole("option", { name: "Streamable HTTP" }).click(); + + // Wait for the form to update + await page.waitForTimeout(100); + + // Check that URL field is visible + await expect(page.locator("#sse-url-input")).toBeVisible(); + + // Check that Command and Arguments fields are not visible + await expect(page.locator("#command-input")).not.toBeVisible(); + await expect(page.locator("#arguments-input")).not.toBeVisible(); + + // Also verify the labels are present/absent + await expect(page.getByText("URL")).toBeVisible(); + await expect(page.getByText("Command")).not.toBeVisible(); + await expect(page.getByText("Arguments")).not.toBeVisible(); + }); }); From c803d9327e1397ede53d1dc88031625655a78244 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 3 Jun 2025 23:51:14 -0700 Subject: [PATCH 16/91] Move test:e2e up with other two test scripts --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1e7a931e..9ef35437 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,12 @@ "start-client": "cd client && npm run preview", "test": "npm run prettier-check && cd client && npm test", "test-cli": "cd cli && npm run test", + "test:e2e": "npm run test:e2e --workspace=client", "prettier-fix": "prettier --write .", "prettier-check": "prettier --check .", "lint": "prettier --check . && cd client && npm run lint", "prepare": "npm run build", - "publish-all": "npm publish --workspaces --access public && npm publish --access public", - "test:e2e": "npm run test:e2e --workspace=client" + "publish-all": "npm publish --workspaces --access public && npm publish --access public" }, "dependencies": { "@modelcontextprotocol/inspector-cli": "^0.14.0", From 4f6a4cebde023d6d262fab05443cdfe0b4a99a86 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 3 Jun 2025 23:54:25 -0700 Subject: [PATCH 17/91] Add .github/workflows/e2e_tests.yml --- .github/workflows/e2e_tests.yml | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/e2e_tests.yml diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml new file mode 100644 index 00000000..538d8da2 --- /dev/null +++ b/.github/workflows/e2e_tests.yml @@ -0,0 +1,45 @@ +name: Playwright Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + timeout-minutes: 5 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 18 + + # Cache Playwright browsers + - name: Cache Playwright browsers + id: cache-playwright + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright # The default Playwright cache path + key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} # Cache key based on OS and package-lock.json + restore-keys: | + ${{ runner.os }}-playwright- + + - name: Install dependencies + run: npm ci + + - name: Install Playwright and browsers unless cached + run: npx playwright install --with-deps + if: steps.cache-playwright.outputs.cache-hit != 'true' + + - name: Start Server + run: npm run start + + - name: Wait for server to start + run: npx wait-on http://localhost:6274 + + - name: Run Playwright tests + run: npm run test:e2e From 66ad85aadc27694432b94020a26f468f160a8517 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:19:56 -0700 Subject: [PATCH 18/91] npm run prettier-fix --- .github/workflows/e2e_tests.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 538d8da2..599d90df 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -2,26 +2,26 @@ name: Playwright Tests on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: test: timeout-minutes: 5 - runs-on: ubuntu-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 18 # Cache Playwright browsers - name: Cache Playwright browsers id: cache-playwright - uses: actions/cache@v4 + uses: actions/cache@v4 with: path: ~/.cache/ms-playwright # The default Playwright cache path key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} # Cache key based on OS and package-lock.json @@ -29,14 +29,14 @@ jobs: ${{ runner.os }}-playwright- - name: Install dependencies - run: npm ci + run: npm ci - name: Install Playwright and browsers unless cached run: npx playwright install --with-deps - if: steps.cache-playwright.outputs.cache-hit != 'true' + if: steps.cache-playwright.outputs.cache-hit != 'true' - name: Start Server - run: npm run start + run: npm run start - name: Wait for server to start run: npx wait-on http://localhost:6274 From 1df83d73f9604858ac4559c59b8eea6b2ee6fca4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:26:05 -0700 Subject: [PATCH 19/91] Do npm run start in background so that the CI job can proceed --- .github/workflows/e2e_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 599d90df..14553600 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -36,7 +36,7 @@ jobs: if: steps.cache-playwright.outputs.cache-hit != 'true' - name: Start Server - run: npm run start + run: npm run start & - name: Wait for server to start run: npx wait-on http://localhost:6274 From 826bc35cf2e5c6be740b8d32efc95b46082d9d9e Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:31:07 -0700 Subject: [PATCH 20/91] Upload Playwright Report and Screenshots --- .github/workflows/e2e_tests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 14553600..652863e4 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -43,3 +43,13 @@ jobs: - name: Run Playwright tests run: npm run test:e2e + + - name: Upload Playwright Report and Screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: | + playwright-report/ + test-results/ + retention-days: 30 From a421f329e98bff46a4d3e360ddd7dcf926065d96 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:43:04 -0700 Subject: [PATCH 21/91] git add playwright.config.ts --- client/playwright.config.ts | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 client/playwright.config.ts diff --git a/client/playwright.config.ts b/client/playwright.config.ts new file mode 100644 index 00000000..5e848d26 --- /dev/null +++ b/client/playwright.config.ts @@ -0,0 +1,82 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * @see https://playwright.dev/docs/test-configuration + */ +export default defineConfig({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: [ + ['html', { outputFolder: 'playwright-report' }], + ['line'] + ], + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://localhost:6274', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + + /* Take screenshots on failure */ + screenshot: 'on', + // screenshot: 'only-on-failure', + + /* Record video on failure */ + video: 'retain-on-failure', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + // Skip WebKit on macOS due to compatibility issues + ...(process.platform !== 'darwin' ? [{ + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }] : []), + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:6274', + // reuseExistingServer: !process.env.CI, + // }, +}); \ No newline at end of file From f06a6e1fb7fcbfd08c5397751b130fe808cd8b4d Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:44:27 -0700 Subject: [PATCH 22/91] npm run prettier-fix --- client/playwright.config.ts | 39 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 5e848d26..551f2d38 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -1,10 +1,10 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from "@playwright/test"; /** * @see https://playwright.dev/docs/test-configuration */ export default defineConfig({ - testDir: './e2e', + testDir: "./e2e", /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ @@ -14,43 +14,44 @@ export default defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [ - ['html', { outputFolder: 'playwright-report' }], - ['line'] - ], + reporter: [["html", { outputFolder: "playwright-report" }], ["line"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: 'http://localhost:6274', + baseURL: "http://localhost:6274", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: "on-first-retry", /* Take screenshots on failure */ - screenshot: 'on', + screenshot: "on", // screenshot: 'only-on-failure', /* Record video on failure */ - video: 'retain-on-failure', + video: "retain-on-failure", }, /* Configure projects for major browsers */ projects: [ { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + name: "chromium", + use: { ...devices["Desktop Chrome"] }, }, { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, + name: "firefox", + use: { ...devices["Desktop Firefox"] }, }, // Skip WebKit on macOS due to compatibility issues - ...(process.platform !== 'darwin' ? [{ - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }] : []), + ...(process.platform !== "darwin" + ? [ + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + ] + : []), /* Test against mobile viewports. */ // { @@ -79,4 +80,4 @@ export default defineConfig({ // url: 'http://127.0.0.1:6274', // reuseExistingServer: !process.env.CI, // }, -}); \ No newline at end of file +}); From a2a58c2bc21baa55d9eac6d1e48d0662d82181de Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 18:57:02 -0700 Subject: [PATCH 23/91] Install Playwright dependencies --- .github/workflows/e2e_tests.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 652863e4..b80ffd81 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -12,6 +12,11 @@ jobs: runs-on: ubuntu-latest steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libwoff1 + - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -31,6 +36,9 @@ jobs: - name: Install dependencies run: npm ci + - name: Install Playwright dependencies + run: npx playwright install-deps + - name: Install Playwright and browsers unless cached run: npx playwright install --with-deps if: steps.cache-playwright.outputs.cache-hit != 'true' From 705d7b46c27016f16befa44ae5311b5f98f43a43 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Jun 2025 19:05:07 -0700 Subject: [PATCH 24/91] e2e_tests.yml: playwright-report and test-result in client dir --- .github/workflows/e2e_tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index b80ffd81..d61227ba 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -58,6 +58,6 @@ jobs: with: name: playwright-report path: | - playwright-report/ - test-results/ + client/playwright-report/ + client/test-results/ retention-days: 30 From cdb9180629542dc87fe2b13e0e274277493b3768 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sat, 7 Jun 2025 08:11:23 -0700 Subject: [PATCH 25/91] Generate report with https://github.com/daun/playwright-report-summary --- .github/workflows/e2e_tests.yml | 16 ++++++++++++++++ client/playwright.config.ts | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index d61227ba..df323c07 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -60,4 +60,20 @@ jobs: path: | client/playwright-report/ client/test-results/ + client/results.json retention-days: 30 + + - name: Publish Playwright Test Summary + uses: daun/playwright-report-summary@v3 + if: always() + with: + report-file: client/results.json + comment-title: "šŸŽ­ Playwright E2E Test Results" + job-summary: true + icon-style: "emojis" + custom-info: | + **Test Environment:** Ubuntu Latest, Node.js 18 + **Browsers:** Chromium, Firefox + + šŸ“Š [View Detailed HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) (download artifacts) + test-command: "npm run test:e2e" diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 551f2d38..935e4b3d 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -14,7 +14,11 @@ export default defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [["html", { outputFolder: "playwright-report" }], ["line"]], + reporter: [ + ["html", { outputFolder: "playwright-report" }], + ["json", { outputFile: "results.json" }], + ["line"], + ], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ From 2c0af88f504e09461b7bf5c307d84e9bd70485ae Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sat, 7 Jun 2025 08:35:13 -0700 Subject: [PATCH 26/91] Take screenshots on failure --- client/playwright.config.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 935e4b3d..fad4176b 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -28,8 +28,7 @@ export default defineConfig({ trace: "on-first-retry", /* Take screenshots on failure */ - screenshot: "on", - // screenshot: 'only-on-failure', + screenshot: "only-on-failure", /* Record video on failure */ video: "retain-on-failure", From 66e247b274ba888997beb7fbeb7bc7b4fab14dd4 Mon Sep 17 00:00:00 2001 From: Sebastian Ko Date: Tue, 10 Jun 2025 12:17:12 -0400 Subject: [PATCH 27/91] Remove additional slash in the end of the proxy base url --- client/src/lib/hooks/useConnection.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index d42b8d38..75e2ffd5 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -241,7 +241,9 @@ export function useConnection({ const checkProxyHealth = async () => { try { - const proxyHealthUrl = new URL(`${getMCPProxyAddress(config)}/health`); + const proxyBaseUrl = getMCPProxyAddress(config).replace(/\/+$/, ''); + const proxyHealthUrl = new URL(`${proxyBaseUrl}/health`); + const proxyHealthResponse = await fetch(proxyHealthUrl); const proxyHealth = await proxyHealthResponse.json(); if (proxyHealth?.status !== "ok") { From da003c7553aec04db1b7188016cb881689edfe9b Mon Sep 17 00:00:00 2001 From: Sebastian Ko Date: Tue, 10 Jun 2025 12:32:15 -0400 Subject: [PATCH 28/91] Change '' to "" --- client/src/lib/hooks/useConnection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index 75e2ffd5..4c18f90b 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -241,7 +241,7 @@ export function useConnection({ const checkProxyHealth = async () => { try { - const proxyBaseUrl = getMCPProxyAddress(config).replace(/\/+$/, ''); + const proxyBaseUrl = getMCPProxyAddress(config).replace(/\/+$/, ""); const proxyHealthUrl = new URL(`${proxyBaseUrl}/health`); const proxyHealthResponse = await fetch(proxyHealthUrl); From 6c7c4176454b7ebeacf47026bb12a2daa7bfce86 Mon Sep 17 00:00:00 2001 From: Sebastian Ko Date: Tue, 10 Jun 2025 12:32:52 -0400 Subject: [PATCH 29/91] add comment --- client/src/lib/hooks/useConnection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index 4c18f90b..698c2ea2 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -241,6 +241,7 @@ export function useConnection({ const checkProxyHealth = async () => { try { + // Remove additional slashes const proxyBaseUrl = getMCPProxyAddress(config).replace(/\/+$/, ""); const proxyHealthUrl = new URL(`${proxyBaseUrl}/health`); From 51eb7cf849dce561957347c07b1c82c22c1d7662 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Tue, 10 Jun 2025 21:21:43 -0700 Subject: [PATCH 30/91] Update client/src/utils/schemaUtils.ts Co-authored-by: Cliff Hall --- client/src/utils/schemaUtils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index c47022e0..a0cf1a15 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -95,8 +95,7 @@ export function generateDefaultValue( } // Check if this property is required in the parent schema - const isRequired = - parentSchema?.required?.includes(propertyName || "") ?? false; + const isRequired = isPropertyRequired(propertyName, parentSchema); switch (schema.type) { case "string": From cf2778ad1914cd38b66898e162ebf358ea0f20bf Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Tue, 10 Jun 2025 21:21:51 -0700 Subject: [PATCH 31/91] Update client/src/utils/schemaUtils.ts Co-authored-by: Cliff Hall --- client/src/utils/schemaUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index a0cf1a15..65e334d6 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -113,13 +113,13 @@ export function generateDefaultValue( const obj: JsonObject = {}; // Only include properties that are required according to the schema's required array Object.entries(schema.properties).forEach(([key, prop]) => { - const isPropertyRequired = schema.required?.includes(key) ?? false; - if (isPropertyRequired) { + if (isPropertyRequired(key, schema)) { const value = generateDefaultValue(prop, key, schema); if (value !== undefined) { obj[key] = value; } } + }); return obj; } From 123a4626811493aa48a9c6ffe58a5aa53087648a Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 10 Jun 2025 21:23:04 -0700 Subject: [PATCH 32/91] Fix formatting --- client/src/utils/schemaUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index 65e334d6..b903058b 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -119,7 +119,6 @@ export function generateDefaultValue( obj[key] = value; } } - }); return obj; } From a2061a6f761800216f20c3ecf7a0c8cfecfbfb42 Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 10 Jun 2025 21:27:54 -0700 Subject: [PATCH 33/91] Add check to fix build failure --- client/src/utils/schemaUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index b903058b..38bc8aae 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -95,7 +95,7 @@ export function generateDefaultValue( } // Check if this property is required in the parent schema - const isRequired = isPropertyRequired(propertyName, parentSchema); + const isRequired = propertyName && parentSchema ? isPropertyRequired(propertyName, parentSchema) : false; switch (schema.type) { case "string": From 2fb5d4b684ed247a892ef18b6b7f00a9ca83ddb8 Mon Sep 17 00:00:00 2001 From: olaservo Date: Tue, 10 Jun 2025 21:29:08 -0700 Subject: [PATCH 34/91] Fix formatting --- client/src/utils/schemaUtils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/utils/schemaUtils.ts b/client/src/utils/schemaUtils.ts index 38bc8aae..9fc7a724 100644 --- a/client/src/utils/schemaUtils.ts +++ b/client/src/utils/schemaUtils.ts @@ -95,7 +95,10 @@ export function generateDefaultValue( } // Check if this property is required in the parent schema - const isRequired = propertyName && parentSchema ? isPropertyRequired(propertyName, parentSchema) : false; + const isRequired = + propertyName && parentSchema + ? isPropertyRequired(propertyName, parentSchema) + : false; switch (schema.type) { case "string": From b3e1b5cb6acd398619a4ce9e607a19c5c8402f67 Mon Sep 17 00:00:00 2001 From: olaservo Date: Wed, 11 Jun 2025 06:45:23 -0700 Subject: [PATCH 35/91] Update defineProperty to make jest-dom happy --- client/src/components/__tests__/AuthDebugger.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/__tests__/AuthDebugger.test.tsx b/client/src/components/__tests__/AuthDebugger.test.tsx index 2130e68b..70862768 100644 --- a/client/src/components/__tests__/AuthDebugger.test.tsx +++ b/client/src/components/__tests__/AuthDebugger.test.tsx @@ -88,6 +88,8 @@ Object.defineProperty(window, "location", { value: { origin: "http://localhost:3000", }, + configurable: true, + writable: true, }); describe("AuthDebugger", () => { From dac224bad7e6a5c1810600277e74501f1f9a749a Mon Sep 17 00:00:00 2001 From: olaservo Date: Thu, 12 Jun 2025 03:56:20 -0700 Subject: [PATCH 36/91] Remove mocking --- .../__tests__/AuthDebugger.test.tsx | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/client/src/components/__tests__/AuthDebugger.test.tsx b/client/src/components/__tests__/AuthDebugger.test.tsx index 70862768..eb7ff3ba 100644 --- a/client/src/components/__tests__/AuthDebugger.test.tsx +++ b/client/src/components/__tests__/AuthDebugger.test.tsx @@ -84,14 +84,6 @@ Object.defineProperty(window, "sessionStorage", { value: sessionStorageMock, }); -Object.defineProperty(window, "location", { - value: { - origin: "http://localhost:3000", - }, - configurable: true, - writable: true, -}); - describe("AuthDebugger", () => { const defaultAuthState = EMPTY_DEBUGGER_STATE; @@ -106,7 +98,7 @@ describe("AuthDebugger", () => { jest.clearAllMocks(); sessionStorageMock.getItem.mockReturnValue(null); - // Supress + // Suppress console errors in tests to avoid JSDOM navigation noise jest.spyOn(console, "error").mockImplementation(() => {}); mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata); @@ -449,18 +441,6 @@ describe("AuthDebugger", () => { it("should store auth state to sessionStorage before redirect in Quick OAuth Flow", async () => { const updateAuthState = jest.fn(); - // Mock window.location.href setter - const originalLocation = window.location; - const locationMock = { - ...originalLocation, - href: "", - origin: "http://localhost:3000", - }; - Object.defineProperty(window, "location", { - writable: true, - value: locationMock, - }); - // Setup mocks for OAuth flow mockStartAuthorization.mockResolvedValue({ authorizationUrl: new URL( From 03e21bd3e469ebadbeb5c3339894017565551156 Mon Sep 17 00:00:00 2001 From: Sebastian Ko Date: Sun, 15 Jun 2025 21:25:01 -0400 Subject: [PATCH 37/91] Move remove slashes logic to getMCPProxyAddress --- client/src/utils/configUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/utils/configUtils.ts b/client/src/utils/configUtils.ts index ae404d65..aad03ce8 100644 --- a/client/src/utils/configUtils.ts +++ b/client/src/utils/configUtils.ts @@ -5,8 +5,9 @@ import { } from "@/lib/constants"; export const getMCPProxyAddress = (config: InspectorConfig): string => { - const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; + var proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; if (proxyFullAddress) { + proxyFullAddress = proxyFullAddress.replace(/\/+$/, ""); return proxyFullAddress; } return `${window.location.protocol}//${window.location.hostname}:${DEFAULT_MCP_PROXY_LISTEN_PORT}`; From 6e5ccf679ac6cd4e8c1ca4f728ee4e7b0dfb24be Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 16 Jun 2025 20:55:45 -0700 Subject: [PATCH 38/91] Remove commented out stuff in playwright.config.ts --- client/playwright.config.ts | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index fad4176b..42612a26 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -55,32 +55,5 @@ export default defineConfig({ }, ] : []), - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, ], - - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:6274', - // reuseExistingServer: !process.env.CI, - // }, }); From 8b1faf110cbf5956df05dd0bd18589c3ba1a972f Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 17 Jun 2025 20:18:32 -0700 Subject: [PATCH 39/91] playwright.config.ts: Start dev server automatically --- client/playwright.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 42612a26..e4d6a30d 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -4,6 +4,14 @@ import { defineConfig, devices } from "@playwright/test"; * @see https://playwright.dev/docs/test-configuration */ export default defineConfig({ + /* Run your local dev server before starting the tests */ + webServer: { + cwd: '..', + command: 'npm run dev', + url: 'http://localhost:6274', + reuseExistingServer: !process.env.CI, + }, + testDir: "./e2e", /* Run tests in files in parallel */ fullyParallel: true, From 4ef6bdb1b8144b23d698fe13f47f4e380059ad64 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 17 Jun 2025 20:19:41 -0700 Subject: [PATCH 40/91] e2e_tests.yml: Remove start dev server since now we are doing that in `playwright.config.ts` --- .github/workflows/e2e_tests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index df323c07..b47daf2b 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -43,12 +43,6 @@ jobs: run: npx playwright install --with-deps if: steps.cache-playwright.outputs.cache-hit != 'true' - - name: Start Server - run: npm run start & - - - name: Wait for server to start - run: npx wait-on http://localhost:6274 - - name: Run Playwright tests run: npm run test:e2e From 0f1cc199268d5c8e45dcbdac898948d788c857db Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 17 Jun 2025 20:26:22 -0700 Subject: [PATCH 41/91] prettier fix playwright.config.ts --- client/playwright.config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index e4d6a30d..f4650843 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -6,9 +6,9 @@ import { defineConfig, devices } from "@playwright/test"; export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { - cwd: '..', - command: 'npm run dev', - url: 'http://localhost:6274', + cwd: "..", + command: "npm run dev", + url: "http://localhost:6274", reuseExistingServer: !process.env.CI, }, From 0b31ce745423f50a070e593bdb7ec2daf3e54d55 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 17 Jun 2025 23:44:49 -0700 Subject: [PATCH 42/91] .gitignore: Add playwright artifacts --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 60faf653..8e184de8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ client/tsconfig.app.tsbuildinfo client/tsconfig.node.tsbuildinfo cli/build test-output +client/playwright-report/ +client/results.json +client/test-results/ + From b783b50f7f5c30e1e8dad9ffc8e6a95fe4871aae Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 17 Jun 2025 23:56:18 -0700 Subject: [PATCH 43/91] Make "npm run clean" remove Playwright files --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ef35437..9108e3e3 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "build-server": "cd server && npm run build", "build-client": "cd client && npm run build", "build-cli": "cd cli && npm run build", - "clean": "rimraf ./node_modules ./client/node_modules ./cli/node_modules ./build ./client/dist ./server/build ./cli/build ./package-lock.json && npm install", + "clean": "rimraf ./node_modules ./client/node_modules ./cli/node_modules ./build ./client/dist ./server/build ./cli/build ./package-lock.json client/playwright-report client/results.json client/test-results && npm install", "dev": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev\"", "dev:windows": "concurrently \"cd client && npm run dev\" \"cd server && npm run dev:windows\"", "start": "node client/bin/start.js", From db9ca3762a9c99501d45f72c4724ad2089e2fa82 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 19 Jun 2025 00:00:32 -0700 Subject: [PATCH 44/91] No playwright-report or results.json for non-CI --- client/playwright.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index f4650843..3e4f1d2e 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -22,11 +22,11 @@ export default defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [ + reporter: process.env.CI ? [ ["html", { outputFolder: "playwright-report" }], ["json", { outputFile: "results.json" }], ["line"], - ], + ] : [["line"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ From 08e4f6b4a83c8e4ac753974269c7f8f0fda74e5c Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 19 Jun 2025 00:06:36 -0700 Subject: [PATCH 45/91] outputDir: "./e2e/test-results" --- client/playwright.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index 3e4f1d2e..fd24eb17 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -13,6 +13,7 @@ export default defineConfig({ }, testDir: "./e2e", + outputDir: "./e2e/test-results", /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ From 8b3613e11ae76d3f29ad84c6e8a4bc38a5e76c52 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 19 Jun 2025 07:02:06 -0700 Subject: [PATCH 46/91] prettier fix --- client/playwright.config.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/playwright.config.ts b/client/playwright.config.ts index fd24eb17..570dd054 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -23,11 +23,13 @@ export default defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: process.env.CI ? [ - ["html", { outputFolder: "playwright-report" }], - ["json", { outputFile: "results.json" }], - ["line"], - ] : [["line"]], + reporter: process.env.CI + ? [ + ["html", { outputFolder: "playwright-report" }], + ["json", { outputFile: "results.json" }], + ["line"], + ] + : [["line"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ From 1807542582482cb2f769ea69c5686cafd6ddb088 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 19 Jun 2025 07:22:38 -0700 Subject: [PATCH 47/91] Cleanup client/e2e/test-results/ after test:e2e --- client/e2e/global-teardown.js | 18 ++++++++++++++++++ client/package.json | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 client/e2e/global-teardown.js diff --git a/client/e2e/global-teardown.js b/client/e2e/global-teardown.js new file mode 100644 index 00000000..9308d940 --- /dev/null +++ b/client/e2e/global-teardown.js @@ -0,0 +1,18 @@ +import { rimraf } from "rimraf"; + +async function globalTeardown() { + if (!process.env.CI) { + console.log("Cleaning up test-results directory..."); + // Add a small delay to ensure all Playwright files are written + await new Promise((resolve) => setTimeout(resolve, 100)); + await rimraf("./e2e/test-results"); + console.log("Test-results directory cleaned up."); + } +} + +export default globalTeardown; + +// Call the function when this script is run directly +if (import.meta.url === `file://${process.argv[1]}`) { + globalTeardown().catch(console.error); +} diff --git a/client/package.json b/client/package.json index a34ecbc4..6d2e7d1a 100644 --- a/client/package.json +++ b/client/package.json @@ -21,7 +21,8 @@ "preview": "vite preview --port 6274", "test": "jest --config jest.config.cjs", "test:watch": "jest --config jest.config.cjs --watch", - "test:e2e": "playwright test e2e" + "test:e2e": "playwright test e2e && npm run cleanup:e2e", + "cleanup:e2e": "node e2e/global-teardown.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", From b481ed0077f662562ddfb0ffd5b81eec8e9578be Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 19 Jun 2025 09:39:52 -0700 Subject: [PATCH 48/91] Set `MCP_AUTO_OPEN_ENABLED=false` for `test:e2e` script Since merging the latest changes from `main` that put auto-open back in when running the start or dev scripts, the `test:e2e` run results in the Inspector being opened in the browser. This change suppresses that (tested locally). Thanks, @cliffhall! Co-authored-by: Cliff Hall --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f333ef9e..3461976b 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "start-client": "cd client && npm run preview", "test": "npm run prettier-check && cd client && npm test", "test-cli": "cd cli && npm run test", - "test:e2e": "npm run test:e2e --workspace=client", + "test:e2e": "MCP_AUTO_OPEN_ENABLED=false npm run test:e2e --workspace=client", "prettier-fix": "prettier --write .", "prettier-check": "prettier --check .", "lint": "prettier --check . && cd client && npm run lint", From 0e6915a061f6cbef16fe29eb8d271a5869e46afb Mon Sep 17 00:00:00 2001 From: Alex Andru Date: Fri, 20 Jun 2025 18:54:13 +0200 Subject: [PATCH 49/91] chore: bump workspace deps --- cli/package.json | 2 +- client/package.json | 2 +- server/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/package.json b/cli/package.json index f1ff1c33..382eb1b4 100644 --- a/cli/package.json +++ b/cli/package.json @@ -21,7 +21,7 @@ }, "devDependencies": {}, "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "commander": "^13.1.0", "spawn-rx": "^5.1.2" } diff --git a/client/package.json b/client/package.json index 37a0675b..449e0637 100644 --- a/client/package.json +++ b/client/package.json @@ -23,7 +23,7 @@ "test:watch": "jest --config jest.config.cjs --watch" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "@radix-ui/react-checkbox": "^1.1.4", "ajv": "^6.12.6", "@radix-ui/react-dialog": "^1.1.3", diff --git a/server/package.json b/server/package.json index 8f81a9df..9c248635 100644 --- a/server/package.json +++ b/server/package.json @@ -27,7 +27,7 @@ "typescript": "^5.6.2" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0", From d5b4a6e6a77f52b510306c9a6ba3bb256559469a Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 11:12:03 -0700 Subject: [PATCH 50/91] Update .github/workflows/e2e_tests.yml Co-authored-by: Cliff Hall --- .github/workflows/e2e_tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index b47daf2b..2d36f128 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + pull-requests: write + jobs: test: timeout-minutes: 5 From eb89e0191f7a54ac421e593c0af520e8349a20e7 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 11:39:18 -0700 Subject: [PATCH 51/91] Change retention-days from 30 to 2 --- .github/workflows/e2e_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 2d36f128..f620c318 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -58,7 +58,7 @@ jobs: client/playwright-report/ client/test-results/ client/results.json - retention-days: 30 + retention-days: 2 - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 From 1ff39f13f5339a1bf87101f80848bc7b69c089b4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 11:44:45 -0700 Subject: [PATCH 52/91] Replace pull_request with pull_request_target --- .github/workflows/e2e_tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index f620c318..c601e45b 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -3,7 +3,7 @@ name: Playwright Tests on: push: branches: [main] - pull_request: + pull_request_target: branches: [main] permissions: @@ -20,7 +20,10 @@ jobs: sudo apt-get update sudo apt-get install -y libwoff1 + # Security: Explicitly checkout the PR's code, not the target branch - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - uses: actions/setup-node@v4 with: From 4b14b96f417598bde7fbae5acfe99b3b8faff2e5 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 12:13:29 -0700 Subject: [PATCH 53/91] Both pull_request and pull_request_target --- .github/workflows/e2e_tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index c601e45b..f52e928f 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -3,6 +3,8 @@ name: Playwright Tests on: push: branches: [main] + pull_request: + branches: [main] pull_request_target: branches: [main] From 9ffe63ee08908718b0ade8bdd457cbe46567dae1 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 13:35:45 -0700 Subject: [PATCH 54/91] Revert "Both pull_request and pull_request_target" This reverts commit 4b14b96f417598bde7fbae5acfe99b3b8faff2e5. --- .github/workflows/e2e_tests.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index f52e928f..c601e45b 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -3,8 +3,6 @@ name: Playwright Tests on: push: branches: [main] - pull_request: - branches: [main] pull_request_target: branches: [main] From 3e28357e9cdb0434a4d519608f9bd49ad6cdf049 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 13:36:00 -0700 Subject: [PATCH 55/91] Revert "Replace pull_request with pull_request_target" This reverts commit 1ff39f13f5339a1bf87101f80848bc7b69c089b4. --- .github/workflows/e2e_tests.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index c601e45b..f620c318 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -3,7 +3,7 @@ name: Playwright Tests on: push: branches: [main] - pull_request_target: + pull_request: branches: [main] permissions: @@ -20,10 +20,7 @@ jobs: sudo apt-get update sudo apt-get install -y libwoff1 - # Security: Explicitly checkout the PR's code, not the target branch - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - uses: actions/setup-node@v4 with: From bda9b139718d288ad5224219599d9729bb30df7f Mon Sep 17 00:00:00 2001 From: cliffhall Date: Fri, 20 Jun 2025 16:46:25 -0400 Subject: [PATCH 56/91] Wasn't fully updated with dependency versions in #532 Update package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e557269a..09db8c0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "version": "0.14.3", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "commander": "^13.1.0", "spawn-rx": "^5.1.2" }, @@ -66,7 +66,7 @@ "version": "0.14.3", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", @@ -10924,7 +10924,7 @@ "version": "0.14.3", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.1", + "@modelcontextprotocol/sdk": "^1.13.0", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0", From 465ee9aaf4480e9703039bb72c18b2774329ec34 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 13:55:12 -0700 Subject: [PATCH 57/91] Revert "Update .github/workflows/e2e_tests.yml" This reverts commit d5b4a6e6a77f52b510306c9a6ba3bb256559469a. --- .github/workflows/e2e_tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index f620c318..83f7da96 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -6,9 +6,6 @@ on: pull_request: branches: [main] -permissions: - pull-requests: write - jobs: test: timeout-minutes: 5 From 4375433a8550117b5260f56f401a27750637deda Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Fri, 20 Jun 2025 15:27:39 -0700 Subject: [PATCH 58/91] docs: Update project organization in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add cli/ directory description - Remove non-existent bin/ directory reference šŸ¤– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index e62fd188..ec826b1f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,4 +30,4 @@ The project is organized as a monorepo with workspaces: - `client/`: React frontend with Vite, TypeScript and Tailwind - `server/`: Express backend with TypeScript -- `bin/`: CLI scripts +- `cli/`: Command-line interface for testing and invoking MCP server methods directly From c747fe85d8e1f0619ed761366dd66c8c30aeced4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 19:17:12 -0700 Subject: [PATCH 59/91] Only try to comment on PR if the PR is from the canonical repo and not from a fork --- .github/workflows/e2e_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 83f7da96..e56a49d8 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -59,7 +59,7 @@ jobs: - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 - if: always() + if: always() && github.event.pull_request.head.repo.full_name == github.repository with: report-file: client/results.json comment-title: "šŸŽ­ Playwright E2E Test Results" From 94a35d07f3f3e7b98de1ae72c9b22c2604685c3e Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 19:24:32 -0700 Subject: [PATCH 60/91] Only try to comment on PR if the PR is from the canonical repo and not from a fork --- .github/workflows/e2e_tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index e56a49d8..35786cbe 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -59,8 +59,9 @@ jobs: - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 - if: always() && github.event.pull_request.head.repo.full_name == github.repository + if: always() with: + create-comment: github.event.pull_request.head.repo.full_name == github.repository report-file: client/results.json comment-title: "šŸŽ­ Playwright E2E Test Results" job-summary: true From 2cd7b7490c1e68a01fcb214f659d6b6eaad822ae Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 19:29:47 -0700 Subject: [PATCH 61/91] Revert --- .github/workflows/e2e_tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 35786cbe..e56a49d8 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -59,9 +59,8 @@ jobs: - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 - if: always() + if: always() && github.event.pull_request.head.repo.full_name == github.repository with: - create-comment: github.event.pull_request.head.repo.full_name == github.repository report-file: client/results.json comment-title: "šŸŽ­ Playwright E2E Test Results" job-summary: true From ebc249b3d5144cdc27c5763c2c1ea6cd7c991cb5 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 20 Jun 2025 19:43:19 -0700 Subject: [PATCH 62/91] Always gen test summary but only comment on same repo PRs --- .github/workflows/e2e_tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index e56a49d8..f40dd582 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -59,8 +59,9 @@ jobs: - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 - if: always() && github.event.pull_request.head.repo.full_name == github.repository + if: always() with: + create-comment: ${{ github.event.pull_request.head.repo.full_name == github.repository }} report-file: client/results.json comment-title: "šŸŽ­ Playwright E2E Test Results" job-summary: true From f5dba84051f4ae61d7bf8c121cea1ed09b55be98 Mon Sep 17 00:00:00 2001 From: Mark Anthony Cianfrani Date: Sat, 21 Jun 2025 11:57:42 -0400 Subject: [PATCH 63/91] fix: allow typing negative numbers in tool parameter inputs Number inputs were immediately converting values to Number() on every keystroke, which prevented users from typing negative numbers since the intermediate "-" character cannot be converted to a valid number. Now the input stores the raw string value and only converts to Number when the value is non-empty, allowing proper negative number entry. --- client/src/components/ToolsTab.tsx | 9 ++++---- .../components/__tests__/ToolsTab.test.tsx | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 8a7f6578..2b139ed6 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -163,12 +163,13 @@ const ToolsTab = ({ name={key} placeholder={prop.description} value={(params[key] as string) ?? ""} - onChange={(e) => + onChange={(e) => { + const value = e.target.value; setParams({ ...params, - [key]: Number(e.target.value), - }) - } + [key]: value === "" ? "" : Number(value), + }); + }} className="mt-1" /> ) : ( diff --git a/client/src/components/__tests__/ToolsTab.test.tsx b/client/src/components/__tests__/ToolsTab.test.tsx index c9f9b315..dc353ba5 100644 --- a/client/src/components/__tests__/ToolsTab.test.tsx +++ b/client/src/components/__tests__/ToolsTab.test.tsx @@ -111,6 +111,27 @@ describe("ToolsTab", () => { }); }); + it("should allow typing negative numbers", async () => { + renderToolsTab({ + selectedTool: mockTools[0], + }); + + const input = screen.getByRole("spinbutton") as HTMLInputElement; + + // Complete the negative number + fireEvent.change(input, { target: { value: "-42" } }); + expect(input.value).toBe("-42"); + + const submitButton = screen.getByRole("button", { name: /run tool/i }); + await act(async () => { + fireEvent.click(submitButton); + }); + + expect(defaultProps.callTool).toHaveBeenCalledWith(mockTools[0].name, { + num: -42, + }); + }); + it("should disable button and change text while tool is running", async () => { // Create a promise that we can resolve later let resolvePromise: ((value: unknown) => void) | undefined; From 5db64265cec2942ace9f5aceebd7862aeef3625c Mon Sep 17 00:00:00 2001 From: Paul Carleton Date: Mon, 23 Jun 2025 16:39:07 +0100 Subject: [PATCH 64/91] [auth] Add resource compatibility to debugger (RFC 8707) (#526) * pass resource in auth debugger, reusing server url * throw error on resource url mismatch to match regular auth flow * lint & tests * add test * make authserver url make more sense * use latest typescript sdk * more lenient resource checking * pick resource, and store in state * fixing tests and types * [auth] use sdk function for selecting resource (#537) * use sdk function * bump typescript sdk * fix some tests --- client/src/components/OAuthFlowProgress.tsx | 2 +- .../__tests__/AuthDebugger.test.tsx | 22 ++++++++++--------- client/src/lib/auth-types.ts | 2 ++ client/src/lib/oauth-state-machine.ts | 19 +++++++++++----- package-lock.json | 9 ++++---- package.json | 2 +- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/client/src/components/OAuthFlowProgress.tsx b/client/src/components/OAuthFlowProgress.tsx index b9b67c6c..0e260556 100644 --- a/client/src/components/OAuthFlowProgress.tsx +++ b/client/src/components/OAuthFlowProgress.tsx @@ -156,7 +156,7 @@ export const OAuthFlowProgress = ({ {authState.resourceMetadataError && (

- ā„¹ļø No resource metadata available from{" "} + ā„¹ļø Problem with resource metadata from{" "} ({ startAuthorization: jest.fn(), exchangeAuthorization: jest.fn(), discoverOAuthProtectedResourceMetadata: jest.fn(), + selectResourceURL: jest.fn(), })); // Import the functions to get their types @@ -88,7 +89,7 @@ describe("AuthDebugger", () => { const defaultAuthState = EMPTY_DEBUGGER_STATE; const defaultProps = { - serverUrl: "https://example.com", + serverUrl: "https://example.com/mcp", onBack: jest.fn(), authState: defaultAuthState, updateAuthState: jest.fn(), @@ -203,7 +204,7 @@ describe("AuthDebugger", () => { // Should first discover and save OAuth metadata expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith( - new URL("https://example.com"), + new URL("https://example.com/"), ); // Check that updateAuthState was called with the right info message @@ -320,6 +321,7 @@ describe("AuthDebugger", () => { isInitiatingAuth: false, resourceMetadata: null, resourceMetadataError: null, + resource: null, oauthTokens: null, oauthStep: "metadata_discovery", latestError: null, @@ -361,7 +363,7 @@ describe("AuthDebugger", () => { }); expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith( - new URL("https://example.com"), + new URL("https://example.com/"), ); }); @@ -496,11 +498,11 @@ describe("AuthDebugger", () => { it("should successfully fetch and display protected resource metadata", async () => { const updateAuthState = jest.fn(); const mockResourceMetadata = { - resource: "https://example.com/api", + resource: "https://example.com/mcp", authorization_servers: ["https://custom-auth.example.com"], bearer_methods_supported: ["header", "body"], - resource_documentation: "https://example.com/api/docs", - resource_policy_uri: "https://example.com/api/policy", + resource_documentation: "https://example.com/mcp/docs", + resource_policy_uri: "https://example.com/mcp/policy", }; // Mock successful metadata discovery @@ -538,7 +540,7 @@ describe("AuthDebugger", () => { // Wait for the metadata to be fetched await waitFor(() => { expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith( - "https://example.com", + "https://example.com/mcp", ); }); @@ -584,7 +586,7 @@ describe("AuthDebugger", () => { // Wait for the metadata fetch to fail await waitFor(() => { expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith( - "https://example.com", + "https://example.com/mcp", ); }); @@ -594,7 +596,7 @@ describe("AuthDebugger", () => { expect.objectContaining({ resourceMetadataError: mockError, // Should use the original server URL as fallback - authServerUrl: new URL("https://example.com"), + authServerUrl: new URL("https://example.com/"), oauthStep: "client_registration", }), ); @@ -602,7 +604,7 @@ describe("AuthDebugger", () => { // Verify that regular OAuth metadata discovery was still called expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith( - new URL("https://example.com"), + new URL("https://example.com/"), ); }); }); diff --git a/client/src/lib/auth-types.ts b/client/src/lib/auth-types.ts index 5e8113ef..f8f927c6 100644 --- a/client/src/lib/auth-types.ts +++ b/client/src/lib/auth-types.ts @@ -30,6 +30,7 @@ export interface AuthDebuggerState { oauthStep: OAuthStep; resourceMetadata: OAuthProtectedResourceMetadata | null; resourceMetadataError: Error | null; + resource: URL | null; authServerUrl: URL | null; oauthMetadata: OAuthMetadata | null; oauthClientInfo: OAuthClientInformationFull | OAuthClientInformation | null; @@ -47,6 +48,7 @@ export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = { oauthMetadata: null, resourceMetadata: null, resourceMetadataError: null, + resource: null, authServerUrl: null, oauthClientInfo: null, authorizationUrl: null, diff --git a/client/src/lib/oauth-state-machine.ts b/client/src/lib/oauth-state-machine.ts index 5f10a783..d87b3ecd 100644 --- a/client/src/lib/oauth-state-machine.ts +++ b/client/src/lib/oauth-state-machine.ts @@ -6,6 +6,7 @@ import { startAuthorization, exchangeAuthorization, discoverOAuthProtectedResourceMetadata, + selectResourceURL, } from "@modelcontextprotocol/sdk/client/auth.js"; import { OAuthMetadataSchema, @@ -29,17 +30,15 @@ export const oauthTransitions: Record = { metadata_discovery: { canTransition: async () => true, execute: async (context) => { - let authServerUrl = new URL(context.serverUrl); + // Default to discovering from the server's URL + let authServerUrl = new URL("/", context.serverUrl); let resourceMetadata: OAuthProtectedResourceMetadata | null = null; let resourceMetadataError: Error | null = null; try { resourceMetadata = await discoverOAuthProtectedResourceMetadata( context.serverUrl, ); - if ( - resourceMetadata && - resourceMetadata.authorization_servers?.length - ) { + if (resourceMetadata?.authorization_servers?.length) { authServerUrl = new URL(resourceMetadata.authorization_servers[0]); } } catch (e) { @@ -50,6 +49,13 @@ export const oauthTransitions: Record = { } } + const resource: URL | undefined = await selectResourceURL( + context.serverUrl, + context.provider, + // we default to null, so swap it for undefined if not set + resourceMetadata ?? undefined, + ); + const metadata = await discoverOAuthMetadata(authServerUrl); if (!metadata) { throw new Error("Failed to discover OAuth metadata"); @@ -58,6 +64,7 @@ export const oauthTransitions: Record = { context.provider.saveServerMetadata(parsedMetadata); context.updateState({ resourceMetadata, + resource, resourceMetadataError, authServerUrl, oauthMetadata: parsedMetadata, @@ -113,6 +120,7 @@ export const oauthTransitions: Record = { clientInformation, redirectUrl: context.provider.redirectUrl, scope, + resource: context.state.resource ?? undefined, }, ); @@ -163,6 +171,7 @@ export const oauthTransitions: Record = { authorizationCode: context.state.authorizationCode, codeVerifier, redirectUri: context.provider.redirectUrl, + resource: context.state.resource ?? undefined, }); context.provider.saveTokens(tokens); diff --git a/package-lock.json b/package-lock.json index 09db8c0d..695f6a02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@modelcontextprotocol/inspector-cli": "^0.14.3", "@modelcontextprotocol/inspector-client": "^0.14.3", "@modelcontextprotocol/inspector-server": "^0.14.3", - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "concurrently": "^9.0.1", "open": "^10.1.0", "shell-quote": "^1.8.2", @@ -2005,10 +2005,9 @@ "link": true }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.13.0.tgz", - "integrity": "sha512-P5FZsXU0kY881F6Hbk9GhsYx02/KgWK1DYf7/tyE/1lcFKhDYPQR9iYjhQXJn+Sg6hQleMo3DB7h7+p4wgp2Lw==", - "license": "MIT", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.13.1.tgz", + "integrity": "sha512-8q6+9aF0yA39/qWT/uaIj6zTpC+Qu07DnN/lb9mjoquCJsAh6l3HyYqc9O3t2j7GilseOQOQimLg7W3By6jqvg==", "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", diff --git a/package.json b/package.json index a21363a7..7b89edb8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@modelcontextprotocol/inspector-cli": "^0.14.3", "@modelcontextprotocol/inspector-client": "^0.14.3", "@modelcontextprotocol/inspector-server": "^0.14.3", - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "concurrently": "^9.0.1", "open": "^10.1.0", "shell-quote": "^1.8.2", From 336804d97c3db80ff89a3c7367fd30de91c3a21f Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 17:00:05 -0700 Subject: [PATCH 65/91] Update @radix-ui/react-checkbox --- package-lock.json | 49 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e74be50..7c58b359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2123,16 +2123,16 @@ } }, "node_modules/@radix-ui/react-checkbox": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.2.3.tgz", - "integrity": "sha512-pHVzDYsnaDmBlAuwim45y3soIN8H4R7KbkSVirGhXO+R/kO2OLCe0eucUEbddaTcdMHHdzcIGHtZSMSQlA+apw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.2.tgz", + "integrity": "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" @@ -2152,6 +2152,47 @@ } } }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz", From 6d8e2ddd2f12b49d5e49c7065d4cd00341dba5c4 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 17:06:32 -0700 Subject: [PATCH 66/91] Update @radix-ui/react-label --- package-lock.json | 49 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c58b359..2cad711c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2395,12 +2395,12 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.4.tgz", - "integrity": "sha512-wy3dqizZnZVV4ja0FNnUhIWNwWdoldXrneEyUcVtLYDAt8ovGS4ridtMAOGgXBBIfggL4BOveVWsjXDORdGEQg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.0" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -2417,6 +2417,47 @@ } } }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.11.tgz", From 21d3b7d0f3874ef2c3d0635a8041bbddd918d9b6 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 17:10:22 -0700 Subject: [PATCH 67/91] Update @radix-ui/react-tabs --- package-lock.json | 128 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2cad711c..fa7011f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2599,18 +2599,18 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.7.tgz", - "integrity": "sha512-C6oAg451/fQT3EGbWHbCQjYTtbyjNO1uzQgMzwyivcHT3GKNEmu1q3UuREhN+HzHAVtv3ivMVK08QlC+PkYw9Q==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, @@ -2629,6 +2629,73 @@ } } }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.2.tgz", @@ -2691,9 +2758,9 @@ } }, "node_modules/@radix-ui/react-tabs": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.9.tgz", - "integrity": "sha512-KIjtwciYvquiW/wAFkELZCVnaNLBsYNhTNcvl+zfMAbMhRkcvNuCLXDDd22L0j7tagpzVh/QwbFpwAATg7ILPw==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz", + "integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -2701,8 +2768,8 @@ "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-roving-focus": "1.1.7", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { @@ -2720,6 +2787,47 @@ } } }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-toast": { "version": "1.2.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.11.tgz", From 54209f4809182c36f20b95df938d0fd27893224b Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 17:20:05 -0700 Subject: [PATCH 68/91] Update @radix-ui/react-tooltip --- package-lock.json | 188 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa7011f6..4b9a05d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2863,23 +2863,193 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.4.tgz", - "integrity": "sha512-DyW8VVeeMSSLFvAmnVnCwvI3H+1tpJFHT50r+tdOoMse9XqYDBCcyux8u3G2y+LOpt7fPQ6KKH0mhs+ce1+Z5w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz", + "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.4", - "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.0" + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", From 098712725580bcea291334613db87bb199b4de9a Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 17:38:28 -0700 Subject: [PATCH 69/91] Update @radix-ui/react-toast --- package-lock.json | 157 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b9a05d6..14c65e38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2829,23 +2829,164 @@ } }, "node_modules/@radix-ui/react-toast": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.11.tgz", - "integrity": "sha512-Ed2mlOmT+tktOsu2NZBK1bCSHh/uqULu1vWOkpQTVq53EoOuZUZw7FInQoDB3uil5wZc2oe0XN9a7uVZB7/6AQ==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.14.tgz", + "integrity": "sha512-nAP5FBxBJGQ/YfUB+r+O6USFVkWq3gAInkxyEnmvEV5jtSbfDhfa4hwX8CraCnbjMLsE7XSf/K75l9xXY7joWg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.7", - "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.0" + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", From 8153f0d5e4a7935225d3a9653f42cce3354f46f0 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 18:08:59 -0700 Subject: [PATCH 70/91] Update @radix-ui/react-dialog --- package-lock.json | 133 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14c65e38..bad767b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2250,22 +2250,22 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.11.tgz", - "integrity": "sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", + "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", - "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" @@ -2285,6 +2285,123 @@ } } }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", From 5d00e870b6da560f933eee4416984c08541defa3 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 18:20:36 -0700 Subject: [PATCH 71/91] Update @radix-ui/react-popover --- package-lock.json | 190 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 181 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index bad767b9..2c6d4453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2576,23 +2576,23 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.11.tgz", - "integrity": "sha512-yFMfZkVA5G3GJnBgb2PxrrcLKm1ZLWXrbYVgdyTl//0TYEIHS9LJbnyz7WWcZ0qCq7hIlJZpRtxeSeIG5T5oJw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", + "integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", - "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.4", - "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" @@ -2612,6 +2612,178 @@ } } }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz", From e0fe311528745d7cfd829f175f69fe43d2412c75 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Mon, 23 Jun 2025 18:25:23 -0700 Subject: [PATCH 72/91] Update @radix-ui/react-select --- package-lock.json | 872 +++------------------------------------------- 1 file changed, 41 insertions(+), 831 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c6d4453..d3019a93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2100,12 +2100,12 @@ "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.4.tgz", - "integrity": "sha512-qz+fxrqgNxG0dYew5l7qR3c7wdgRu1XVUHGnGYX7rg5HM4p9SWaRmJwfgR3J0SgyUKayLmzQIun+N6rWRgiRKw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.0" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -2152,57 +2152,16 @@ } } }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-collection": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz", - "integrity": "sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0" + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -2285,123 +2244,6 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", @@ -2418,14 +2260,14 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.7.tgz", - "integrity": "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, @@ -2460,13 +2302,13 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.4.tgz", - "integrity": "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { @@ -2534,47 +2376,6 @@ } } }, - "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-popover": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", @@ -2612,82 +2413,7 @@ } } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { + "node_modules/@radix-ui/react-popper": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", @@ -2719,7 +2445,7 @@ } } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-portal": { + "node_modules/@radix-ui/react-portal": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", @@ -2743,103 +2469,6 @@ } } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz", - "integrity": "sha512-3p2Rgm/a1cK0r/UVkx5F/K9v/EplfjAeIFCGOPYPO4lZ0jtg4iSQXt/YGTSLWaf4x7NG6Z4+uKFcylcTZjeqDA==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.4", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.6.tgz", - "integrity": "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-presence": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", @@ -2865,12 +2494,12 @@ } }, "node_modules/@radix-ui/react-primitive": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", - "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.0" + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -2918,98 +2547,31 @@ } } }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-select": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.2.tgz", - "integrity": "sha512-HjkVHtBkuq+r3zUAZ/CvNWUGKPfuicGDbgtZgiQuFmNcV5F+Tgy24ep2nsAW2nFgvhGPJVqeBZa6KyVN0EyrBA==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", - "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.4", - "@radix-ui/react-portal": "1.1.6", - "@radix-ui/react-primitive": "2.1.0", - "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.0", + "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, @@ -3029,9 +2591,9 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", - "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -3076,47 +2638,6 @@ } } }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-toast": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.14.tgz", @@ -3151,147 +2672,6 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-tooltip": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz", @@ -3326,176 +2706,6 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.2", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", - "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", @@ -3633,12 +2843,12 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.0.tgz", - "integrity": "sha512-rQj0aAWOpCdCMRbI6pLQm8r7S2BM3YhTa0SzOYD55k+hJA8oo9J+H+9wLM9oMlZWOX/wJWPTzfDfmZkf7LvCfg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.0" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", From 9c5c7575c0c095d0134bfb1338252a6fee1f98a0 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Wed, 18 Jun 2025 17:14:07 +0100 Subject: [PATCH 73/91] fix: Bind client to localhost by default to prevent DNS rebinding attacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete the security hardening started in e8e9909 by also binding the client to localhost only. Previously only the server was protected while the client remained exposed to the network, allowing attackers to access the server through the client as a proxy. Changes: - Add HOST environment variable support to client (prod mode) - Configure Vite dev server to bind to localhost by default - Update browser auto-open URLs to use actual host instead of hardcoded 127.0.0.1 - Fix missing cancelled parameter in startProdClient function šŸ¤– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 4 ++-- client/bin/client.js | 7 ++++--- client/bin/start.js | 20 ++++++++++++-------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 94efe83c..1a5bffff 100644 --- a/README.md +++ b/README.md @@ -168,13 +168,13 @@ DANGEROUSLY_OMIT_AUTH=true npm start #### Local-only Binding -By default, the MCP Inspector proxy server binds only to `127.0.0.1` (localhost) to prevent network access. This ensures the server is not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable: +By default, both the MCP Inspector proxy server and client bind only to `127.0.0.1` (localhost) to prevent network access. This ensures they are not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable: ```bash HOST=0.0.0.0 npm start ``` -**Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes. +**Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes and both services to network access. #### DNS Rebinding Protection diff --git a/client/bin/client.js b/client/bin/client.js index 7179e19e..45fc2421 100755 --- a/client/bin/client.js +++ b/client/bin/client.js @@ -40,18 +40,19 @@ const server = http.createServer((request, response) => { }); const port = process.env.PORT || 6274; +const host = process.env.HOST || "127.0.0.1"; server.on("listening", () => { console.log( - `šŸ” MCP Inspector is up and running at http://127.0.0.1:${port} šŸš€`, + `šŸ” MCP Inspector is up and running at http://${host}:${port} šŸš€`, ); }); server.on("error", (err) => { if (err.message.includes(`EADDRINUSE`)) { console.error( - `āŒ MCP Inspector PORT IS IN USE at http://127.0.0.1:${port} āŒ `, + `āŒ MCP Inspector PORT IS IN USE at http://${host}:${port} āŒ `, ); } else { throw err; } }); -server.listen(port); +server.listen(port, host); diff --git a/client/bin/start.js b/client/bin/start.js index ad75078a..54b125e9 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -102,7 +102,8 @@ async function startDevClient(clientOptions) { const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = clientOptions; const clientCommand = "npx"; - const clientArgs = ["vite", "--port", CLIENT_PORT]; + const host = process.env.HOST || "127.0.0.1"; + const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host]; const client = spawn(clientCommand, clientArgs, { cwd: resolve(__dirname, ".."), @@ -113,9 +114,10 @@ async function startDevClient(clientOptions) { // Auto-open browser after vite starts if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { + const clientHost = process.env.HOST || "127.0.0.1"; const url = authDisabled - ? `http://127.0.0.1:${CLIENT_PORT}` - : `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + ? `http://${clientHost}:${CLIENT_PORT}` + : `http://${clientHost}:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; // Give vite time to start before opening browser setTimeout(() => { @@ -139,7 +141,8 @@ async function startDevClient(clientOptions) { } async function startProdClient(clientOptions) { - const { CLIENT_PORT, authDisabled, sessionToken, abort } = clientOptions; + const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = + clientOptions; const inspectorClientPath = resolve( __dirname, "../..", @@ -148,11 +151,12 @@ async function startProdClient(clientOptions) { "client.js", ); - // Auto-open browser with token - if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { + // Only auto-open browser if not cancelled + if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) { + const clientHost = process.env.HOST || "127.0.0.1"; const url = authDisabled - ? `http://127.0.0.1:${CLIENT_PORT}` - : `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + ? `http://${clientHost}:${CLIENT_PORT}` + : `http://${clientHost}:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; open(url); } From fe2c5c767d7a7670f997a42cbe5d58ea2164d5ff Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Thu, 19 Jun 2025 11:47:04 +0100 Subject: [PATCH 74/91] refactor: deduplicate URL generation and standardize on localhost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract duplicated URL generation code into getClientUrl() helper function in start.js - Replace all 127.0.0.1 references with localhost for consistency across codebase - Update server to respect HOST environment variable for URL generation - Remove 127.0.0.1 from default allowed origins in CORS configuration - Update documentation to use localhost instead of 127.0.0.1 šŸ¤– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CONTRIBUTING.md | 2 +- README.md | 4 ++-- client/bin/client.js | 2 +- client/bin/start.js | 20 +++++++++++--------- server/src/index.ts | 13 ++++++------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1eeeb864..0129a9e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Thanks for your interest in contributing! This guide explains how to get involve 1. Fork the repository and clone it locally 2. Install dependencies with `npm install` 3. Run `npm run dev` to start both client and server in development mode -4. Use the web UI at http://127.0.0.1:6274 to interact with the inspector +4. Use the web UI at http://localhost:6274 to interact with the inspector ## Development Process & Pull Requests diff --git a/README.md b/README.md index 1a5bffff..deec2a45 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ DANGEROUSLY_OMIT_AUTH=true npm start #### Local-only Binding -By default, both the MCP Inspector proxy server and client bind only to `127.0.0.1` (localhost) to prevent network access. This ensures they are not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable: +By default, both the MCP Inspector proxy server and client bind only to `localhost` to prevent network access. This ensures they are not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable: ```bash HOST=0.0.0.0 npm start @@ -181,7 +181,7 @@ HOST=0.0.0.0 npm start To prevent DNS rebinding attacks, the MCP Inspector validates the `Origin` header on incoming requests. By default, only requests from the client origin are allowed (respects `CLIENT_PORT` if set, defaulting to port 6274). You can configure additional allowed origins by setting the `ALLOWED_ORIGINS` environment variable (comma-separated list): ```bash -ALLOWED_ORIGINS=http://localhost:6274,http://127.0.0.1:6274,http://localhost:8000 npm start +ALLOWED_ORIGINS=http://localhost:6274,http://localhost:8000 npm start ``` ### Configuration diff --git a/client/bin/client.js b/client/bin/client.js index 45fc2421..7c35a131 100755 --- a/client/bin/client.js +++ b/client/bin/client.js @@ -40,7 +40,7 @@ const server = http.createServer((request, response) => { }); const port = process.env.PORT || 6274; -const host = process.env.HOST || "127.0.0.1"; +const host = process.env.HOST || "localhost"; server.on("listening", () => { console.log( `šŸ” MCP Inspector is up and running at http://${host}:${port} šŸš€`, diff --git a/client/bin/start.js b/client/bin/start.js index 54b125e9..51d3ef76 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -12,6 +12,14 @@ function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms, true)); } +function getClientUrl(port, authDisabled, sessionToken) { + const host = process.env.HOST || "localhost"; + const baseUrl = `http://${host}:${port}`; + return authDisabled + ? baseUrl + : `${baseUrl}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; +} + async function startDevServer(serverOptions) { const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } = serverOptions; @@ -102,7 +110,7 @@ async function startDevClient(clientOptions) { const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = clientOptions; const clientCommand = "npx"; - const host = process.env.HOST || "127.0.0.1"; + const host = process.env.HOST || "localhost"; const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host]; const client = spawn(clientCommand, clientArgs, { @@ -114,10 +122,7 @@ async function startDevClient(clientOptions) { // Auto-open browser after vite starts if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { - const clientHost = process.env.HOST || "127.0.0.1"; - const url = authDisabled - ? `http://${clientHost}:${CLIENT_PORT}` - : `http://${clientHost}:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); // Give vite time to start before opening browser setTimeout(() => { @@ -153,10 +158,7 @@ async function startProdClient(clientOptions) { // Only auto-open browser if not cancelled if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) { - const clientHost = process.env.HOST || "127.0.0.1"; - const url = authDisabled - ? `http://${clientHost}:${CLIENT_PORT}` - : `http://${clientHost}:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); open(url); } diff --git a/server/src/index.ts b/server/src/index.ts index 7653597a..a18fa566 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -104,12 +104,10 @@ const originValidationMiddleware = ( // Default origins based on CLIENT_PORT or use environment variable const clientPort = process.env.CLIENT_PORT || "6274"; - const defaultOrigins = [ - `http://localhost:${clientPort}`, - `http://127.0.0.1:${clientPort}`, + const defaultOrigin = `http://localhost:${clientPort}`; + const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(",") || [ + defaultOrigin, ]; - const allowedOrigins = - process.env.ALLOWED_ORIGINS?.split(",") || defaultOrigins; if (origin && !allowedOrigins.includes(origin)) { console.error(`Invalid origin: ${origin}`); @@ -531,7 +529,7 @@ app.get("/config", originValidationMiddleware, authMiddleware, (req, res) => { }); const PORT = parseInt(process.env.PORT || "6277", 10); -const HOST = process.env.HOST || "127.0.0.1"; +const HOST = process.env.HOST || "localhost"; const server = app.listen(PORT, HOST); server.on("listening", () => { @@ -544,7 +542,8 @@ server.on("listening", () => { // Display clickable URL with pre-filled token const clientPort = process.env.CLIENT_PORT || "6274"; - const clientUrl = `http://localhost:${clientPort}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + const clientHost = process.env.HOST || "localhost"; + const clientUrl = `http://${clientHost}:${clientPort}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; console.log( `\nšŸ”— Open inspector with token pre-filled:\n ${clientUrl}\n`, ); From d0673ba9e1142ba3e720dd4bb655cee7c416ead1 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 20 Jun 2025 18:58:52 +0100 Subject: [PATCH 75/91] refactor: Use specific SERVER_PORT and CLIENT_PORT env vars Per PR feedback from cliffhall: - Changed PORT to SERVER_PORT in server/src/index.ts - Changed PORT to CLIENT_PORT in client/bin/client.js - Added parseInt() for CLIENT_PORT consistency - Updated start.js to pass correct env var names This improves clarity by using specific environment variables for server and client ports instead of the generic PORT variable. --- client/bin/client.js | 2 +- client/bin/start.js | 8 ++++---- server/src/index.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/bin/client.js b/client/bin/client.js index 7c35a131..e25ecb7c 100755 --- a/client/bin/client.js +++ b/client/bin/client.js @@ -39,7 +39,7 @@ const server = http.createServer((request, response) => { return handler(request, response, handlerOptions); }); -const port = process.env.PORT || 6274; +const port = parseInt(process.env.CLIENT_PORT || "6274", 10); const host = process.env.HOST || "localhost"; server.on("listening", () => { console.log( diff --git a/client/bin/start.js b/client/bin/start.js index 51d3ef76..bea3031f 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -31,7 +31,7 @@ async function startDevServer(serverOptions) { cwd: resolve(__dirname, "../..", "server"), env: { ...process.env, - PORT: SERVER_PORT, + SERVER_PORT: SERVER_PORT, CLIENT_PORT: CLIENT_PORT, MCP_PROXY_TOKEN: sessionToken, MCP_ENV_VARS: JSON.stringify(envVars), @@ -90,7 +90,7 @@ async function startProdServer(serverOptions) { { env: { ...process.env, - PORT: SERVER_PORT, + SERVER_PORT: SERVER_PORT, CLIENT_PORT: CLIENT_PORT, MCP_PROXY_TOKEN: sessionToken, MCP_ENV_VARS: JSON.stringify(envVars), @@ -115,7 +115,7 @@ async function startDevClient(clientOptions) { const client = spawn(clientCommand, clientArgs, { cwd: resolve(__dirname, ".."), - env: { ...process.env, PORT: CLIENT_PORT }, + env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, signal: abort.signal, echoOutput: true, }); @@ -163,7 +163,7 @@ async function startProdClient(clientOptions) { } await spawnPromise("node", [inspectorClientPath], { - env: { ...process.env, PORT: CLIENT_PORT }, + env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, signal: abort.signal, echoOutput: true, }); diff --git a/server/src/index.ts b/server/src/index.ts index a18fa566..89def8ba 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -528,7 +528,7 @@ app.get("/config", originValidationMiddleware, authMiddleware, (req, res) => { } }); -const PORT = parseInt(process.env.PORT || "6277", 10); +const PORT = parseInt(process.env.SERVER_PORT || "6277", 10); const HOST = process.env.HOST || "localhost"; const server = app.listen(PORT, HOST); From 0bef6f71ad9e9671b71ecb9c1460729b506de0e6 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Tue, 24 Jun 2025 09:23:51 -0500 Subject: [PATCH 76/91] feat: add tests for http transport --- cli/scripts/cli-tests.js | 105 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/cli/scripts/cli-tests.js b/cli/scripts/cli-tests.js index 6e6b56f9..ab5481c6 100755 --- a/cli/scripts/cli-tests.js +++ b/cli/scripts/cli-tests.js @@ -44,7 +44,10 @@ console.log(`${colors.BLUE}- Resource-related options (--uri)${colors.NC}`); console.log( `${colors.BLUE}- Prompt-related options (--prompt-name, --prompt-args)${colors.NC}`, ); -console.log(`${colors.BLUE}- Logging options (--log-level)${colors.NC}\n`); +console.log(`${colors.BLUE}- Logging options (--log-level)${colors.NC}`); +console.log(`${colors.BLUE}- Transport types (--transport http/sse/stdio)${colors.NC}`); +console.log(`${colors.BLUE}- Transport inference from URL suffixes (/mcp, /sse)${colors.NC}`); +console.log(`\n`); // Get directory paths const SCRIPTS_DIR = __dirname; @@ -62,9 +65,11 @@ if (!fs.existsSync(OUTPUT_DIR)) { } // Create a temporary directory for test files -const TEMP_DIR = fs.mkdirSync(path.join(os.tmpdir(), "mcp-inspector-tests"), { - recursive: true, -}); +const TEMP_DIR = path.join(os.tmpdir(), "mcp-inspector-tests"); +fs.mkdirSync(TEMP_DIR, { recursive: true }); + +// Track servers for cleanup +let runningServers = []; process.on("exit", () => { try { @@ -74,6 +79,23 @@ process.on("exit", () => { `${colors.RED}Failed to remove temp directory: ${err.message}${colors.NC}`, ); } + + runningServers.forEach(server => { + try { + process.kill(-server.pid); + } catch (e) { + } + }); +}); + +process.on("SIGINT", () => { + runningServers.forEach(server => { + try { + process.kill(-server.pid); + } catch (e) { + } + }); + process.exit(1); }); // Use the existing sample config file @@ -121,6 +143,11 @@ async function runBasicTest(testName, ...args) { stdio: ["ignore", "pipe", "pipe"], }); + const timeout = setTimeout(() => { + console.log(`${colors.YELLOW}Test timed out: ${testName}${colors.NC}`); + child.kill(); + }, 10000); + // Pipe stdout and stderr to the output file child.stdout.pipe(outputStream); child.stderr.pipe(outputStream); @@ -135,6 +162,7 @@ async function runBasicTest(testName, ...args) { }); child.on("close", (code) => { + clearTimeout(timeout); outputStream.end(); if (code === 0) { @@ -201,6 +229,11 @@ async function runErrorTest(testName, ...args) { stdio: ["ignore", "pipe", "pipe"], }); + const timeout = setTimeout(() => { + console.log(`${colors.YELLOW}Error test timed out: ${testName}${colors.NC}`); + child.kill(); + }, 10000); + // Pipe stdout and stderr to the output file child.stdout.pipe(outputStream); child.stderr.pipe(outputStream); @@ -215,6 +248,7 @@ async function runErrorTest(testName, ...args) { }); child.on("close", (code) => { + clearTimeout(timeout); outputStream.end(); // For error tests, we expect a non-zero exit code @@ -611,6 +645,69 @@ async function runTests() { "debug", ); + console.log( + `\n${colors.YELLOW}=== Running HTTP Transport Tests ===${colors.NC}`, + ); + + console.log(`${colors.BLUE}Starting server-everything in streamableHttp mode.${colors.NC}`); + const httpServer = spawn("npx", ["@modelcontextprotocol/server-everything", "streamableHttp"], { + detached: true, + stdio: "ignore" + }); + runningServers.push(httpServer); + + await new Promise(resolve => setTimeout(resolve, 3000)); + + // Test 25: HTTP transport inferred from URL ending with /mcp + await runBasicTest( + "http_transport_inferred", + "http://127.0.0.1:3001/mcp", + "--cli", + "--method", + "tools/list", + ); + + // Test 26: HTTP transport with explicit --transport http flag + await runBasicTest( + "http_transport_with_explicit_flag", + "http://127.0.0.1:3001", + "--transport", + "http", + "--cli", + "--method", + "tools/list", + ); + + // Test 27: HTTP transport with suffix and --transport http flag + await runBasicTest( + "http_transport_with_explicit_flag_and_suffix", + "http://127.0.0.1:3001/mcp", + "--transport", + "http", + "--cli", + "--method", + "tools/list", + ); + + // Test 28: SSE transport given to HTTP server (should fail) + await runErrorTest( + "sse_transport_given_to_http_server", + "http://127.0.0.1:3001", + "--transport", + "sse", + "--cli", + "--method", + "tools/list", + ); + + // Kill HTTP server + try { + process.kill(-httpServer.pid); + console.log(`${colors.BLUE}HTTP server killed, waiting for port to be released...${colors.NC}`); + } catch (e) { + console.log(`${colors.RED}Error killing HTTP server: ${e.message}${colors.NC}`); + } + // Print test summary console.log(`\n${colors.YELLOW}=== Test Summary ===${colors.NC}`); console.log(`${colors.GREEN}Passed: ${PASSED_TESTS}${colors.NC}`); From 73bb0005974d82896e0e947744d372fffb6c7271 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Tue, 24 Jun 2025 12:43:03 -0700 Subject: [PATCH 77/91] Update lucide-react Checked for icon name changes by teaching Claude to search the lucide-react repo with: `git log -i -E --grep '(rename|change)' 0.448.0^...0.523.0 ..then searching for any of the found icons in the Inspector imports. --- client/package.json | 2 +- package-lock.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/package.json b/client/package.json index 12438aeb..3c87560a 100644 --- a/client/package.json +++ b/client/package.json @@ -40,7 +40,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.4", - "lucide-react": "^0.447.0", + "lucide-react": "^0.523.0", "pkce-challenge": "^4.1.0", "prismjs": "^1.30.0", "react": "^18.3.1", diff --git a/package-lock.json b/package-lock.json index d3019a93..4bfb7a9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,7 +82,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.4", - "lucide-react": "^0.447.0", + "lucide-react": "^0.523.0", "pkce-challenge": "^4.1.0", "prismjs": "^1.30.0", "react": "^18.3.1", @@ -7860,12 +7860,12 @@ } }, "node_modules/lucide-react": { - "version": "0.447.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.447.0.tgz", - "integrity": "sha512-SZ//hQmvi+kDKrNepArVkYK7/jfeZ5uFNEnYmd45RKZcbGD78KLnrcNXmgeg6m+xNHFvTG+CblszXCy4n6DN4w==", + "version": "0.523.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.523.0.tgz", + "integrity": "sha512-rUjQoy7egZT9XYVXBK1je9ckBnNp7qzRZOhLQx5RcEp2dCGlXo+mv6vf7Am4LimEcFBJIIZzSGfgTqc9QCrPSw==", "license": "ISC", "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/lz-string": { From 7dc7b09cd4b01acd6ba2d3bf31890d94e47ccf37 Mon Sep 17 00:00:00 2001 From: Sebastian Ko Date: Wed, 25 Jun 2025 00:45:03 -0400 Subject: [PATCH 78/91] Change var to let --- client/src/utils/configUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/configUtils.ts b/client/src/utils/configUtils.ts index 43da9188..f7bd4bb9 100644 --- a/client/src/utils/configUtils.ts +++ b/client/src/utils/configUtils.ts @@ -5,7 +5,7 @@ import { } from "@/lib/constants"; export const getMCPProxyAddress = (config: InspectorConfig): string => { - var proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; + let proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; if (proxyFullAddress) { proxyFullAddress = proxyFullAddress.replace(/\/+$/, ""); return proxyFullAddress; From 14a9b8fb36ca752707089f7f7c6d3e8420158470 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Wed, 25 Jun 2025 00:46:11 -0500 Subject: [PATCH 79/91] feat: formatting --- cli/scripts/cli-tests.js | 48 ++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/cli/scripts/cli-tests.js b/cli/scripts/cli-tests.js index ab5481c6..51bda553 100755 --- a/cli/scripts/cli-tests.js +++ b/cli/scripts/cli-tests.js @@ -45,8 +45,12 @@ console.log( `${colors.BLUE}- Prompt-related options (--prompt-name, --prompt-args)${colors.NC}`, ); console.log(`${colors.BLUE}- Logging options (--log-level)${colors.NC}`); -console.log(`${colors.BLUE}- Transport types (--transport http/sse/stdio)${colors.NC}`); -console.log(`${colors.BLUE}- Transport inference from URL suffixes (/mcp, /sse)${colors.NC}`); +console.log( + `${colors.BLUE}- Transport types (--transport http/sse/stdio)${colors.NC}`, +); +console.log( + `${colors.BLUE}- Transport inference from URL suffixes (/mcp, /sse)${colors.NC}`, +); console.log(`\n`); // Get directory paths @@ -80,20 +84,18 @@ process.on("exit", () => { ); } - runningServers.forEach(server => { + runningServers.forEach((server) => { try { process.kill(-server.pid); - } catch (e) { - } + } catch (e) {} }); }); process.on("SIGINT", () => { - runningServers.forEach(server => { + runningServers.forEach((server) => { try { process.kill(-server.pid); - } catch (e) { - } + } catch (e) {} }); process.exit(1); }); @@ -230,7 +232,9 @@ async function runErrorTest(testName, ...args) { }); const timeout = setTimeout(() => { - console.log(`${colors.YELLOW}Error test timed out: ${testName}${colors.NC}`); + console.log( + `${colors.YELLOW}Error test timed out: ${testName}${colors.NC}`, + ); child.kill(); }, 10000); @@ -649,14 +653,20 @@ async function runTests() { `\n${colors.YELLOW}=== Running HTTP Transport Tests ===${colors.NC}`, ); - console.log(`${colors.BLUE}Starting server-everything in streamableHttp mode.${colors.NC}`); - const httpServer = spawn("npx", ["@modelcontextprotocol/server-everything", "streamableHttp"], { - detached: true, - stdio: "ignore" - }); + console.log( + `${colors.BLUE}Starting server-everything in streamableHttp mode.${colors.NC}`, + ); + const httpServer = spawn( + "npx", + ["@modelcontextprotocol/server-everything", "streamableHttp"], + { + detached: true, + stdio: "ignore", + }, + ); runningServers.push(httpServer); - await new Promise(resolve => setTimeout(resolve, 3000)); + await new Promise((resolve) => setTimeout(resolve, 3000)); // Test 25: HTTP transport inferred from URL ending with /mcp await runBasicTest( @@ -703,9 +713,13 @@ async function runTests() { // Kill HTTP server try { process.kill(-httpServer.pid); - console.log(`${colors.BLUE}HTTP server killed, waiting for port to be released...${colors.NC}`); + console.log( + `${colors.BLUE}HTTP server killed, waiting for port to be released...${colors.NC}`, + ); } catch (e) { - console.log(`${colors.RED}Error killing HTTP server: ${e.message}${colors.NC}`); + console.log( + `${colors.RED}Error killing HTTP server: ${e.message}${colors.NC}`, + ); } // Print test summary From 36e053ae66642c8112bd13eef7e18218d8c04f6f Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Wed, 25 Jun 2025 01:57:32 -0700 Subject: [PATCH 80/91] Adjust e2e test configuration - Playwright installation can take more than 5m, increase to 15m - Only attempt to upload the report if Playwright executed, otherwise there are no report files, and the upload step will error --- .github/workflows/e2e_tests.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index f40dd582..2630a495 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -8,7 +8,8 @@ on: jobs: test: - timeout-minutes: 5 + # Installing Playright dependencies can take quite awhile, and also depends on GitHub CI load. + timeout-minutes: 15 runs-on: ubuntu-latest steps: @@ -44,11 +45,12 @@ jobs: if: steps.cache-playwright.outputs.cache-hit != 'true' - name: Run Playwright tests + id: playwright-tests run: npm run test:e2e - name: Upload Playwright Report and Screenshots uses: actions/upload-artifact@v4 - if: always() + if: steps.playwright-tests.conclusion != 'skipped' with: name: playwright-report path: | @@ -59,7 +61,7 @@ jobs: - name: Publish Playwright Test Summary uses: daun/playwright-report-summary@v3 - if: always() + if: steps.playwright-tests.conclusion != 'skipped' with: create-comment: ${{ github.event.pull_request.head.repo.full_name == github.repository }} report-file: client/results.json From 2ca82b5be6f870cdf2bf87c1fbd39c5d7fca0a4c Mon Sep 17 00:00:00 2001 From: olaservo Date: Wed, 25 Jun 2025 07:19:44 -0700 Subject: [PATCH 81/91] Bump version to 0.15.0 --- cli/package.json | 2 +- client/package.json | 2 +- package-lock.json | 16 ++++++++-------- package.json | 8 ++++---- server/package.json | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cli/package.json b/cli/package.json index 382eb1b4..1676c046 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-cli", - "version": "0.14.3", + "version": "0.15.0", "description": "CLI for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/client/package.json b/client/package.json index 3c87560a..ba7e52ad 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-client", - "version": "0.14.3", + "version": "0.15.0", "description": "Client-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/package-lock.json b/package-lock.json index 4bfb7a9d..6f2acb04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.14.3", + "version": "0.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@modelcontextprotocol/inspector", - "version": "0.14.3", + "version": "0.15.0", "license": "MIT", "workspaces": [ "client", @@ -14,9 +14,9 @@ "cli" ], "dependencies": { - "@modelcontextprotocol/inspector-cli": "^0.14.3", - "@modelcontextprotocol/inspector-client": "^0.14.3", - "@modelcontextprotocol/inspector-server": "^0.14.3", + "@modelcontextprotocol/inspector-cli": "^0.15.0", + "@modelcontextprotocol/inspector-client": "^0.15.0", + "@modelcontextprotocol/inspector-server": "^0.15.0", "@modelcontextprotocol/sdk": "^1.13.1", "concurrently": "^9.0.1", "open": "^10.1.0", @@ -41,7 +41,7 @@ }, "cli": { "name": "@modelcontextprotocol/inspector-cli", - "version": "0.14.3", + "version": "0.15.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.13.0", @@ -64,7 +64,7 @@ }, "client": { "name": "@modelcontextprotocol/inspector-client", - "version": "0.14.3", + "version": "0.15.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.13.0", @@ -10984,7 +10984,7 @@ }, "server": { "name": "@modelcontextprotocol/inspector-server", - "version": "0.14.3", + "version": "0.15.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.13.0", diff --git a/package.json b/package.json index 8f48f85a..de02890d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.14.3", + "version": "0.15.0", "description": "Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -44,9 +44,9 @@ "check-version": "node scripts/check-version-consistency.js" }, "dependencies": { - "@modelcontextprotocol/inspector-cli": "^0.14.3", - "@modelcontextprotocol/inspector-client": "^0.14.3", - "@modelcontextprotocol/inspector-server": "^0.14.3", + "@modelcontextprotocol/inspector-cli": "^0.15.0", + "@modelcontextprotocol/inspector-client": "^0.15.0", + "@modelcontextprotocol/inspector-server": "^0.15.0", "@modelcontextprotocol/sdk": "^1.13.1", "concurrently": "^9.0.1", "open": "^10.1.0", diff --git a/server/package.json b/server/package.json index 9c248635..58d6ceb7 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-server", - "version": "0.14.3", + "version": "0.15.0", "description": "Server-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", From d49a5f65c15c4dfdc44bb663c17408b8a66488d0 Mon Sep 17 00:00:00 2001 From: olaservo Date: Wed, 25 Jun 2025 07:22:34 -0700 Subject: [PATCH 82/91] Bump sdk --- cli/package.json | 2 +- client/package.json | 2 +- package-lock.json | 6 +++--- server/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cli/package.json b/cli/package.json index 1676c046..bfb173a8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -21,7 +21,7 @@ }, "devDependencies": {}, "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "commander": "^13.1.0", "spawn-rx": "^5.1.2" } diff --git a/client/package.json b/client/package.json index ba7e52ad..59bf2288 100644 --- a/client/package.json +++ b/client/package.json @@ -25,7 +25,7 @@ "cleanup:e2e": "node e2e/global-teardown.js" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "@radix-ui/react-checkbox": "^1.1.4", "ajv": "^6.12.6", "@radix-ui/react-dialog": "^1.1.3", diff --git a/package-lock.json b/package-lock.json index 6f2acb04..ce3b7ba7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "version": "0.15.0", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "commander": "^13.1.0", "spawn-rx": "^5.1.2" }, @@ -67,7 +67,7 @@ "version": "0.15.0", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", @@ -10987,7 +10987,7 @@ "version": "0.15.0", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0", diff --git a/server/package.json b/server/package.json index 58d6ceb7..b43fc289 100644 --- a/server/package.json +++ b/server/package.json @@ -27,7 +27,7 @@ "typescript": "^5.6.2" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.13.0", + "@modelcontextprotocol/sdk": "^1.13.1", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0", From 9fcfd89326361ce69e1d97af219847ff478228a8 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Tue, 24 Jun 2025 11:42:45 +0100 Subject: [PATCH 83/91] fix: pass proxy port via URL params when non-default - Update client to read MCP_PROXY_PORT from URL parameters - Update server to include port in displayed URL when non-default - Update start scripts to pass SERVER_PORT to client - Use DEFAULT_MCP_PROXY_LISTEN_PORT constant instead of magic numbers This fixes the issue where the client couldn't connect to the proxy when SERVER_PORT was set to a non-default value. --- client/bin/start.js | 57 ++++++++++++++++++++++++++------- client/src/utils/configUtils.ts | 25 +++++++++------ server/src/index.ts | 18 +++++++++-- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/client/bin/start.js b/client/bin/start.js index bea3031f..96556790 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -7,17 +7,29 @@ import { fileURLToPath } from "url"; import { randomBytes } from "crypto"; const __dirname = dirname(fileURLToPath(import.meta.url)); +const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277"; function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms, true)); } -function getClientUrl(port, authDisabled, sessionToken) { +function getClientUrl(port, authDisabled, sessionToken, serverPort) { const host = process.env.HOST || "localhost"; const baseUrl = `http://${host}:${port}`; - return authDisabled - ? baseUrl - : `${baseUrl}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + + if (authDisabled) { + return baseUrl; + } + + const params = new URLSearchParams(); + params.set("MCP_PROXY_AUTH_TOKEN", sessionToken); + + // Add server port if it's not the default + if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) { + params.set("MCP_PROXY_PORT", serverPort); + } + + return `${baseUrl}/?${params.toString()}`; } async function startDevServer(serverOptions) { @@ -107,8 +119,14 @@ async function startProdServer(serverOptions) { } async function startDevClient(clientOptions) { - const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = - clientOptions; + const { + CLIENT_PORT, + SERVER_PORT, + authDisabled, + sessionToken, + abort, + cancelled, + } = clientOptions; const clientCommand = "npx"; const host = process.env.HOST || "localhost"; const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host]; @@ -122,7 +140,12 @@ async function startDevClient(clientOptions) { // Auto-open browser after vite starts if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { - const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); + const url = getClientUrl( + CLIENT_PORT, + authDisabled, + sessionToken, + SERVER_PORT, + ); // Give vite time to start before opening browser setTimeout(() => { @@ -146,8 +169,14 @@ async function startDevClient(clientOptions) { } async function startProdClient(clientOptions) { - const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } = - clientOptions; + const { + CLIENT_PORT, + SERVER_PORT, + authDisabled, + sessionToken, + abort, + cancelled, + } = clientOptions; const inspectorClientPath = resolve( __dirname, "../..", @@ -158,7 +187,12 @@ async function startProdClient(clientOptions) { // Only auto-open browser if not cancelled if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) { - const url = getClientUrl(CLIENT_PORT, authDisabled, sessionToken); + const url = getClientUrl( + CLIENT_PORT, + authDisabled, + sessionToken, + SERVER_PORT, + ); open(url); } @@ -210,7 +244,7 @@ async function main() { } const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274"; - const SERVER_PORT = process.env.SERVER_PORT ?? "6277"; + const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT; console.log( isDev @@ -255,6 +289,7 @@ async function main() { try { const clientOptions = { CLIENT_PORT, + SERVER_PORT, authDisabled, sessionToken, abort, diff --git a/client/src/utils/configUtils.ts b/client/src/utils/configUtils.ts index 40e47a94..85319497 100644 --- a/client/src/utils/configUtils.ts +++ b/client/src/utils/configUtils.ts @@ -4,12 +4,26 @@ import { DEFAULT_INSPECTOR_CONFIG, } from "@/lib/constants"; +const getSearchParam = (key: string): string | null => { + try { + const url = new URL(window.location.href); + return url.searchParams.get(key); + } catch { + return null; + } +}; + export const getMCPProxyAddress = (config: InspectorConfig): string => { const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; if (proxyFullAddress) { return proxyFullAddress; } - return `${window.location.protocol}//${window.location.hostname}:${DEFAULT_MCP_PROXY_LISTEN_PORT}`; + + // Check for proxy port from query params, fallback to default + const proxyPort = + getSearchParam("MCP_PROXY_PORT") || DEFAULT_MCP_PROXY_LISTEN_PORT; + + return `${window.location.protocol}//${window.location.hostname}:${proxyPort}`; }; export const getMCPServerRequestTimeout = (config: InspectorConfig): number => { @@ -40,15 +54,6 @@ export const getMCPProxyAuthToken = ( }; }; -const getSearchParam = (key: string): string | null => { - try { - const url = new URL(window.location.href); - return url.searchParams.get(key); - } catch { - return null; - } -}; - export const getInitialTransportType = (): | "stdio" | "sse" diff --git a/server/src/index.ts b/server/src/index.ts index 89def8ba..3e02cad1 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -21,6 +21,7 @@ import { findActualExecutable } from "spawn-rx"; import mcpProxy from "./mcpProxy.js"; import { randomUUID, randomBytes, timingSafeEqual } from "node:crypto"; +const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277"; const SSE_HEADERS_PASSTHROUGH = ["authorization"]; const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = [ "authorization", @@ -528,7 +529,10 @@ app.get("/config", originValidationMiddleware, authMiddleware, (req, res) => { } }); -const PORT = parseInt(process.env.SERVER_PORT || "6277", 10); +const PORT = parseInt( + process.env.SERVER_PORT || DEFAULT_MCP_PROXY_LISTEN_PORT, + 10, +); const HOST = process.env.HOST || "localhost"; const server = app.listen(PORT, HOST); @@ -543,7 +547,17 @@ server.on("listening", () => { // Display clickable URL with pre-filled token const clientPort = process.env.CLIENT_PORT || "6274"; const clientHost = process.env.HOST || "localhost"; - const clientUrl = `http://${clientHost}:${clientPort}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`; + + // Build URL with query parameters + const params = new URLSearchParams(); + params.set("MCP_PROXY_AUTH_TOKEN", sessionToken); + + // Add server port if it's not the default + if (PORT !== parseInt(DEFAULT_MCP_PROXY_LISTEN_PORT, 10)) { + params.set("MCP_PROXY_PORT", PORT.toString()); + } + + const clientUrl = `http://${clientHost}:${clientPort}/?${params.toString()}`; console.log( `\nšŸ”— Open inspector with token pre-filled:\n ${clientUrl}\n`, ); From 9e9419bf21df5d366e17cb0a96c224ba3e277813 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Thu, 26 Jun 2025 10:33:58 +0100 Subject: [PATCH 84/91] fix: ensure MCP_PROXY_PORT is included when auth is disabled Address PR feedback by restructuring getClientUrl to always include MCP_PROXY_PORT parameter when using non-default port, regardless of auth status. Also improved code clarity by using params.size check. --- client/bin/start.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/client/bin/start.js b/client/bin/start.js index 96556790..e5e32832 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -17,19 +17,14 @@ function getClientUrl(port, authDisabled, sessionToken, serverPort) { const host = process.env.HOST || "localhost"; const baseUrl = `http://${host}:${port}`; - if (authDisabled) { - return baseUrl; - } - const params = new URLSearchParams(); - params.set("MCP_PROXY_AUTH_TOKEN", sessionToken); - - // Add server port if it's not the default if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) { params.set("MCP_PROXY_PORT", serverPort); } - - return `${baseUrl}/?${params.toString()}`; + if (!authDisabled) { + params.set("MCP_PROXY_AUTH_TOKEN", sessionToken); + } + return params.size > 0 ? `${baseUrl}/?${params.toString()}` : baseUrl; } async function startDevServer(serverOptions) { From ae1aeb3c3ffc4feed9b83e02f4e22c3711a81c10 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 27 Jun 2025 13:08:29 +0100 Subject: [PATCH 85/91] fix: improve logging consistency between dev and prod client startup Refactored startProdClient to match startDevClient's logging pattern, ensuring consistent user feedback whether auto-open is enabled or disabled. Also ensures that we log full information on how to open the browser regardless of whether MCP_AUTO_OPEN_ENABLED=false. --- client/bin/start.js | 49 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/client/bin/start.js b/client/bin/start.js index e5e32832..8fa246cb 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -133,21 +133,21 @@ async function startDevClient(clientOptions) { echoOutput: true, }); - // Auto-open browser after vite starts - if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { - const url = getClientUrl( - CLIENT_PORT, - authDisabled, - sessionToken, - SERVER_PORT, - ); + const url = getClientUrl( + CLIENT_PORT, + authDisabled, + sessionToken, + SERVER_PORT, + ); - // Give vite time to start before opening browser - setTimeout(() => { + // Give vite time to start before opening or logging the URL + setTimeout(() => { + console.log(`\nšŸš€ MCP Inspector is up and running at:\n ${url}\n`); + if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { + console.log("🌐 Opening browser..."); open(url); - console.log(`\nšŸ”— Opening browser at: ${url}\n`); - }, 3000); - } + } + }, 3000); await new Promise((resolve) => { client.subscribe({ @@ -180,15 +180,20 @@ async function startProdClient(clientOptions) { "client.js", ); - // Only auto-open browser if not cancelled - if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && !cancelled) { - const url = getClientUrl( - CLIENT_PORT, - authDisabled, - sessionToken, - SERVER_PORT, - ); - open(url); + const url = getClientUrl( + CLIENT_PORT, + authDisabled, + sessionToken, + SERVER_PORT, + ); + + // Handle auto-open and logging + if (!cancelled) { + console.log(`\nšŸš€ MCP Inspector is up and running at:\n ${url}\n`); + if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { + console.log(`\n🌐 Opening browser...:\n`); + open(url); + } } await spawnPromise("node", [inspectorClientPath], { From 042e7a2aa79939fc2f677531b8d4180cca176c7c Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 27 Jun 2025 14:46:40 +0100 Subject: [PATCH 86/91] refactor: move browser auto-open logic to client process Simplifies the startup flow by consolidating browser opening in the client script rather than the start script for prod. We were duplicating a lot of logging, making it easy for logs to go out of sync - this is a proposal to consolidate: - server only logs info about itself - client only logs info about itself To reduce the number of places we print connection information to the user. --- client/bin/client.js | 10 +++++++--- client/bin/start.js | 15 +++++---------- server/src/index.ts | 22 ++-------------------- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/client/bin/client.js b/client/bin/client.js index e25ecb7c..2a7419e6 100755 --- a/client/bin/client.js +++ b/client/bin/client.js @@ -1,5 +1,6 @@ #!/usr/bin/env node +import open from "open"; import { join, dirname } from "path"; import { fileURLToPath } from "url"; import handler from "serve-handler"; @@ -42,9 +43,12 @@ const server = http.createServer((request, response) => { const port = parseInt(process.env.CLIENT_PORT || "6274", 10); const host = process.env.HOST || "localhost"; server.on("listening", () => { - console.log( - `šŸ” MCP Inspector is up and running at http://${host}:${port} šŸš€`, - ); + const url = process.env.INSPECTOR_URL || `http://${host}:${port}`; + console.log(`\nšŸš€ MCP Inspector is up and running at:\n ${url}\n`); + if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { + console.log(`🌐 Opening browser...`); + open(url); + } }); server.on("error", (err) => { if (err.message.includes(`EADDRINUSE`)) { diff --git a/client/bin/start.js b/client/bin/start.js index 8fa246cb..507026cc 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -187,17 +187,12 @@ async function startProdClient(clientOptions) { SERVER_PORT, ); - // Handle auto-open and logging - if (!cancelled) { - console.log(`\nšŸš€ MCP Inspector is up and running at:\n ${url}\n`); - if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") { - console.log(`\n🌐 Opening browser...:\n`); - open(url); - } - } - await spawnPromise("node", [inspectorClientPath], { - env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, + env: { + ...process.env, + CLIENT_PORT: CLIENT_PORT, + INSPECTOR_URL: url, + }, signal: abort.signal, echoOutput: true, }); diff --git a/server/src/index.ts b/server/src/index.ts index 3e02cad1..971cf158 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -539,27 +539,9 @@ const server = app.listen(PORT, HOST); server.on("listening", () => { console.log(`āš™ļø Proxy server listening on ${HOST}:${PORT}`); if (!authDisabled) { - console.log(`šŸ”‘ Session token: ${sessionToken}`); console.log( - `Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth`, - ); - - // Display clickable URL with pre-filled token - const clientPort = process.env.CLIENT_PORT || "6274"; - const clientHost = process.env.HOST || "localhost"; - - // Build URL with query parameters - const params = new URLSearchParams(); - params.set("MCP_PROXY_AUTH_TOKEN", sessionToken); - - // Add server port if it's not the default - if (PORT !== parseInt(DEFAULT_MCP_PROXY_LISTEN_PORT, 10)) { - params.set("MCP_PROXY_PORT", PORT.toString()); - } - - const clientUrl = `http://${clientHost}:${clientPort}/?${params.toString()}`; - console.log( - `\nšŸ”— Open inspector with token pre-filled:\n ${clientUrl}\n`, + `šŸ”‘ Session token: ${sessionToken}\n ` + + `Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth`, ); } else { console.log( From 1aea3374ff14b3bd0f50d2236cf9c44d5a362c0f Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 27 Jun 2025 17:40:22 +0100 Subject: [PATCH 87/91] refactor: use ES6 shorthand property syntax in start.js Replace explicit property assignments with shorthand syntax when property names match variable names (e.g., SERVER_PORT: SERVER_PORT becomes just SERVER_PORT). --- client/bin/start.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/bin/start.js b/client/bin/start.js index 507026cc..70ca046e 100755 --- a/client/bin/start.js +++ b/client/bin/start.js @@ -38,8 +38,8 @@ async function startDevServer(serverOptions) { cwd: resolve(__dirname, "../..", "server"), env: { ...process.env, - SERVER_PORT: SERVER_PORT, - CLIENT_PORT: CLIENT_PORT, + SERVER_PORT, + CLIENT_PORT, MCP_PROXY_TOKEN: sessionToken, MCP_ENV_VARS: JSON.stringify(envVars), }, @@ -97,8 +97,8 @@ async function startProdServer(serverOptions) { { env: { ...process.env, - SERVER_PORT: SERVER_PORT, - CLIENT_PORT: CLIENT_PORT, + SERVER_PORT, + CLIENT_PORT, MCP_PROXY_TOKEN: sessionToken, MCP_ENV_VARS: JSON.stringify(envVars), }, @@ -128,7 +128,7 @@ async function startDevClient(clientOptions) { const client = spawn(clientCommand, clientArgs, { cwd: resolve(__dirname, ".."), - env: { ...process.env, CLIENT_PORT: CLIENT_PORT }, + env: { ...process.env, CLIENT_PORT }, signal: abort.signal, echoOutput: true, }); @@ -190,7 +190,7 @@ async function startProdClient(clientOptions) { await spawnPromise("node", [inspectorClientPath], { env: { ...process.env, - CLIENT_PORT: CLIENT_PORT, + CLIENT_PORT, INSPECTOR_URL: url, }, signal: abort.signal, From 80082e127278e498e027c74fa6ff26d615a974e0 Mon Sep 17 00:00:00 2001 From: Baruch Odem Date: Sun, 29 Jun 2025 07:46:25 +0300 Subject: [PATCH 88/91] chore: update Node.js version requirement and adjust workflows to use package.json for node version --- .github/workflows/e2e_tests.yml | 6 ++++-- .github/workflows/main.yml | 4 ++-- package.json | 3 +++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index 2630a495..573672cc 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -21,8 +21,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 + id: setup_node with: - node-version: 18 + node-version-file: package.json + cache: npm # Cache Playwright browsers - name: Cache Playwright browsers @@ -69,7 +71,7 @@ jobs: job-summary: true icon-style: "emojis" custom-info: | - **Test Environment:** Ubuntu Latest, Node.js 18 + **Test Environment:** Ubuntu Latest, Node.js ${{ steps.setup_node.outputs.node-version }} **Browsers:** Chromium, Firefox šŸ“Š [View Detailed HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) (download artifacts) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 199e33a4..d01f7175 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version-file: .node-version + node-version-file: package.json cache: npm # Working around https://github.com/npm/cli/issues/4828 @@ -53,7 +53,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version-file: .node-version + node-version-file: package.json cache: npm registry-url: "https://registry.npmjs.org" diff --git a/package.json b/package.json index de02890d..722ca3d7 100644 --- a/package.json +++ b/package.json @@ -64,5 +64,8 @@ "prettier": "3.3.3", "rimraf": "^6.0.1", "typescript": "^5.4.2" + }, + "engines": { + "node": ">=22.0.0" } } From 0027e870cc6bd7bb2665cf92426a44c104abb3dc Mon Sep 17 00:00:00 2001 From: Baruch Odem Date: Tue, 1 Jul 2025 08:25:39 +0300 Subject: [PATCH 89/91] follow the README https://github.com/modelcontextprotocol/inspector/pull/318 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 722ca3d7..5d5fe52f 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,6 @@ "typescript": "^5.4.2" }, "engines": { - "node": ">=22.0.0" + "node": ">=22.7.5" } } From daf5f0af382bec502cc33cec87a1e1b4067f7781 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Tue, 1 Jul 2025 09:30:36 -0700 Subject: [PATCH 90/91] Full-width #root --- client/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/index.html b/client/index.html index 00f5600b..b3736a82 100644 --- a/client/index.html +++ b/client/index.html @@ -7,7 +7,7 @@ MCP Inspector -

+
From 0f2548e71d49a7a14eb844e264431456028fe9b9 Mon Sep 17 00:00:00 2001 From: Richard Michael Date: Tue, 1 Jul 2025 09:31:19 -0700 Subject: [PATCH 91/91] Remove unnecessary margin property --- client/src/App.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/src/App.css b/client/src/App.css index 5f47310f..0d669ffa 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -1,7 +1,3 @@ -#root { - margin: 0 auto; -} - .logo { height: 6em; padding: 1.5em;