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" ;
2
14
import {
3
15
Send ,
4
16
Bell ,
@@ -18,19 +30,19 @@ import RequestsTab from "./components/RequestsTabs";
18
30
import ResourcesTab , { Resource } from "./components/ResourcesTab" ;
19
31
import NotificationsTab from "./components/NotificationsTab" ;
20
32
import PromptsTab , { Prompt } from "./components/PromptsTab" ;
21
- import ToolsTab , { Tool as ToolType } from "./components/ToolsTab" ;
33
+ import ToolsTab from "./components/ToolsTab" ;
22
34
import History from "./components/History" ;
35
+ import { AnyZodObject } from "node_modules/zod/lib" ;
23
36
24
37
const App = ( ) => {
25
- const [ socket , setSocket ] = useState < WebSocket | null > ( null ) ;
26
38
const [ connectionStatus , setConnectionStatus ] = useState <
27
39
"disconnected" | "connected" | "error"
28
40
> ( "disconnected" ) ;
29
41
const [ resources , setResources ] = useState < Resource [ ] > ( [ ] ) ;
30
42
const [ resourceContent , setResourceContent ] = useState < string > ( "" ) ;
31
43
const [ prompts , setPrompts ] = useState < Prompt [ ] > ( [ ] ) ;
32
44
const [ promptContent , setPromptContent ] = useState < string > ( "" ) ;
33
- const [ tools , setTools ] = useState < ToolType [ ] > ( [ ] ) ;
45
+ const [ tools , setTools ] = useState < Tool [ ] > ( [ ] ) ;
34
46
const [ toolResult , setToolResult ] = useState < string > ( "" ) ;
35
47
const [ error , setError ] = useState < string | null > ( null ) ;
36
48
const [ command , setCommand ] = useState < string > (
@@ -39,121 +51,128 @@ const App = () => {
39
51
const [ args , setArgs ] = useState < string > (
40
52
"/Users/ashwin/code/example-servers/build/everything/index.js" ,
41
53
) ;
42
- const [ mcpConnected , setMcpConnected ] = useState < boolean > ( false ) ;
43
54
const [ requestHistory , setRequestHistory ] = useState <
44
- Array < { request : string ; response : string | null } >
55
+ { request : string ; response : string } [ ]
45
56
> ( [ ] ) ;
57
+ const [ mcpClient , setMcpClient ] = useState < Client | null > ( null ) ;
46
58
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 ) ;
89
64
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
+ } ;
94
71
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
+ }
97
79
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
+ }
111
88
} ;
112
89
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 ) ;
121
99
}
122
100
} ;
123
101
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 ) ) ;
132
111
} ;
133
112
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 ) ;
136
121
} ;
137
122
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 ) ) ;
140
132
} ;
141
133
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 ) ;
144
142
} ;
145
143
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 ) ) ;
148
153
} ;
149
154
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 ) ;
153
169
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
+ }
157
176
} ;
158
177
159
178
return (
@@ -182,7 +201,7 @@ const App = () => {
182
201
</ Button >
183
202
</ div >
184
203
</ div >
185
- { mcpConnected ? (
204
+ { mcpClient ? (
186
205
< Tabs defaultValue = "resources" className = "w-full p-4" >
187
206
< TabsList className = "mb-4 p-0" >
188
207
< TabsTrigger value = "resources" >
0 commit comments