@@ -19,10 +19,11 @@ import {
19
19
Request ,
20
20
Resource ,
21
21
ResourceTemplate ,
22
- Result ,
23
22
Root ,
24
23
ServerNotification ,
25
24
Tool ,
25
+ ServerCapabilitiesSchema ,
26
+ Result ,
26
27
} from "@modelcontextprotocol/sdk/types.js" ;
27
28
import { useCallback , useEffect , useRef , useState } from "react" ;
28
29
@@ -43,7 +44,7 @@ import {
43
44
} from "lucide-react" ;
44
45
45
46
import { toast } from "react-toastify" ;
46
- import { ZodType } from "zod" ;
47
+ import { z , type ZodType } from "zod" ;
47
48
import "./App.css" ;
48
49
import ConsoleTab from "./components/ConsoleTab" ;
49
50
import HistoryAndNotifications from "./components/History" ;
@@ -55,6 +56,8 @@ import SamplingTab, { PendingRequest } from "./components/SamplingTab";
55
56
import Sidebar from "./components/Sidebar" ;
56
57
import ToolsTab from "./components/ToolsTab" ;
57
58
59
+ type ServerCapabilities = z . infer < typeof ServerCapabilitiesSchema > ;
60
+
58
61
const DEFAULT_REQUEST_TIMEOUT_MSEC = 10000 ;
59
62
60
63
const params = new URLSearchParams ( window . location . search ) ;
@@ -67,6 +70,7 @@ const App = () => {
67
70
const [ connectionStatus , setConnectionStatus ] = useState <
68
71
"disconnected" | "connected" | "error"
69
72
> ( "disconnected" ) ;
73
+ const [ serverCapabilities , setServerCapabilities ] = useState < ServerCapabilities | null > ( null ) ;
70
74
const [ resources , setResources ] = useState < Resource [ ] > ( [ ] ) ;
71
75
const [ resourceTemplates , setResourceTemplates ] = useState <
72
76
ResourceTemplate [ ]
@@ -455,6 +459,9 @@ const App = () => {
455
459
456
460
await client . connect ( clientTransport ) ;
457
461
462
+ const capabilities = client . getServerCapabilities ( ) ;
463
+ setServerCapabilities ( capabilities ?? null ) ;
464
+
458
465
client . setRequestHandler ( CreateMessageRequestSchema , ( request ) => {
459
466
return new Promise < CreateMessageResult > ( ( resolve , reject ) => {
460
467
setPendingSampleRequests ( ( prev ) => [
@@ -497,20 +504,27 @@ const App = () => {
497
504
< div className = "flex-1 overflow-auto" >
498
505
{ mcpClient ? (
499
506
< Tabs
500
- defaultValue = { window . location . hash . slice ( 1 ) || "resources" }
507
+ defaultValue = {
508
+ Object . keys ( serverCapabilities ?? { } ) . includes ( window . location . hash . slice ( 1 ) ) ?
509
+ window . location . hash . slice ( 1 ) :
510
+ serverCapabilities ?. resources ? "resources" :
511
+ serverCapabilities ?. prompts ? "prompts" :
512
+ serverCapabilities ?. tools ? "tools" :
513
+ "ping"
514
+ }
501
515
className = "w-full p-4"
502
516
onValueChange = { ( value ) => ( window . location . hash = value ) }
503
517
>
504
518
< TabsList className = "mb-4 p-0" >
505
- < TabsTrigger value = "resources" >
519
+ < TabsTrigger value = "resources" disabled = { ! serverCapabilities ?. resources } >
506
520
< Files className = "w-4 h-4 mr-2" />
507
521
Resources
508
522
</ TabsTrigger >
509
- < TabsTrigger value = "prompts" >
523
+ < TabsTrigger value = "prompts" disabled = { ! serverCapabilities ?. prompts } >
510
524
< MessageSquare className = "w-4 h-4 mr-2" />
511
525
Prompts
512
526
</ TabsTrigger >
513
- < TabsTrigger value = "tools" >
527
+ < TabsTrigger value = "tools" disabled = { ! serverCapabilities ?. tools } >
514
528
< Hammer className = "w-4 h-4 mr-2" />
515
529
Tools
516
530
</ TabsTrigger >
@@ -534,107 +548,117 @@ const App = () => {
534
548
</ TabsList >
535
549
536
550
< div className = "w-full" >
537
- < ResourcesTab
538
- resources = { resources }
539
- resourceTemplates = { resourceTemplates }
540
- listResources = { ( ) => {
541
- clearError ( "resources" ) ;
542
- listResources ( ) ;
543
- } }
544
- clearResources = { ( ) => {
545
- setResources ( [ ] ) ;
546
- setNextResourceCursor ( undefined ) ;
547
- } }
548
- listResourceTemplates = { ( ) => {
549
- clearError ( "resources" ) ;
550
- listResourceTemplates ( ) ;
551
- } }
552
- clearResourceTemplates = { ( ) => {
553
- setResourceTemplates ( [ ] ) ;
554
- setNextResourceTemplateCursor ( undefined ) ;
555
- } }
556
- readResource = { ( uri ) => {
557
- clearError ( "resources" ) ;
558
- readResource ( uri ) ;
559
- } }
560
- selectedResource = { selectedResource }
561
- setSelectedResource = { ( resource ) => {
562
- clearError ( "resources" ) ;
563
- setSelectedResource ( resource ) ;
564
- } }
565
- resourceContent = { resourceContent }
566
- nextCursor = { nextResourceCursor }
567
- nextTemplateCursor = { nextResourceTemplateCursor }
568
- error = { errors . resources }
569
- />
570
- < PromptsTab
571
- prompts = { prompts }
572
- listPrompts = { ( ) => {
573
- clearError ( "prompts" ) ;
574
- listPrompts ( ) ;
575
- } }
576
- clearPrompts = { ( ) => {
577
- setPrompts ( [ ] ) ;
578
- setNextPromptCursor ( undefined ) ;
579
- } }
580
- getPrompt = { ( name , args ) => {
581
- clearError ( "prompts" ) ;
582
- getPrompt ( name , args ) ;
583
- } }
584
- selectedPrompt = { selectedPrompt }
585
- setSelectedPrompt = { ( prompt ) => {
586
- clearError ( "prompts" ) ;
587
- setSelectedPrompt ( prompt ) ;
588
- } }
589
- promptContent = { promptContent }
590
- nextCursor = { nextPromptCursor }
591
- error = { errors . prompts }
592
- />
593
- < ToolsTab
594
- tools = { tools }
595
- listTools = { ( ) => {
596
- clearError ( "tools" ) ;
597
- listTools ( ) ;
598
- } }
599
- clearTools = { ( ) => {
600
- setTools ( [ ] ) ;
601
- setNextToolCursor ( undefined ) ;
602
- } }
603
- callTool = { ( name , params ) => {
604
- clearError ( "tools" ) ;
605
- callTool ( name , params ) ;
606
- } }
607
- selectedTool = { selectedTool }
608
- setSelectedTool = { ( tool ) => {
609
- clearError ( "tools" ) ;
610
- setSelectedTool ( tool ) ;
611
- setToolResult ( null ) ;
612
- } }
613
- toolResult = { toolResult }
614
- nextCursor = { nextToolCursor }
615
- error = { errors . tools }
616
- />
617
- < ConsoleTab />
618
- < PingTab
619
- onPingClick = { ( ) => {
620
- void makeRequest (
621
- {
622
- method : "ping" as const ,
623
- } ,
624
- EmptyResultSchema ,
625
- ) ;
626
- } }
627
- />
628
- < SamplingTab
629
- pendingRequests = { pendingSampleRequests }
630
- onApprove = { handleApproveSampling }
631
- onReject = { handleRejectSampling }
632
- />
633
- < RootsTab
634
- roots = { roots }
635
- setRoots = { setRoots }
636
- onRootsChange = { handleRootsChange }
637
- />
551
+ { ! serverCapabilities ?. resources && ! serverCapabilities ?. prompts && ! serverCapabilities ?. tools ? (
552
+ < div className = "flex items-center justify-center p-4" >
553
+ < p className = "text-lg text-gray-500" >
554
+ The connected server does not support any MCP capabilities
555
+ </ p >
556
+ </ div >
557
+ ) : (
558
+ < >
559
+ < ResourcesTab
560
+ resources = { resources }
561
+ resourceTemplates = { resourceTemplates }
562
+ listResources = { ( ) => {
563
+ clearError ( "resources" ) ;
564
+ listResources ( ) ;
565
+ } }
566
+ clearResources = { ( ) => {
567
+ setResources ( [ ] ) ;
568
+ setNextResourceCursor ( undefined ) ;
569
+ } }
570
+ listResourceTemplates = { ( ) => {
571
+ clearError ( "resources" ) ;
572
+ listResourceTemplates ( ) ;
573
+ } }
574
+ clearResourceTemplates = { ( ) => {
575
+ setResourceTemplates ( [ ] ) ;
576
+ setNextResourceTemplateCursor ( undefined ) ;
577
+ } }
578
+ readResource = { ( uri ) => {
579
+ clearError ( "resources" ) ;
580
+ readResource ( uri ) ;
581
+ } }
582
+ selectedResource = { selectedResource }
583
+ setSelectedResource = { ( resource ) => {
584
+ clearError ( "resources" ) ;
585
+ setSelectedResource ( resource ) ;
586
+ } }
587
+ resourceContent = { resourceContent }
588
+ nextCursor = { nextResourceCursor }
589
+ nextTemplateCursor = { nextResourceTemplateCursor }
590
+ error = { errors . resources }
591
+ />
592
+ < PromptsTab
593
+ prompts = { prompts }
594
+ listPrompts = { ( ) => {
595
+ clearError ( "prompts" ) ;
596
+ listPrompts ( ) ;
597
+ } }
598
+ clearPrompts = { ( ) => {
599
+ setPrompts ( [ ] ) ;
600
+ setNextPromptCursor ( undefined ) ;
601
+ } }
602
+ getPrompt = { ( name , args ) => {
603
+ clearError ( "prompts" ) ;
604
+ getPrompt ( name , args ) ;
605
+ } }
606
+ selectedPrompt = { selectedPrompt }
607
+ setSelectedPrompt = { ( prompt ) => {
608
+ clearError ( "prompts" ) ;
609
+ setSelectedPrompt ( prompt ) ;
610
+ } }
611
+ promptContent = { promptContent }
612
+ nextCursor = { nextPromptCursor }
613
+ error = { errors . prompts }
614
+ />
615
+ < ToolsTab
616
+ tools = { tools }
617
+ listTools = { ( ) => {
618
+ clearError ( "tools" ) ;
619
+ listTools ( ) ;
620
+ } }
621
+ clearTools = { ( ) => {
622
+ setTools ( [ ] ) ;
623
+ setNextToolCursor ( undefined ) ;
624
+ } }
625
+ callTool = { ( name , params ) => {
626
+ clearError ( "tools" ) ;
627
+ callTool ( name , params ) ;
628
+ } }
629
+ selectedTool = { selectedTool }
630
+ setSelectedTool = { ( tool ) => {
631
+ clearError ( "tools" ) ;
632
+ setSelectedTool ( tool ) ;
633
+ setToolResult ( null ) ;
634
+ } }
635
+ toolResult = { toolResult }
636
+ nextCursor = { nextToolCursor }
637
+ error = { errors . tools }
638
+ />
639
+ < ConsoleTab />
640
+ < PingTab
641
+ onPingClick = { ( ) => {
642
+ void makeRequest (
643
+ {
644
+ method : "ping" as const ,
645
+ } ,
646
+ EmptyResultSchema ,
647
+ ) ;
648
+ } }
649
+ />
650
+ < SamplingTab
651
+ pendingRequests = { pendingSampleRequests }
652
+ onApprove = { handleApproveSampling }
653
+ onReject = { handleRejectSampling }
654
+ />
655
+ < RootsTab
656
+ roots = { roots }
657
+ setRoots = { setRoots }
658
+ onRootsChange = { handleRootsChange }
659
+ />
660
+ </ >
661
+ ) }
638
662
</ div >
639
663
</ Tabs >
640
664
) : (
0 commit comments