Skip to content

Commit 163356f

Browse files
adding two buttons for configs: copy entry, copy file. also adding some tooltip and optimizations.
1 parent 114df8a commit 163356f

File tree

1 file changed

+112
-47
lines changed

1 file changed

+112
-47
lines changed

client/src/components/Sidebar.tsx

Lines changed: 112 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useState, useCallback } from "react";
22
import {
33
Play,
44
ChevronDown,
@@ -98,47 +98,62 @@ const Sidebar = ({
9898
const [showBearerToken, setShowBearerToken] = useState(false);
9999
const [showConfig, setShowConfig] = useState(false);
100100
const [shownEnvVars, setShownEnvVars] = useState<Set<string>>(new Set());
101-
const [copiedConfig, setCopiedConfig] = useState(false);
101+
const [copiedConfigEntry, setCopiedConfigEntry] = useState(false);
102+
const [copiedConfigFile, setCopiedConfigFile] = useState(false);
102103
const { toast } = useToast();
103104

104-
// Generate MCP configuration JSON
105-
const generateMCPConfig = () => {
106-
if (transportType === "stdio") {
107-
// Generate only the server config without the mcpServers wrapper
108-
const serverConfig = {
105+
// Shared utility function to generate server config
106+
const generateServerConfig = useCallback(() => {
107+
if (transportType === "stdio") {
108+
return {
109109
command,
110110
args: args.trim() ? args.split(/\s+/) : [],
111-
env: { ...env },
111+
env: { ...env }
112112
};
113-
114-
return JSON.stringify(serverConfig, null, 2);
115113
} else {
116-
// For SSE connections
117-
return JSON.stringify({
118-
// SSE configuration doesn't go in mcp.json, but provide the URL info
119-
"type": "sse",
120-
"url": sseUrl,
121-
"note": "For SSE connections, add this URL directly in Cursor"
122-
}, null, 2);
114+
return {
115+
type: "sse",
116+
url: sseUrl,
117+
note: "For SSE connections, add this URL directly in Client"
118+
};
123119
}
124-
};
120+
}, [transportType, command, args, env, sseUrl]);
121+
122+
// Memoized config entry generator
123+
const generateMCPConfigEntry = useCallback(() => {
124+
return JSON.stringify(generateServerConfig(), null, 2);
125+
}, [generateServerConfig]);
126+
127+
// Memoized config file generator
128+
const generateMCPConfigFile = useCallback(() => {
129+
return JSON.stringify(
130+
{
131+
mcpServers: {
132+
"default-server": generateServerConfig()
133+
}
134+
},
135+
null,
136+
2
137+
);
138+
}, [generateServerConfig]);
125139

126-
// Handle copy config
127-
const handleCopyConfig = () => {
140+
// Memoized copy handlers
141+
const handleCopyConfigEntry = useCallback(() => {
128142
try {
129-
const configJson = generateMCPConfig();
143+
const configJson = generateMCPConfigEntry();
130144
navigator.clipboard.writeText(configJson);
131-
setCopiedConfig(true);
132-
145+
setCopiedConfigEntry(true);
146+
133147
toast({
134-
title: "Config copied",
135-
description: transportType === "stdio"
136-
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
137-
: "SSE URL has been copied. Use this URL in Cursor directly.",
148+
title: "Config entry copied",
149+
description:
150+
transportType === "stdio"
151+
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
152+
: "SSE URL has been copied. Use this URL in Cursor directly.",
138153
});
139-
154+
140155
setTimeout(() => {
141-
setCopiedConfig(false);
156+
setCopiedConfigEntry(false);
142157
}, 2000);
143158
} catch (error) {
144159
toast({
@@ -147,7 +162,30 @@ const Sidebar = ({
147162
variant: "destructive",
148163
});
149164
}
150-
};
165+
}, [generateMCPConfigEntry, transportType, toast]);
166+
167+
const handleCopyConfigFile = useCallback(() => {
168+
try {
169+
const configJson = generateMCPConfigFile();
170+
navigator.clipboard.writeText(configJson);
171+
setCopiedConfigFile(true);
172+
173+
toast({
174+
title: "Config file copied",
175+
description: "Server configuration has been copied to clipboard. Add this to your mcp.json file. Current testing server will be added as 'default-server'",
176+
});
177+
178+
setTimeout(() => {
179+
setCopiedConfigFile(false);
180+
}, 2000);
181+
} catch (error) {
182+
toast({
183+
title: "Error",
184+
description: `Failed to copy config: ${error instanceof Error ? error.message : String(error)}`,
185+
variant: "destructive",
186+
});
187+
}
188+
}, [generateMCPConfigFile, toast]);
151189

152190
return (
153191
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
@@ -213,21 +251,48 @@ const Sidebar = ({
213251
className="font-mono"
214252
/>
215253
</div>
216-
<div className="flex justify-end">
217-
<Button
218-
variant="outline"
219-
size="sm"
220-
onClick={handleCopyConfig}
221-
className="mt-1"
222-
title="Copy Server Configuration for mcp.json"
223-
>
224-
{copiedConfig ? (
225-
<CheckCheck className="h-4 w-4 mr-2" />
226-
) : (
227-
<Copy className="h-4 w-4 mr-2" />
228-
)}
229-
Copy Config
230-
</Button>
254+
<div className="flex gap-2 justify-end">
255+
256+
<Tooltip>
257+
<TooltipTrigger asChild>
258+
<Button
259+
variant="outline"
260+
size="sm"
261+
onClick={handleCopyConfigEntry}
262+
className="mt-1"
263+
>
264+
{copiedConfigEntry ? (
265+
<CheckCheck className="h-4 w-4 mr-2" />
266+
) : (
267+
<Copy className="h-4 w-4 mr-2" />
268+
)}
269+
Config Entry
270+
</Button>
271+
</TooltipTrigger>
272+
<TooltipContent>
273+
Copy Config Entry
274+
</TooltipContent>
275+
</Tooltip>
276+
<Tooltip>
277+
<TooltipTrigger asChild>
278+
<Button
279+
variant="outline"
280+
size="sm"
281+
onClick={handleCopyConfigFile}
282+
className="mt-1"
283+
>
284+
{copiedConfigFile ? (
285+
<CheckCheck className="h-4 w-4 mr-2" />
286+
) : (
287+
<Copy className="h-4 w-4 mr-2" />
288+
)}
289+
Config File
290+
</Button>
291+
</TooltipTrigger>
292+
<TooltipContent>
293+
Copy Config File
294+
</TooltipContent>
295+
</Tooltip>
231296
</div>
232297
</>
233298
) : (
@@ -248,11 +313,11 @@ const Sidebar = ({
248313
<Button
249314
variant="outline"
250315
size="sm"
251-
onClick={handleCopyConfig}
316+
onClick={handleCopyConfigFile}
252317
className="mt-1"
253318
title="Copy SSE URL Configuration"
254319
>
255-
{copiedConfig ? (
320+
{copiedConfigFile ? (
256321
<CheckCheck className="h-4 w-4 mr-2" />
257322
) : (
258323
<Copy className="h-4 w-4 mr-2" />

0 commit comments

Comments
 (0)