Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c2be8d139 | ||
|
|
97d469911e | ||
|
|
11b891c6ca |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@modelcontextprotocol/inspector-client",
|
"name": "@modelcontextprotocol/inspector-client",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Client-side application for the Model Context Protocol inspector",
|
"description": "Client-side application for the Model Context Protocol inspector",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|||||||
import {
|
import {
|
||||||
Notification,
|
Notification,
|
||||||
StdErrNotification,
|
StdErrNotification,
|
||||||
StdErrNotificationSchema
|
StdErrNotificationSchema,
|
||||||
} from "./lib/notificationTypes";
|
} from "./lib/notificationTypes";
|
||||||
|
|
||||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
@@ -54,7 +54,6 @@ 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 useDarkModeSync from "./lib/useDarkModeSync";
|
|
||||||
|
|
||||||
const DEFAULT_REQUEST_TIMEOUT_MSEC = 10000;
|
const DEFAULT_REQUEST_TIMEOUT_MSEC = 10000;
|
||||||
|
|
||||||
@@ -144,8 +143,6 @@ const App = () => {
|
|||||||
const dragStartY = useRef<number>(0);
|
const dragStartY = useRef<number>(0);
|
||||||
const dragStartHeight = useRef<number>(0);
|
const dragStartHeight = useRef<number>(0);
|
||||||
|
|
||||||
useDarkModeSync();
|
|
||||||
|
|
||||||
const handleDragStart = useCallback(
|
const handleDragStart = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { Play, ChevronDown, ChevronRight, Settings } from "lucide-react";
|
import { Play, ChevronDown, ChevronRight } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +12,8 @@ import {
|
|||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { StdErrNotification } from "@/lib/notificationTypes";
|
import { StdErrNotification } from "@/lib/notificationTypes";
|
||||||
|
|
||||||
|
import useTheme from "../lib/useTheme";
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
connectionStatus: "disconnected" | "connected" | "error";
|
connectionStatus: "disconnected" | "connected" | "error";
|
||||||
transportType: "stdio" | "sse";
|
transportType: "stdio" | "sse";
|
||||||
@@ -43,13 +45,15 @@ const Sidebar = ({
|
|||||||
onConnect,
|
onConnect,
|
||||||
stdErrNotifications,
|
stdErrNotifications,
|
||||||
}: SidebarProps) => {
|
}: SidebarProps) => {
|
||||||
|
const [theme, setTheme] = useTheme();
|
||||||
const [showEnvVars, setShowEnvVars] = useState(false);
|
const [showEnvVars, setShowEnvVars] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
|
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
|
||||||
<div className="flex items-center p-4 border-b border-gray-200">
|
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
||||||
<Settings className="w-6 h-6 text-gray-500" />
|
<div className="flex items-center">
|
||||||
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4 flex-1 overflow-auto">
|
<div className="p-4 flex-1 overflow-auto">
|
||||||
@@ -212,6 +216,25 @@ const Sidebar = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-4 border-t">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Select
|
||||||
|
value={theme}
|
||||||
|
onValueChange={(value: string) =>
|
||||||
|
setTheme(value as "system" | "light" | "dark")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[120px]" id="theme-select">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="system">System</SelectItem>
|
||||||
|
<SelectItem value="light">Light</SelectItem>
|
||||||
|
<SelectItem value="dark">Dark</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
// Listen for changes to the user's preferred color scheme
|
|
||||||
const useDarkModeSync = () => {
|
|
||||||
useEffect(() => {
|
|
||||||
const darkModeMediaQuery = window.matchMedia(
|
|
||||||
"(prefers-color-scheme: dark)",
|
|
||||||
);
|
|
||||||
const handleDarkModeChange = (e: MediaQueryListEvent) => {
|
|
||||||
if (e.matches) {
|
|
||||||
document.documentElement.classList.add("dark");
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove("dark");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (darkModeMediaQuery.matches) {
|
|
||||||
document.documentElement.classList.add("dark");
|
|
||||||
}
|
|
||||||
|
|
||||||
darkModeMediaQuery.addEventListener("change", handleDarkModeChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
darkModeMediaQuery.removeEventListener("change", handleDarkModeChange);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useDarkModeSync;
|
|
||||||
51
client/src/lib/useTheme.ts
Normal file
51
client/src/lib/useTheme.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
type Theme = "light" | "dark" | "system";
|
||||||
|
|
||||||
|
const useTheme = (): [Theme, (mode: Theme) => void] => {
|
||||||
|
const [theme, setTheme] = useState<Theme>(() => {
|
||||||
|
const savedTheme = localStorage.getItem("theme") as Theme;
|
||||||
|
return savedTheme || "system";
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const darkModeMediaQuery = window.matchMedia(
|
||||||
|
"(prefers-color-scheme: dark)",
|
||||||
|
);
|
||||||
|
const handleDarkModeChange = (e: MediaQueryListEvent) => {
|
||||||
|
if (theme === "system") {
|
||||||
|
updateDocumentTheme(e.matches ? "dark" : "light");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateDocumentTheme = (newTheme: "light" | "dark") => {
|
||||||
|
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set initial theme based on current mode
|
||||||
|
if (theme === "system") {
|
||||||
|
updateDocumentTheme(darkModeMediaQuery.matches ? "dark" : "light");
|
||||||
|
} else {
|
||||||
|
updateDocumentTheme(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
darkModeMediaQuery.addEventListener("change", handleDarkModeChange);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
darkModeMediaQuery.removeEventListener("change", handleDarkModeChange);
|
||||||
|
};
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
theme,
|
||||||
|
useCallback((newTheme: Theme) => {
|
||||||
|
setTheme(newTheme);
|
||||||
|
localStorage.setItem("theme", newTheme);
|
||||||
|
if (newTheme !== "system") {
|
||||||
|
document.documentElement.classList.toggle("dark", newTheme === "dark");
|
||||||
|
}
|
||||||
|
}, []),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTheme;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@modelcontextprotocol/inspector",
|
"name": "@modelcontextprotocol/inspector",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Model Context Protocol inspector",
|
"description": "Model Context Protocol inspector",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@modelcontextprotocol/inspector-server",
|
"name": "@modelcontextprotocol/inspector-server",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Server-side application for the Model Context Protocol inspector",
|
"description": "Server-side application for the Model Context Protocol inspector",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Anthropic, PBC (https://anthropic.com)",
|
"author": "Anthropic, PBC (https://anthropic.com)",
|
||||||
|
|||||||
Reference in New Issue
Block a user