1- import { useState , useEffect } from "react" ;
1+ import { Client } from "mcp-typescript/client/index.js" ;
2+ import { SSEClientTransport } from "mcp-typescript/client/sse.js" ;
3+ import {
4+ ListResourcesResultSchema ,
5+ GetPromptResultSchema ,
6+ ListToolsResultSchema ,
7+ ReadResourceResultSchema ,
8+ CallToolResultSchema ,
9+ ListPromptsResultSchema ,
10+ Tool ,
11+ ClientRequest ,
12+ } from "mcp-typescript/types.js" ;
13+ import { useState } from "react" ;
214import {
315 Send ,
416 Bell ,
@@ -18,19 +30,19 @@ import RequestsTab from "./components/RequestsTabs";
1830import ResourcesTab , { Resource } from "./components/ResourcesTab" ;
1931import NotificationsTab from "./components/NotificationsTab" ;
2032import PromptsTab , { Prompt } from "./components/PromptsTab" ;
21- import ToolsTab , { Tool as ToolType } from "./components/ToolsTab" ;
33+ import ToolsTab from "./components/ToolsTab" ;
2234import History from "./components/History" ;
35+ import { AnyZodObject } from "node_modules/zod/lib" ;
2336
2437const App = ( ) => {
25- const [ socket , setSocket ] = useState < WebSocket | null > ( null ) ;
2638 const [ connectionStatus , setConnectionStatus ] = useState <
2739 "disconnected" | "connected" | "error"
2840 > ( "disconnected" ) ;
2941 const [ resources , setResources ] = useState < Resource [ ] > ( [ ] ) ;
3042 const [ resourceContent , setResourceContent ] = useState < string > ( "" ) ;
3143 const [ prompts , setPrompts ] = useState < Prompt [ ] > ( [ ] ) ;
3244 const [ promptContent , setPromptContent ] = useState < string > ( "" ) ;
33- const [ tools , setTools ] = useState < ToolType [ ] > ( [ ] ) ;
45+ const [ tools , setTools ] = useState < Tool [ ] > ( [ ] ) ;
3446 const [ toolResult , setToolResult ] = useState < string > ( "" ) ;
3547 const [ error , setError ] = useState < string | null > ( null ) ;
3648 const [ command , setCommand ] = useState < string > (
@@ -39,121 +51,128 @@ const App = () => {
3951 const [ args , setArgs ] = useState < string > (
4052 "/Users/ashwin/code/example-servers/build/everything/index.js" ,
4153 ) ;
42- const [ mcpConnected , setMcpConnected ] = useState < boolean > ( false ) ;
4354 const [ requestHistory , setRequestHistory ] = useState <
44- Array < { request : string ; response : string | null } >
55+ { request : string ; response : string } [ ]
4556 > ( [ ] ) ;
57+ const [ mcpClient , setMcpClient ] = useState < Client | null > ( null ) ;
4658
47- useEffect ( ( ) => {
48- const ws = new WebSocket ( "ws://localhost:3000" ) ;
49-
50- ws . onopen = ( ) => {
51- console . log ( "Connected to WebSocket server" ) ;
52- setConnectionStatus ( "connected" ) ;
53- setSocket ( ws ) ;
54- } ;
55-
56- ws . onmessage = ( event ) => {
57- const message = JSON . parse ( event . data ) ;
58- console . log ( "Received message:" , message ) ;
59- if ( message . type === "resources" ) {
60- setResources ( message . data . resources ) ;
61- setError ( null ) ;
62- } else if ( message . type === "resource" ) {
63- setResourceContent ( JSON . stringify ( message . data , null , 2 ) ) ;
64- setError ( null ) ;
65- } else if ( message . type === "prompts" ) {
66- setPrompts ( message . data . prompts ) ;
67- setError ( null ) ;
68- } else if ( message . type === "prompt" ) {
69- setPromptContent ( JSON . stringify ( message . data , null , 2 ) ) ;
70- setError ( null ) ;
71- } else if ( message . type === "tools" ) {
72- setTools ( message . data . tools ) ;
73- setError ( null ) ;
74- } else if ( message . type === "toolResult" ) {
75- setToolResult ( JSON . stringify ( message . data , null , 2 ) ) ;
76- setError ( null ) ;
77- } else if ( message . type === "error" ) {
78- setError ( message . message ) ;
79- } else if ( message . type === "connected" ) {
80- setMcpConnected ( true ) ;
81- }
82-
83- updateRequestHistory ( message ) ;
84- } ;
85-
86- ws . onerror = ( ) => {
87- setConnectionStatus ( "error" ) ;
88- } ;
59+ const [ selectedResource , setSelectedResource ] = useState < Resource | null > (
60+ null ,
61+ ) ;
62+ const [ selectedPrompt , setSelectedPrompt ] = useState < Prompt | null > ( null ) ;
63+ const [ selectedTool , setSelectedTool ] = useState < Tool | null > ( null ) ;
8964
90- ws . onclose = ( ) => {
91- setConnectionStatus ( "disconnected" ) ;
92- setMcpConnected ( false ) ;
93- } ;
65+ const pushHistory = ( request : object , response : object ) => {
66+ setRequestHistory ( ( prev ) => [
67+ ...prev ,
68+ { request : JSON . stringify ( request ) , response : JSON . stringify ( response ) } ,
69+ ] ) ;
70+ } ;
9471
95- return ( ) => ws . close ( ) ;
96- } , [ ] ) ;
72+ const makeRequest = async < T extends AnyZodObject > (
73+ request : ClientRequest ,
74+ schema : T ,
75+ ) => {
76+ if ( ! mcpClient ) {
77+ throw new Error ( "MCP client not connected" ) ;
78+ }
9779
98- const updateRequestHistory = ( response : unknown ) => {
99- setRequestHistory ( ( prev ) => {
100- const lastRequest = prev [ prev . length - 1 ] ;
101- if ( lastRequest && lastRequest . response === null ) {
102- const updatedHistory = [ ...prev ] ;
103- updatedHistory [ updatedHistory . length - 1 ] = {
104- ...lastRequest ,
105- response : JSON . stringify ( response ) ,
106- } ;
107- return updatedHistory ;
108- }
109- return prev ;
110- } ) ;
80+ try {
81+ const response = await mcpClient . request ( request , schema ) ;
82+ pushHistory ( request , response ) ;
83+ return response ;
84+ } catch ( e : unknown ) {
85+ setError ( ( e as Error ) . message ) ;
86+ throw e ;
87+ }
11188 } ;
11289
113- const sendWebSocketMessage = ( message : object ) => {
114- if ( socket ) {
115- console . log ( "Sending WebSocket message:" , message ) ;
116- socket . send ( JSON . stringify ( message ) ) ;
117- setRequestHistory ( ( prev ) => [
118- ...prev ,
119- { request : JSON . stringify ( message ) , response : null } ,
120- ] ) ;
90+ const listResources = async ( ) => {
91+ const response = await makeRequest (
92+ {
93+ method : "resources/list" as const ,
94+ } ,
95+ ListResourcesResultSchema ,
96+ ) ;
97+ if ( response . resources ) {
98+ setResources ( response . resources ) ;
12199 }
122100 } ;
123101
124- const [ selectedResource , setSelectedResource ] = useState < Resource | null > (
125- null ,
126- ) ;
127- const [ selectedPrompt , setSelectedPrompt ] = useState < Prompt | null > ( null ) ;
128- const [ selectedTool , setSelectedTool ] = useState < ToolType | null > ( null ) ;
129-
130- const listResources = ( ) => {
131- sendWebSocketMessage ( { type : "listResources" } ) ;
102+ const readResource = async ( uri : string ) => {
103+ const response = await makeRequest (
104+ {
105+ method : "resources/read" as const ,
106+ params : { uri } ,
107+ } ,
108+ ReadResourceResultSchema ,
109+ ) ;
110+ setResourceContent ( JSON . stringify ( response , null , 2 ) ) ;
132111 } ;
133112
134- const readResource = ( uri : string ) => {
135- sendWebSocketMessage ( { type : "readResource" , uri } ) ;
113+ const listPrompts = async ( ) => {
114+ const response = await makeRequest (
115+ {
116+ method : "prompts/list" as const ,
117+ } ,
118+ ListPromptsResultSchema ,
119+ ) ;
120+ setPrompts ( response . prompts ) ;
136121 } ;
137122
138- const listPrompts = ( ) => {
139- sendWebSocketMessage ( { type : "listPrompts" } ) ;
123+ const getPrompt = async ( name : string , args : Record < string , string > = { } ) => {
124+ const response = await makeRequest (
125+ {
126+ method : "prompts/get" as const ,
127+ params : { name, arguments : args } ,
128+ } ,
129+ GetPromptResultSchema ,
130+ ) ;
131+ setPromptContent ( JSON . stringify ( response , null , 2 ) ) ;
140132 } ;
141133
142- const getPrompt = ( name : string , args : Record < string , unknown > = { } ) => {
143- sendWebSocketMessage ( { type : "getPrompt" , name, args } ) ;
134+ const listTools = async ( ) => {
135+ const response = await makeRequest (
136+ {
137+ method : "tools/list" as const ,
138+ } ,
139+ ListToolsResultSchema ,
140+ ) ;
141+ setTools ( response . tools ) ;
144142 } ;
145143
146- const listTools = ( ) => {
147- sendWebSocketMessage ( { type : "listTools" } ) ;
144+ const callTool = async ( name : string , params : Record < string , unknown > ) => {
145+ const response = await makeRequest (
146+ {
147+ method : "tools/call" as const ,
148+ params : { name, arguments : params } ,
149+ } ,
150+ CallToolResultSchema ,
151+ ) ;
152+ setToolResult ( JSON . stringify ( response . toolResult , null , 2 ) ) ;
148153 } ;
149154
150- const callTool = ( name : string , params : Record < string , unknown > ) => {
151- sendWebSocketMessage ( { type : "callTool" , name, params } ) ;
152- } ;
155+ const connectMcpServer = async ( ) => {
156+ try {
157+ const client = new Client ( {
158+ name : "mcp-inspector" ,
159+ version : "0.0.1" ,
160+ } ) ;
161+
162+ const clientTransport = new SSEClientTransport ( ) ;
163+ const url = new URL ( "http://localhost:3000/sse" ) ;
164+ url . searchParams . append ( "command" , encodeURIComponent ( command ) ) ;
165+ url . searchParams . append ( "args" , encodeURIComponent ( args ) ) ;
166+ await clientTransport . connect ( url ) ;
167+
168+ await client . connect ( clientTransport ) ;
153169
154- const connectMcpServer = ( ) => {
155- const argsArray = args . split ( " " ) . filter ( ( arg ) => arg . trim ( ) !== "" ) ;
156- sendWebSocketMessage ( { type : "connect" , command, args : argsArray } ) ;
170+ setMcpClient ( client ) ;
171+ setConnectionStatus ( "connected" ) ;
172+ } catch ( e ) {
173+ console . error ( e ) ;
174+ setConnectionStatus ( "error" ) ;
175+ }
157176 } ;
158177
159178 return (
@@ -182,7 +201,7 @@ const App = () => {
182201 </ Button >
183202 </ div >
184203 </ div >
185- { mcpConnected ? (
204+ { mcpClient ? (
186205 < Tabs defaultValue = "resources" className = "w-full p-4" >
187206 < TabsList className = "mb-4 p-0" >
188207 < TabsTrigger value = "resources" >
0 commit comments