1
- import { Button } from "@/components/ui/button" ;
2
- import { Input } from "@/components/ui/input" ;
3
- import {
4
- Select ,
5
- SelectContent ,
6
- SelectItem ,
7
- SelectTrigger ,
8
- SelectValue ,
9
- } from "@/components/ui/select" ;
10
- import { Tabs , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
11
1
import { Client } from "@modelcontextprotocol/sdk/client/index.js" ;
12
2
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js" ;
13
3
import {
14
4
CallToolResultSchema ,
15
5
ClientRequest ,
6
+ CreateMessageRequestSchema ,
7
+ CreateMessageResult ,
16
8
EmptyResultSchema ,
17
9
GetPromptResultSchema ,
18
10
ListPromptsResultSchema ,
@@ -24,16 +16,28 @@ import {
24
16
ServerNotification ,
25
17
Tool ,
26
18
} from "@modelcontextprotocol/sdk/types.js" ;
19
+ import { useEffect , useRef , useState } from "react" ;
20
+
21
+ import { Button } from "@/components/ui/button" ;
22
+ import { Input } from "@/components/ui/input" ;
23
+ import {
24
+ Select ,
25
+ SelectContent ,
26
+ SelectItem ,
27
+ SelectTrigger ,
28
+ SelectValue ,
29
+ } from "@/components/ui/select" ;
30
+ import { Tabs , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
27
31
import {
28
32
Bell ,
29
33
Files ,
30
34
Hammer ,
35
+ Hash ,
31
36
MessageSquare ,
32
37
Play ,
33
38
Send ,
34
39
Terminal ,
35
40
} from "lucide-react" ;
36
- import { useEffect , useRef , useState } from "react" ;
37
41
38
42
import { AnyZodObject } from "zod" ;
39
43
import "./App.css" ;
@@ -43,6 +47,7 @@ import PingTab from "./components/PingTab";
43
47
import PromptsTab , { Prompt } from "./components/PromptsTab" ;
44
48
import RequestsTab from "./components/RequestsTabs" ;
45
49
import ResourcesTab from "./components/ResourcesTab" ;
50
+ import SamplingTab , { PendingRequest } from "./components/SamplingTab" ;
46
51
import Sidebar from "./components/Sidebar" ;
47
52
import ToolsTab from "./components/ToolsTab" ;
48
53
@@ -77,6 +82,32 @@ const App = () => {
77
82
const [ mcpClient , setMcpClient ] = useState < Client | null > ( null ) ;
78
83
const [ notifications , setNotifications ] = useState < ServerNotification [ ] > ( [ ] ) ;
79
84
85
+ const [ pendingSampleRequests , setPendingSampleRequests ] = useState <
86
+ Array <
87
+ PendingRequest & {
88
+ resolve : ( result : CreateMessageResult ) => void ;
89
+ reject : ( error : Error ) => void ;
90
+ }
91
+ >
92
+ > ( [ ] ) ;
93
+ const nextRequestId = useRef ( 0 ) ;
94
+
95
+ const handleApproveSampling = ( id : number , result : CreateMessageResult ) => {
96
+ setPendingSampleRequests ( ( prev ) => {
97
+ const request = prev . find ( ( r ) => r . id === id ) ;
98
+ request ?. resolve ( result ) ;
99
+ return prev . filter ( ( r ) => r . id !== id ) ;
100
+ } ) ;
101
+ } ;
102
+
103
+ const handleRejectSampling = ( id : number ) => {
104
+ setPendingSampleRequests ( ( prev ) => {
105
+ const request = prev . find ( ( r ) => r . id === id ) ;
106
+ request ?. reject ( new Error ( "Sampling request rejected" ) ) ;
107
+ return prev . filter ( ( r ) => r . id !== id ) ;
108
+ } ) ;
109
+ } ;
110
+
80
111
const [ selectedResource , setSelectedResource ] = useState < Resource | null > (
81
112
null ,
82
113
) ;
@@ -229,6 +260,15 @@ const App = () => {
229
260
} ,
230
261
) ;
231
262
263
+ client . setRequestHandler ( CreateMessageRequestSchema , ( request ) => {
264
+ return new Promise < CreateMessageResult > ( ( resolve , reject ) => {
265
+ setPendingSampleRequests ( ( prev ) => [
266
+ ...prev ,
267
+ { id : nextRequestId . current ++ , request, resolve, reject } ,
268
+ ] ) ;
269
+ } ) ;
270
+ } ) ;
271
+
232
272
setMcpClient ( client ) ;
233
273
setConnectionStatus ( "connected" ) ;
234
274
} catch ( e ) {
@@ -314,6 +354,15 @@ const App = () => {
314
354
< Bell className = "w-4 h-4 mr-2" />
315
355
Ping
316
356
</ TabsTrigger >
357
+ < TabsTrigger value = "sampling" className = "relative" >
358
+ < Hash className = "w-4 h-4 mr-2" />
359
+ Sampling
360
+ { pendingSampleRequests . length > 0 && (
361
+ < span className = "absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-4 w-4 flex items-center justify-center" >
362
+ { pendingSampleRequests . length }
363
+ </ span >
364
+ ) }
365
+ </ TabsTrigger >
317
366
</ TabsList >
318
367
319
368
< div className = "w-full" >
@@ -362,6 +411,11 @@ const App = () => {
362
411
) ;
363
412
} }
364
413
/>
414
+ < SamplingTab
415
+ pendingRequests = { pendingSampleRequests }
416
+ onApprove = { handleApproveSampling }
417
+ onReject = { handleRejectSampling }
418
+ />
365
419
</ div >
366
420
</ Tabs >
367
421
) : (
0 commit comments