@@ -13,8 +13,12 @@ import {
13
13
ProgressNotificationSchema ,
14
14
ServerNotification ,
15
15
EmptyResultSchema ,
16
+ CreateMessageRequest ,
17
+ CreateMessageResult ,
18
+ CreateMessageRequestSchema ,
16
19
} from "mcp-typescript/types.js" ;
17
20
import { useState , useRef , useEffect } from "react" ;
21
+
18
22
import {
19
23
Send ,
20
24
Terminal ,
@@ -23,6 +27,7 @@ import {
23
27
MessageSquare ,
24
28
Hammer ,
25
29
Play ,
30
+ Hash ,
26
31
} from "lucide-react" ;
27
32
import { Tabs , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
28
33
import { Input } from "@/components/ui/input" ;
@@ -45,6 +50,7 @@ import { AnyZodObject } from "zod";
45
50
import HistoryAndNotifications from "./components/History" ;
46
51
import "./App.css" ;
47
52
import PingTab from "./components/PingTab" ;
53
+ import SamplingTab , { PendingRequest } from "./components/SamplingTab" ;
48
54
49
55
const App = ( ) => {
50
56
const [ connectionStatus , setConnectionStatus ] = useState <
@@ -77,6 +83,32 @@ const App = () => {
77
83
const [ mcpClient , setMcpClient ] = useState < Client | null > ( null ) ;
78
84
const [ notifications , setNotifications ] = useState < ServerNotification [ ] > ( [ ] ) ;
79
85
86
+ const [ pendingSampleRequests , setPendingSampleRequests ] = useState <
87
+ Array <
88
+ PendingRequest & {
89
+ resolve : ( result : CreateMessageResult ) => void ;
90
+ reject : ( error : Error ) => void ;
91
+ }
92
+ >
93
+ > ( [ ] ) ;
94
+ const nextRequestId = useRef ( 0 ) ;
95
+
96
+ const handleApproveSampling = ( id : number , result : CreateMessageResult ) => {
97
+ setPendingSampleRequests ( ( prev ) => {
98
+ const request = prev . find ( ( r ) => r . id === id ) ;
99
+ request ?. resolve ( result ) ;
100
+ return prev . filter ( ( r ) => r . id !== id ) ;
101
+ } ) ;
102
+ } ;
103
+
104
+ const handleRejectSampling = ( id : number ) => {
105
+ setPendingSampleRequests ( ( prev ) => {
106
+ const request = prev . find ( ( r ) => r . id === id ) ;
107
+ request ?. reject ( new Error ( "Sampling request rejected" ) ) ;
108
+ return prev . filter ( ( r ) => r . id !== id ) ;
109
+ } ) ;
110
+ } ;
111
+
80
112
const [ selectedResource , setSelectedResource ] = useState < Resource | null > (
81
113
null ,
82
114
) ;
@@ -229,6 +261,15 @@ const App = () => {
229
261
} ,
230
262
) ;
231
263
264
+ client . setRequestHandler ( CreateMessageRequestSchema , ( request ) => {
265
+ return new Promise < CreateMessageResult > ( ( resolve , reject ) => {
266
+ setPendingSampleRequests ( ( prev ) => [
267
+ ...prev ,
268
+ { id : nextRequestId . current ++ , request, resolve, reject } ,
269
+ ] ) ;
270
+ } ) ;
271
+ } ) ;
272
+
232
273
setMcpClient ( client ) ;
233
274
setConnectionStatus ( "connected" ) ;
234
275
} catch ( e ) {
@@ -314,6 +355,10 @@ const App = () => {
314
355
< Bell className = "w-4 h-4 mr-2" />
315
356
Ping
316
357
</ TabsTrigger >
358
+ < TabsTrigger value = "sampling" >
359
+ < Hash className = "w-4 h-4 mr-2" />
360
+ Sampling
361
+ </ TabsTrigger >
317
362
</ TabsList >
318
363
319
364
< div className = "w-full" >
@@ -362,6 +407,11 @@ const App = () => {
362
407
) ;
363
408
} }
364
409
/>
410
+ < SamplingTab
411
+ pendingRequests = { pendingSampleRequests }
412
+ onApprove = { handleApproveSampling }
413
+ onReject = { handleRejectSampling }
414
+ />
365
415
</ div >
366
416
</ Tabs >
367
417
) : (
0 commit comments