fix types, eliminate client/server

This commit is contained in:
Ashwin Bhat
2024-10-11 08:34:28 -07:00
parent df8051b975
commit 50f86ebbfe
3 changed files with 16 additions and 43 deletions

View File

@@ -7,6 +7,8 @@ import {
ReadResourceResultSchema, ReadResourceResultSchema,
CallToolResultSchema, CallToolResultSchema,
ListPromptsResultSchema, ListPromptsResultSchema,
Tool,
ClientRequest,
} from "mcp-typescript/types.js"; } from "mcp-typescript/types.js";
import { useState } from "react"; import { useState } from "react";
import { import {
@@ -28,8 +30,9 @@ import RequestsTab from "./components/RequestsTabs";
import ResourcesTab, { Resource } from "./components/ResourcesTab"; import ResourcesTab, { Resource } from "./components/ResourcesTab";
import NotificationsTab from "./components/NotificationsTab"; import NotificationsTab from "./components/NotificationsTab";
import PromptsTab, { Prompt } from "./components/PromptsTab"; import PromptsTab, { Prompt } from "./components/PromptsTab";
import ToolsTab, { Tool as ToolType } from "./components/ToolsTab"; import ToolsTab from "./components/ToolsTab";
import History from "./components/History"; import History from "./components/History";
import { AnyZodObject } from "node_modules/zod/lib";
const App = () => { const App = () => {
const [connectionStatus, setConnectionStatus] = useState< const [connectionStatus, setConnectionStatus] = useState<
@@ -39,7 +42,7 @@ const App = () => {
const [resourceContent, setResourceContent] = useState<string>(""); const [resourceContent, setResourceContent] = useState<string>("");
const [prompts, setPrompts] = useState<Prompt[]>([]); const [prompts, setPrompts] = useState<Prompt[]>([]);
const [promptContent, setPromptContent] = useState<string>(""); const [promptContent, setPromptContent] = useState<string>("");
const [tools, setTools] = useState<ToolType[]>([]); const [tools, setTools] = useState<Tool[]>([]);
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>( const [command, setCommand] = useState<string>(
@@ -57,7 +60,7 @@ const App = () => {
null, null,
); );
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null); const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
const [selectedTool, setSelectedTool] = useState<ToolType | null>(null); const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
const pushHistory = (request: object, response: object) => { const pushHistory = (request: object, response: object) => {
setRequestHistory((prev) => [ setRequestHistory((prev) => [
@@ -66,10 +69,10 @@ const App = () => {
]); ]);
}; };
const makeRequest = async ( const makeRequest = async <T extends AnyZodObject>(
request: Parameters<Client["request"]>[0], request: ClientRequest,
schema: Parameters<Client["request"]>[1], schema: T,
): Promise<ReturnType<Client["request"]>> => { ) => {
if (!mcpClient) { if (!mcpClient) {
throw new Error("MCP client not connected"); throw new Error("MCP client not connected");
} }
@@ -114,9 +117,7 @@ const App = () => {
}, },
ListPromptsResultSchema, ListPromptsResultSchema,
); );
if (response.prompts) {
setPrompts(response.prompts); setPrompts(response.prompts);
}
}; };
const getPrompt = async (name: string, args: Record<string, string> = {}) => { const getPrompt = async (name: string, args: Record<string, string> = {}) => {
@@ -137,9 +138,7 @@ const App = () => {
}, },
ListToolsResultSchema, ListToolsResultSchema,
); );
if (response.tools) {
setTools(response.tools); setTools(response.tools);
}
}; };
const callTool = async (name: string, params: Record<string, unknown>) => { const callTool = async (name: string, params: Record<string, unknown>) => {

View File

@@ -3,19 +3,11 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Send, AlertCircle } from "lucide-react"; import { Send, AlertCircle } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Tool } from "mcp-typescript/types.js";
import { useState } from "react"; import { useState } from "react";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import ListPane from "./ListPane"; import ListPane from "./ListPane";
export type Tool = {
name: string;
description?: string | undefined;
inputSchema: {
type: string;
properties?: Record<string, { type: string; description: string }>;
};
};
const ToolsTab = ({ const ToolsTab = ({
tools, tools,
listTools, listTools,

View File

@@ -1,48 +1,32 @@
import cors from "cors"; import cors from "cors";
import { Server } from "mcp-typescript/server/index.js";
import { SSEServerTransport } from "mcp-typescript/server/sse.js"; import { SSEServerTransport } from "mcp-typescript/server/sse.js";
import express from "express"; import express from "express";
import { Client } from "mcp-typescript/client/index.js";
import { StdioClientTransport } from "mcp-typescript/client/stdio.js"; import { StdioClientTransport } from "mcp-typescript/client/stdio.js";
import mcpProxy from "./mcpProxy.js"; import mcpProxy from "./mcpProxy.js";
const app = express(); const app = express();
app.use(cors()); app.use(cors());
let servers: Server[] = []; let transports: SSEServerTransport[] = [];
app.get("/sse", async (req, res) => { app.get("/sse", async (req, res) => {
console.log("New SSE connection"); console.log("New SSE connection");
const command = decodeURIComponent(req.query.command as string); const command = decodeURIComponent(req.query.command as string);
const args = decodeURIComponent(req.query.args as string).split(","); const args = decodeURIComponent(req.query.args as string).split(",");
const mcpClient = new Client({ name: "MyApp", version: "1.0.0" });
const backingServerTransport = new StdioClientTransport(); const backingServerTransport = new StdioClientTransport();
await backingServerTransport.spawn({ command, args }); await backingServerTransport.spawn({ command, args });
await mcpClient.connect(backingServerTransport);
const webAppTransport = new SSEServerTransport("/message"); const webAppTransport = new SSEServerTransport("/message");
const server = new Server({ transports.push(webAppTransport);
name: "mcp-server-inspector",
version: "0.0.1",
});
servers.push(server);
server.onclose = async () => {
console.log("SSE connection closed");
servers = servers.filter((s) => s !== server);
await mcpClient.close();
};
await webAppTransport.connectSSE(req, res); await webAppTransport.connectSSE(req, res);
await server.connect(webAppTransport);
mcpProxy({ mcpProxy({
transportToClient: webAppTransport, transportToClient: webAppTransport,
transportToServer: backingServerTransport, transportToServer: backingServerTransport,
onerror: (error) => { onerror: (error) => {
console.error(error); console.error(error);
server.close();
}, },
}); });
}); });
@@ -50,9 +34,7 @@ app.get("/sse", async (req, res) => {
app.post("/message", async (req, res) => { app.post("/message", async (req, res) => {
console.log("Received message"); console.log("Received message");
const transport = servers const transport = transports.find((t) => true);
.map((s) => s.transport as SSEServerTransport)
.find((t) => true);
if (!transport) { if (!transport) {
res.status(404).send("Session not found"); res.status(404).send("Session not found");
return; return;