Merge pull request #333 from kentcdodds/patch-1
feat(client): add search param configuration
This commit is contained in:
16
README.md
16
README.md
@@ -93,6 +93,22 @@ Example server configuration file:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also set the initial `transport` type, `serverUrl`, `serverCommand`, and `serverArgs` via query params, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:6274/?transport=sse&serverUrl=http://localhost:8787/sse
|
||||||
|
http://localhost:6274/?transport=streamable-http&serverUrl=http://localhost:8787/mcp
|
||||||
|
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
|
### From this repository
|
||||||
|
|
||||||
If you're working on the inspector itself:
|
If you're working on the inspector itself:
|
||||||
|
|||||||
@@ -49,9 +49,15 @@ import RootsTab from "./components/RootsTab";
|
|||||||
import SamplingTab, { PendingRequest } from "./components/SamplingTab";
|
import SamplingTab, { PendingRequest } from "./components/SamplingTab";
|
||||||
import Sidebar from "./components/Sidebar";
|
import Sidebar from "./components/Sidebar";
|
||||||
import ToolsTab from "./components/ToolsTab";
|
import ToolsTab from "./components/ToolsTab";
|
||||||
import { DEFAULT_INSPECTOR_CONFIG } from "./lib/constants";
|
|
||||||
import { InspectorConfig } from "./lib/configurationTypes";
|
import { InspectorConfig } from "./lib/configurationTypes";
|
||||||
import { getMCPProxyAddress } from "./utils/configUtils";
|
import {
|
||||||
|
getMCPProxyAddress,
|
||||||
|
getInitialSseUrl,
|
||||||
|
getInitialTransportType,
|
||||||
|
getInitialCommand,
|
||||||
|
getInitialArgs,
|
||||||
|
initializeInspectorConfig,
|
||||||
|
} from "./utils/configUtils";
|
||||||
|
|
||||||
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
const CONFIG_LOCAL_STORAGE_KEY = "inspectorConfig_v1";
|
||||||
|
|
||||||
@@ -71,26 +77,13 @@ const App = () => {
|
|||||||
prompts: null,
|
prompts: null,
|
||||||
tools: null,
|
tools: null,
|
||||||
});
|
});
|
||||||
const [command, setCommand] = useState<string>(() => {
|
const [command, setCommand] = useState<string>(getInitialCommand);
|
||||||
return localStorage.getItem("lastCommand") || "mcp-server-everything";
|
const [args, setArgs] = useState<string>(getInitialArgs);
|
||||||
});
|
|
||||||
const [args, setArgs] = useState<string>(() => {
|
|
||||||
return localStorage.getItem("lastArgs") || "";
|
|
||||||
});
|
|
||||||
|
|
||||||
const [sseUrl, setSseUrl] = useState<string>(() => {
|
const [sseUrl, setSseUrl] = useState<string>(getInitialSseUrl);
|
||||||
return localStorage.getItem("lastSseUrl") || "http://localhost:3001/sse";
|
|
||||||
});
|
|
||||||
const [transportType, setTransportType] = useState<
|
const [transportType, setTransportType] = useState<
|
||||||
"stdio" | "sse" | "streamable-http"
|
"stdio" | "sse" | "streamable-http"
|
||||||
>(() => {
|
>(getInitialTransportType);
|
||||||
return (
|
|
||||||
(localStorage.getItem("lastTransportType") as
|
|
||||||
| "stdio"
|
|
||||||
| "sse"
|
|
||||||
| "streamable-http") || "stdio"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const [logLevel, setLogLevel] = useState<LoggingLevel>("debug");
|
const [logLevel, setLogLevel] = useState<LoggingLevel>("debug");
|
||||||
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
|
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
|
||||||
const [stdErrNotifications, setStdErrNotifications] = useState<
|
const [stdErrNotifications, setStdErrNotifications] = useState<
|
||||||
@@ -99,27 +92,9 @@ const App = () => {
|
|||||||
const [roots, setRoots] = useState<Root[]>([]);
|
const [roots, setRoots] = useState<Root[]>([]);
|
||||||
const [env, setEnv] = useState<Record<string, string>>({});
|
const [env, setEnv] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
const [config, setConfig] = useState<InspectorConfig>(() => {
|
const [config, setConfig] = useState<InspectorConfig>(() =>
|
||||||
const savedConfig = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY);
|
initializeInspectorConfig(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 [bearerToken, setBearerToken] = useState<string>(() => {
|
const [bearerToken, setBearerToken] = useState<string>(() => {
|
||||||
return localStorage.getItem("lastBearerToken") || "";
|
return localStorage.getItem("lastBearerToken") || "";
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { InspectorConfig } from "@/lib/configurationTypes";
|
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 => {
|
export const getMCPProxyAddress = (config: InspectorConfig): string => {
|
||||||
const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string;
|
const proxyFullAddress = config.MCP_PROXY_FULL_ADDRESS.value as string;
|
||||||
@@ -24,3 +27,100 @@ export const getMCPServerRequestMaxTotalTimeout = (
|
|||||||
): number => {
|
): number => {
|
||||||
return config.MCP_REQUEST_MAX_TOTAL_TIMEOUT.value as number;
|
return config.MCP_REQUEST_MAX_TOTAL_TIMEOUT.value as number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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"
|
||||||
|
| "streamable-http" => {
|
||||||
|
const param = getSearchParam("transport");
|
||||||
|
if (param === "stdio" || param === "sse" || param === "streamable-http") {
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(localStorage.getItem("lastTransportType") as
|
||||||
|
| "stdio"
|
||||||
|
| "sse"
|
||||||
|
| "streamable-http") || "stdio"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInitialSseUrl = (): string => {
|
||||||
|
const param = getSearchParam("serverUrl");
|
||||||
|
if (param) return param;
|
||||||
|
return localStorage.getItem("lastSseUrl") || "http://localhost:3001/sse";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInitialCommand = (): string => {
|
||||||
|
const param = getSearchParam("serverCommand");
|
||||||
|
if (param) return param;
|
||||||
|
return localStorage.getItem("lastCommand") || "mcp-server-everything";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInitialArgs = (): string => {
|
||||||
|
const param = getSearchParam("serverArgs");
|
||||||
|
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<InspectorConfig> => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const overrides: Partial<InspectorConfig> = {};
|
||||||
|
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 };
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user