Track subscribed resources and show the appropriate subscribe or unsubscribe button on selected resource panel.
If the server does not support resource subscriptions, do not show any subscription buttons.
* In App.tsx
- useState for resourceSubscriptions, setResourceSubscriptions a Set of type string.
- in subscribeToResource()
- only make the request to subscribe if the uri is not in the resourceSubscriptions set
- in unsubscribeFromResource()
- only make the request to unsubscribe if the uri is in the resourceSubscriptions set
- in ResourceTab element,
- pass a boolean resourceSubscriptionsSupported as serverCapabilities.resources.subscribe
- pass resourceSubscriptions as a prop
* In ResourcesTab.tsx
- deconstruct resourceSubscriptions and resourceSubscriptionsSupported from props and add prop type
- in selected resource panel
- don't show subscribe or unsubscribe buttons unless resourceSubscriptionsSupported is true
- only show subscribe button if selected resource uri is not in resourceSubscriptions set
- only show unsubscribe button if selected resource uri is in resourceSubscriptions set
- wrap buttons in a flex div that is
- justified right
- has a minimal gap between
- 2/5 wide (just big enough to contain two buttons and leave the h3 text 3/5 of the row to render and not overflow.
This commit is contained in:
@@ -128,6 +128,8 @@ const App = () => {
|
||||
const [selectedResource, setSelectedResource] = useState<Resource | null>(
|
||||
null,
|
||||
);
|
||||
const [resourceSubscriptions, setResourceSubscriptions] = useState<Set<string>>(new Set<string>());
|
||||
|
||||
const [selectedPrompt, setSelectedPrompt] = useState<Prompt | null>(null);
|
||||
const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
|
||||
const [nextResourceCursor, setNextResourceCursor] = useState<
|
||||
@@ -310,26 +312,37 @@ const App = () => {
|
||||
|
||||
const subscribeToResource = async (uri: string) => {
|
||||
|
||||
await makeRequest(
|
||||
{
|
||||
method: "resources/subscribe" as const,
|
||||
params: { uri },
|
||||
},
|
||||
z.object({}),
|
||||
"resources",
|
||||
);
|
||||
if (!resourceSubscriptions.has(uri)) {
|
||||
await makeRequest(
|
||||
{
|
||||
method: "resources/subscribe" as const,
|
||||
params: { uri },
|
||||
},
|
||||
z.object({}),
|
||||
"resources",
|
||||
);
|
||||
const clone = new Set(resourceSubscriptions);
|
||||
clone.add(uri);
|
||||
setResourceSubscriptions(clone);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const unsubscribeFromResource = async (uri: string) => {
|
||||
|
||||
await makeRequest(
|
||||
{
|
||||
method: "resources/unsubscribe" as const,
|
||||
params: { uri },
|
||||
},
|
||||
z.object({}),
|
||||
"resources",
|
||||
);
|
||||
if (resourceSubscriptions.has(uri)) {
|
||||
await makeRequest(
|
||||
{
|
||||
method: "resources/unsubscribe" as const,
|
||||
params: { uri },
|
||||
},
|
||||
z.object({}),
|
||||
"resources",
|
||||
);
|
||||
const clone = new Set(resourceSubscriptions);
|
||||
clone.delete(uri);
|
||||
setResourceSubscriptions(clone);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -510,6 +523,8 @@ const App = () => {
|
||||
clearError("resources");
|
||||
setSelectedResource(resource);
|
||||
}}
|
||||
resourceSubscriptionsSupported={serverCapabilities?.resources?.subscribe || false}
|
||||
resourceSubscriptions={resourceSubscriptions}
|
||||
subscribeToResource={(uri) => {
|
||||
clearError("resources");
|
||||
subscribeToResource(uri);
|
||||
|
||||
@@ -26,6 +26,8 @@ const ResourcesTab = ({
|
||||
readResource,
|
||||
selectedResource,
|
||||
setSelectedResource,
|
||||
resourceSubscriptionsSupported,
|
||||
resourceSubscriptions,
|
||||
subscribeToResource,
|
||||
unsubscribeFromResource,
|
||||
handleCompletion,
|
||||
@@ -54,6 +56,8 @@ const ResourcesTab = ({
|
||||
nextCursor: ListResourcesResult["nextCursor"];
|
||||
nextTemplateCursor: ListResourceTemplatesResult["nextCursor"];
|
||||
error: string | null;
|
||||
resourceSubscriptionsSupported: boolean;
|
||||
resourceSubscriptions: Set<string>;
|
||||
subscribeToResource: (uri: string) => void;
|
||||
unsubscribeFromResource: (uri: string) => void;
|
||||
}) => {
|
||||
@@ -168,14 +172,16 @@ const ResourcesTab = ({
|
||||
: "Select a resource or template"}
|
||||
</h3>
|
||||
{selectedResource && (
|
||||
<>
|
||||
<Button
|
||||
<div className="flex row-auto gap-1 justify-end w-2/5">
|
||||
{ resourceSubscriptionsSupported && !resourceSubscriptions.has(selectedResource.uri) && <Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => subscribeToResource(selectedResource.uri)}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
}
|
||||
{ resourceSubscriptionsSupported && resourceSubscriptions.has(selectedResource.uri) &&
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -183,6 +189,7 @@ const ResourcesTab = ({
|
||||
>
|
||||
Unsubscribe
|
||||
</Button>
|
||||
}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -191,7 +198,7 @@ const ResourcesTab = ({
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
Refresh
|
||||
</Button>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4">
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -13,8 +13,8 @@
|
||||
"server"
|
||||
],
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/inspector-client": "0.4.1",
|
||||
"@modelcontextprotocol/inspector-server": "0.4.1",
|
||||
"@modelcontextprotocol/inspector-client": "^0.5.1",
|
||||
"@modelcontextprotocol/inspector-server": "^0.5.1",
|
||||
"concurrently": "^9.0.1",
|
||||
"shell-quote": "^1.8.2",
|
||||
"spawn-rx": "^5.1.2",
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
"publish-all": "npm publish --workspaces --access public && npm publish --access public"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/inspector-client": "0.4.1",
|
||||
"@modelcontextprotocol/inspector-server": "0.4.1",
|
||||
"@modelcontextprotocol/inspector-client": "^0.5.1",
|
||||
"@modelcontextprotocol/inspector-server": "^0.5.1",
|
||||
"concurrently": "^9.0.1",
|
||||
"shell-quote": "^1.8.2",
|
||||
"spawn-rx": "^5.1.2",
|
||||
|
||||
Reference in New Issue
Block a user