add ability to connect manually
This commit is contained in:
@@ -6,8 +6,11 @@ import {
|
|||||||
Files,
|
Files,
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
Hammer,
|
Hammer,
|
||||||
|
Play,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
import ConsoleTab from "./components/ConsoleTab";
|
import ConsoleTab from "./components/ConsoleTab";
|
||||||
import Sidebar from "./components/Sidebar";
|
import Sidebar from "./components/Sidebar";
|
||||||
@@ -29,6 +32,13 @@ const App = () => {
|
|||||||
const [tools, setTools] = useState<ToolType[]>([]);
|
const [tools, setTools] = useState<ToolType[]>([]);
|
||||||
const [toolResult, setToolResult] = useState<string>("");
|
const [toolResult, setToolResult] = useState<string>("");
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [command, setCommand] = useState<string>(
|
||||||
|
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node",
|
||||||
|
);
|
||||||
|
const [args, setArgs] = useState<string>(
|
||||||
|
"/Users/ashwin/code/example-servers/build/everything/index.js",
|
||||||
|
);
|
||||||
|
const [mcpConnected, setMcpConnected] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ws = new WebSocket("ws://localhost:3000");
|
const ws = new WebSocket("ws://localhost:3000");
|
||||||
@@ -62,6 +72,8 @@ const App = () => {
|
|||||||
setError(null);
|
setError(null);
|
||||||
} else if (message.type === "error") {
|
} else if (message.type === "error") {
|
||||||
setError(message.message);
|
setError(message.message);
|
||||||
|
} else if (message.type === "connected") {
|
||||||
|
setMcpConnected(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,6 +83,7 @@ const App = () => {
|
|||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
setConnectionStatus("disconnected");
|
setConnectionStatus("disconnected");
|
||||||
|
setMcpConnected(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => ws.close();
|
return () => ws.close();
|
||||||
@@ -113,73 +126,105 @@ const App = () => {
|
|||||||
sendWebSocketMessage({ type: "callTool", name, params });
|
sendWebSocketMessage({ type: "callTool", name, params });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const connectMcpServer = () => {
|
||||||
|
const argsArray = args.split(" ").filter((arg) => arg.trim() !== "");
|
||||||
|
sendWebSocketMessage({ type: "connect", command, args: argsArray });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-gray-100">
|
<div className="flex h-screen bg-gray-100">
|
||||||
<Sidebar connectionStatus={connectionStatus} />
|
<Sidebar connectionStatus={connectionStatus} />
|
||||||
<div className="flex-1 flex flex-col overflow-hidden">
|
<div className="flex-1 flex flex-col overflow-hidden">
|
||||||
<h1 className="text-2xl font-bold p-4">MCP Inspector</h1>
|
<h1 className="text-2xl font-bold p-4">MCP Inspector</h1>
|
||||||
<div className="flex-1 overflow-auto">
|
<div className="flex-1 overflow-auto">
|
||||||
<Tabs defaultValue="requests" className="w-full p-4">
|
<div className="p-4 bg-white shadow-md m-4 rounded-md">
|
||||||
<TabsList className="mb-4">
|
<h2 className="text-lg font-semibold mb-2">Connect MCP Server</h2>
|
||||||
<TabsTrigger value="resources">
|
<div className="flex space-x-2 mb-2">
|
||||||
<Files className="w-4 h-4 mr-2" />
|
<Input
|
||||||
Resources
|
placeholder="Command"
|
||||||
</TabsTrigger>
|
value={command}
|
||||||
<TabsTrigger value="prompts">
|
onChange={(e) => setCommand(e.target.value)}
|
||||||
<MessageSquare className="w-4 h-4 mr-2" />
|
|
||||||
Prompts
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="requests" disabled>
|
|
||||||
<Send className="w-4 h-4 mr-2" />
|
|
||||||
Requests
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="notifications" disabled>
|
|
||||||
<Bell className="w-4 h-4 mr-2" />
|
|
||||||
Notifications
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="tools" disabled>
|
|
||||||
<Hammer className="w-4 h-4 mr-2" />
|
|
||||||
Tools
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="console" disabled>
|
|
||||||
<Terminal className="w-4 h-4 mr-2" />
|
|
||||||
Console
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<div className="w-full">
|
|
||||||
<RequestsTab />
|
|
||||||
<ResourcesTab
|
|
||||||
resources={resources}
|
|
||||||
listResources={listResources}
|
|
||||||
readResource={readResource}
|
|
||||||
selectedResource={selectedResource}
|
|
||||||
setSelectedResource={setSelectedResource}
|
|
||||||
resourceContent={resourceContent}
|
|
||||||
error={error}
|
|
||||||
/>
|
/>
|
||||||
<NotificationsTab />
|
<Input
|
||||||
<PromptsTab
|
placeholder="Arguments (space-separated)"
|
||||||
prompts={prompts}
|
value={args}
|
||||||
listPrompts={listPrompts}
|
onChange={(e) => setArgs(e.target.value)}
|
||||||
getPrompt={getPrompt}
|
|
||||||
selectedPrompt={selectedPrompt}
|
|
||||||
setSelectedPrompt={setSelectedPrompt}
|
|
||||||
promptContent={promptContent}
|
|
||||||
error={error}
|
|
||||||
/>
|
/>
|
||||||
<ToolsTab
|
<Button onClick={connectMcpServer}>
|
||||||
tools={tools}
|
<Play className="w-4 h-4 mr-2" />
|
||||||
listTools={listTools}
|
Connect
|
||||||
callTool={callTool}
|
</Button>
|
||||||
selectedTool={selectedTool}
|
|
||||||
setSelectedTool={setSelectedTool}
|
|
||||||
toolResult={toolResult}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
<ConsoleTab />
|
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</div>
|
||||||
|
{mcpConnected ? (
|
||||||
|
<Tabs defaultValue="resources" className="w-full p-4">
|
||||||
|
<TabsList className="mb-4 p-0">
|
||||||
|
<TabsTrigger value="resources">
|
||||||
|
<Files className="w-4 h-4 mr-2" />
|
||||||
|
Resources
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="prompts">
|
||||||
|
<MessageSquare className="w-4 h-4 mr-2" />
|
||||||
|
Prompts
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="requests" disabled>
|
||||||
|
<Send className="w-4 h-4 mr-2" />
|
||||||
|
Requests
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="notifications" disabled>
|
||||||
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
|
Notifications
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="tools" disabled>
|
||||||
|
<Hammer className="w-4 h-4 mr-2" />
|
||||||
|
Tools
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="console" disabled>
|
||||||
|
<Terminal className="w-4 h-4 mr-2" />
|
||||||
|
Console
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<div className="w-full">
|
||||||
|
<ResourcesTab
|
||||||
|
resources={resources}
|
||||||
|
listResources={listResources}
|
||||||
|
readResource={readResource}
|
||||||
|
selectedResource={selectedResource}
|
||||||
|
setSelectedResource={setSelectedResource}
|
||||||
|
resourceContent={resourceContent}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<NotificationsTab />
|
||||||
|
<PromptsTab
|
||||||
|
prompts={prompts}
|
||||||
|
listPrompts={listPrompts}
|
||||||
|
getPrompt={getPrompt}
|
||||||
|
selectedPrompt={selectedPrompt}
|
||||||
|
setSelectedPrompt={setSelectedPrompt}
|
||||||
|
promptContent={promptContent}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<RequestsTab />
|
||||||
|
<ToolsTab
|
||||||
|
tools={tools}
|
||||||
|
listTools={listTools}
|
||||||
|
callTool={callTool}
|
||||||
|
selectedTool={selectedTool}
|
||||||
|
setSelectedTool={setSelectedTool}
|
||||||
|
toolResult={toolResult}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<ConsoleTab />
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center h-full">
|
||||||
|
<p className="text-lg text-gray-500">
|
||||||
|
Connect to an MCP server to start inspecting
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,18 +7,25 @@ const app = express();
|
|||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const wss = new WebSocketServer({ server });
|
const wss = new WebSocketServer({ server });
|
||||||
|
|
||||||
const mcpClient = new McpClient("MyApp", "1.0.0");
|
let mcpClient: McpClient | null = null;
|
||||||
await mcpClient.connectStdio(
|
|
||||||
"/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node",
|
|
||||||
["/Users/ashwin/code/example-servers/build/everything/index.js"],
|
|
||||||
);
|
|
||||||
|
|
||||||
wss.on("connection", (ws: WebSocket) => {
|
wss.on("connection", (ws: WebSocket) => {
|
||||||
ws.on("message", async (message: string) => {
|
ws.on("message", async (message: string) => {
|
||||||
try {
|
try {
|
||||||
const command = JSON.parse(message);
|
const command = JSON.parse(message);
|
||||||
|
|
||||||
if (command.type === "listResources") {
|
if (command.type === "connect" && command.command && command.args) {
|
||||||
|
mcpClient = new McpClient("MyApp", "1.0.0");
|
||||||
|
await mcpClient.connectStdio(command.command, command.args);
|
||||||
|
ws.send(JSON.stringify({ type: "connected" }));
|
||||||
|
} else if (!mcpClient) {
|
||||||
|
ws.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: "error",
|
||||||
|
message: "Not connected to MCP server",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else if (command.type === "listResources") {
|
||||||
const resources = await mcpClient.listResources();
|
const resources = await mcpClient.listResources();
|
||||||
ws.send(JSON.stringify({ type: "resources", data: resources }));
|
ws.send(JSON.stringify({ type: "resources", data: resources }));
|
||||||
} else if (command.type === "readResource" && command.uri) {
|
} else if (command.type === "readResource" && command.uri) {
|
||||||
@@ -58,6 +65,8 @@ server.listen(PORT, () => {
|
|||||||
|
|
||||||
// Close the client when the server is shutting down
|
// Close the client when the server is shutting down
|
||||||
process.on("SIGINT", async () => {
|
process.on("SIGINT", async () => {
|
||||||
await mcpClient.close();
|
if (mcpClient) {
|
||||||
|
await mcpClient.close();
|
||||||
|
}
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user