adding two buttons for configs: copy entry, copy file. also adding some tooltip and optimizations.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, useCallback } from "react";
|
||||||
import {
|
import {
|
||||||
Play,
|
Play,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
@@ -98,47 +98,62 @@ const Sidebar = ({
|
|||||||
const [showBearerToken, setShowBearerToken] = useState(false);
|
const [showBearerToken, setShowBearerToken] = useState(false);
|
||||||
const [showConfig, setShowConfig] = useState(false);
|
const [showConfig, setShowConfig] = useState(false);
|
||||||
const [shownEnvVars, setShownEnvVars] = useState<Set<string>>(new Set());
|
const [shownEnvVars, setShownEnvVars] = useState<Set<string>>(new Set());
|
||||||
const [copiedConfig, setCopiedConfig] = useState(false);
|
const [copiedConfigEntry, setCopiedConfigEntry] = useState(false);
|
||||||
|
const [copiedConfigFile, setCopiedConfigFile] = useState(false);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
// Generate MCP configuration JSON
|
// Shared utility function to generate server config
|
||||||
const generateMCPConfig = () => {
|
const generateServerConfig = useCallback(() => {
|
||||||
if (transportType === "stdio") {
|
if (transportType === "stdio") {
|
||||||
// Generate only the server config without the mcpServers wrapper
|
return {
|
||||||
const serverConfig = {
|
|
||||||
command,
|
command,
|
||||||
args: args.trim() ? args.split(/\s+/) : [],
|
args: args.trim() ? args.split(/\s+/) : [],
|
||||||
env: { ...env },
|
env: { ...env }
|
||||||
};
|
};
|
||||||
|
|
||||||
return JSON.stringify(serverConfig, null, 2);
|
|
||||||
} else {
|
} else {
|
||||||
// For SSE connections
|
return {
|
||||||
return JSON.stringify({
|
type: "sse",
|
||||||
// SSE configuration doesn't go in mcp.json, but provide the URL info
|
url: sseUrl,
|
||||||
"type": "sse",
|
note: "For SSE connections, add this URL directly in Client"
|
||||||
"url": sseUrl,
|
};
|
||||||
"note": "For SSE connections, add this URL directly in Cursor"
|
|
||||||
}, null, 2);
|
|
||||||
}
|
}
|
||||||
};
|
}, [transportType, command, args, env, sseUrl]);
|
||||||
|
|
||||||
// Handle copy config
|
// Memoized config entry generator
|
||||||
const handleCopyConfig = () => {
|
const generateMCPConfigEntry = useCallback(() => {
|
||||||
|
return JSON.stringify(generateServerConfig(), null, 2);
|
||||||
|
}, [generateServerConfig]);
|
||||||
|
|
||||||
|
// Memoized config file generator
|
||||||
|
const generateMCPConfigFile = useCallback(() => {
|
||||||
|
return JSON.stringify(
|
||||||
|
{
|
||||||
|
mcpServers: {
|
||||||
|
"default-server": generateServerConfig()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}, [generateServerConfig]);
|
||||||
|
|
||||||
|
// Memoized copy handlers
|
||||||
|
const handleCopyConfigEntry = useCallback(() => {
|
||||||
try {
|
try {
|
||||||
const configJson = generateMCPConfig();
|
const configJson = generateMCPConfigEntry();
|
||||||
navigator.clipboard.writeText(configJson);
|
navigator.clipboard.writeText(configJson);
|
||||||
setCopiedConfig(true);
|
setCopiedConfigEntry(true);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Config copied",
|
title: "Config entry copied",
|
||||||
description: transportType === "stdio"
|
description:
|
||||||
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
|
transportType === "stdio"
|
||||||
: "SSE URL has been copied. Use this URL in Cursor directly.",
|
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
|
||||||
|
: "SSE URL has been copied. Use this URL in Cursor directly.",
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCopiedConfig(false);
|
setCopiedConfigEntry(false);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
@@ -147,7 +162,30 @@ const Sidebar = ({
|
|||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}, [generateMCPConfigEntry, transportType, toast]);
|
||||||
|
|
||||||
|
const handleCopyConfigFile = useCallback(() => {
|
||||||
|
try {
|
||||||
|
const configJson = generateMCPConfigFile();
|
||||||
|
navigator.clipboard.writeText(configJson);
|
||||||
|
setCopiedConfigFile(true);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Config file copied",
|
||||||
|
description: "Server configuration has been copied to clipboard. Add this to your mcp.json file. Current testing server will be added as 'default-server'",
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setCopiedConfigFile(false);
|
||||||
|
}, 2000);
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
description: `Failed to copy config: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [generateMCPConfigFile, toast]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
|
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
|
||||||
@@ -213,21 +251,48 @@ const Sidebar = ({
|
|||||||
className="font-mono"
|
className="font-mono"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end">
|
<div className="flex gap-2 justify-end">
|
||||||
<Button
|
|
||||||
variant="outline"
|
<Tooltip>
|
||||||
size="sm"
|
<TooltipTrigger asChild>
|
||||||
onClick={handleCopyConfig}
|
<Button
|
||||||
className="mt-1"
|
variant="outline"
|
||||||
title="Copy Server Configuration for mcp.json"
|
size="sm"
|
||||||
>
|
onClick={handleCopyConfigEntry}
|
||||||
{copiedConfig ? (
|
className="mt-1"
|
||||||
<CheckCheck className="h-4 w-4 mr-2" />
|
>
|
||||||
) : (
|
{copiedConfigEntry ? (
|
||||||
<Copy className="h-4 w-4 mr-2" />
|
<CheckCheck className="h-4 w-4 mr-2" />
|
||||||
)}
|
) : (
|
||||||
Copy Config
|
<Copy className="h-4 w-4 mr-2" />
|
||||||
</Button>
|
)}
|
||||||
|
Config Entry
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
Copy Config Entry
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={handleCopyConfigFile}
|
||||||
|
className="mt-1"
|
||||||
|
>
|
||||||
|
{copiedConfigFile ? (
|
||||||
|
<CheckCheck className="h-4 w-4 mr-2" />
|
||||||
|
) : (
|
||||||
|
<Copy className="h-4 w-4 mr-2" />
|
||||||
|
)}
|
||||||
|
Config File
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
Copy Config File
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -248,11 +313,11 @@ const Sidebar = ({
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleCopyConfig}
|
onClick={handleCopyConfigFile}
|
||||||
className="mt-1"
|
className="mt-1"
|
||||||
title="Copy SSE URL Configuration"
|
title="Copy SSE URL Configuration"
|
||||||
>
|
>
|
||||||
{copiedConfig ? (
|
{copiedConfigFile ? (
|
||||||
<CheckCheck className="h-4 w-4 mr-2" />
|
<CheckCheck className="h-4 w-4 mr-2" />
|
||||||
) : (
|
) : (
|
||||||
<Copy className="h-4 w-4 mr-2" />
|
<Copy className="h-4 w-4 mr-2" />
|
||||||
|
|||||||
Reference in New Issue
Block a user