diff --git a/README.md b/README.md index 21b51a7..6239e31 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,12 @@ http://localhost:6274/?transport=streamable-http&serverUrl=http://localhost:8787 http://localhost:6274/?transport=stdio&serverCommand=npx&serverArgs=arg1%20arg2 ``` +You can also set initial config settings via query params, for example: + +``` +http://localhost:6274/?MCP_SERVER_REQUEST_TIMEOUT=10000&MCP_REQUEST_TIMEOUT_RESET_ON_PROGRESS=false&MCP_PROXY_FULL_ADDRESS=http://10.1.1.22:5577 +``` + Note that if both the query param and the corresponding localStorage item are set, the query param will take precedence. ### From this repository diff --git a/client/src/App.tsx b/client/src/App.tsx index 7e6a986..32bdcf3 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -49,7 +49,6 @@ import RootsTab from "./components/RootsTab"; import SamplingTab, { PendingRequest } from "./components/SamplingTab"; import Sidebar from "./components/Sidebar"; import ToolsTab from "./components/ToolsTab"; -import { DEFAULT_INSPECTOR_CONFIG } from "./lib/constants"; import { InspectorConfig } from "./lib/configurationTypes"; import { getMCPProxyAddress, @@ -57,6 +56,7 @@ import { getInitialTransportType, getInitialCommand, getInitialArgs, + initializeInspectorConfig, } from "./utils/configUtils"; const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1"; @@ -92,27 +92,9 @@ const App = () => { const [roots, setRoots] = useState([]); const [env, setEnv] = useState>({}); - const [config, setConfig] = useState(() => { - const savedConfig = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY); - if (savedConfig) { - // merge default config with saved config - const mergedConfig = { - ...DEFAULT_INSPECTOR_CONFIG, - ...JSON.parse(savedConfig), - } as InspectorConfig; - - // update description of keys to match the new description (in case of any updates to the default config description) - Object.entries(mergedConfig).forEach(([key, value]) => { - mergedConfig[key as keyof InspectorConfig] = { - ...value, - label: DEFAULT_INSPECTOR_CONFIG[key as keyof InspectorConfig].label, - }; - }); - - return mergedConfig; - } - return DEFAULT_INSPECTOR_CONFIG; - }); + const [config, setConfig] = useState(() => + initializeInspectorConfig(CONFIG_LOCAL_STORAGE_KEY), + ); const [bearerToken, setBearerToken] = useState(() => { return localStorage.getItem("lastBearerToken") || ""; }); diff --git a/client/src/utils/configUtils.ts b/client/src/utils/configUtils.ts index ef9bf38..ae404d6 100644 --- a/client/src/utils/configUtils.ts +++ b/client/src/utils/configUtils.ts @@ -1,5 +1,8 @@ import { InspectorConfig } from "@/lib/configurationTypes"; -import { DEFAULT_MCP_PROXY_LISTEN_PORT } from "@/lib/constants"; +import { + DEFAULT_MCP_PROXY_LISTEN_PORT, + DEFAULT_INSPECTOR_CONFIG, +} from "@/lib/constants"; export const getMCPProxyAddress = (config: InspectorConfig): string => { const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string; @@ -67,3 +70,57 @@ export const getInitialArgs = (): string => { if (param) return param; return localStorage.getItem("lastArgs") || ""; }; + +// Returns a map of config key -> value from query params if present +export const getConfigOverridesFromQueryParams = ( + defaultConfig: InspectorConfig, +): Partial => { + const url = new URL(window.location.href); + const overrides: Partial = {}; + for (const key of Object.keys(defaultConfig)) { + const param = url.searchParams.get(key); + if (param !== null) { + // Try to coerce to correct type based on default value + const defaultValue = defaultConfig[key as keyof InspectorConfig].value; + let value: string | number | boolean = param; + if (typeof defaultValue === "number") { + value = Number(param); + } else if (typeof defaultValue === "boolean") { + value = param === "true"; + } + overrides[key as keyof InspectorConfig] = { + ...defaultConfig[key as keyof InspectorConfig], + value, + }; + } + } + return overrides; +}; + +export const initializeInspectorConfig = ( + localStorageKey: string, +): InspectorConfig => { + const savedConfig = localStorage.getItem(localStorageKey); + let baseConfig: InspectorConfig; + if (savedConfig) { + // merge default config with saved config + const mergedConfig = { + ...DEFAULT_INSPECTOR_CONFIG, + ...JSON.parse(savedConfig), + } as InspectorConfig; + + // update description of keys to match the new description (in case of any updates to the default config description) + for (const [key, value] of Object.entries(mergedConfig)) { + mergedConfig[key as keyof InspectorConfig] = { + ...value, + label: DEFAULT_INSPECTOR_CONFIG[key as keyof InspectorConfig].label, + }; + } + baseConfig = mergedConfig; + } else { + baseConfig = DEFAULT_INSPECTOR_CONFIG; + } + // Apply query param overrides + const overrides = getConfigOverridesFromQueryParams(DEFAULT_INSPECTOR_CONFIG); + return { ...baseConfig, ...overrides }; +};