Skip to content

Commit c824c6e

Browse files
committed
feat: Copy the input parameters of tools
1 parent 8683c0f commit c824c6e

File tree

1 file changed

+60
-24
lines changed

1 file changed

+60
-24
lines changed

client/src/components/ToolsTab.tsx

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@ import {
1313
ListToolsResult,
1414
Tool,
1515
} from "@modelcontextprotocol/sdk/types.js";
16-
import { Loader2, Send, ChevronDown, ChevronUp } from "lucide-react";
16+
import {
17+
Loader2,
18+
Send,
19+
ChevronDown,
20+
ChevronUp,
21+
Copy,
22+
CheckCheck,
23+
} from "lucide-react";
1724
import { useEffect, useState } from "react";
1825
import ListPane from "./ListPane";
1926
import JsonView from "./JsonView";
2027
import ToolResults from "./ToolResults";
28+
import { useToast } from "@/lib/hooks/useToast";
29+
import useCopy from "@/lib/hooks/useCopy";
2130

2231
const ToolsTab = ({
2332
tools,
@@ -46,6 +55,8 @@ const ToolsTab = ({
4655
const [params, setParams] = useState<Record<string, unknown>>({});
4756
const [isToolRunning, setIsToolRunning] = useState(false);
4857
const [isOutputSchemaExpanded, setIsOutputSchemaExpanded] = useState(false);
58+
const { toast } = useToast();
59+
const { copied, setCopied } = useCopy();
4960

5061
useEffect(() => {
5162
const params = Object.entries(
@@ -245,29 +256,54 @@ const ToolsTab = ({
245256
</div>
246257
</div>
247258
)}
248-
<Button
249-
onClick={async () => {
250-
try {
251-
setIsToolRunning(true);
252-
await callTool(selectedTool.name, params);
253-
} finally {
254-
setIsToolRunning(false);
255-
}
256-
}}
257-
disabled={isToolRunning}
258-
>
259-
{isToolRunning ? (
260-
<>
261-
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
262-
Running...
263-
</>
264-
) : (
265-
<>
266-
<Send className="w-4 h-4 mr-2" />
267-
Run Tool
268-
</>
269-
)}
270-
</Button>
259+
<div className="flex gap-2">
260+
<Button
261+
onClick={async () => {
262+
try {
263+
setIsToolRunning(true);
264+
await callTool(selectedTool.name, params);
265+
} finally {
266+
setIsToolRunning(false);
267+
}
268+
}}
269+
disabled={isToolRunning}
270+
>
271+
{isToolRunning ? (
272+
<>
273+
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
274+
Running...
275+
</>
276+
) : (
277+
<>
278+
<Send className="w-4 h-4 mr-2" />
279+
Run Tool
280+
</>
281+
)}
282+
</Button>
283+
<Button
284+
onClick={async () => {
285+
try {
286+
navigator.clipboard.writeText(
287+
JSON.stringify(params, null, 2),
288+
);
289+
setCopied(true);
290+
} catch (error) {
291+
toast({
292+
title: "Error",
293+
description: `There was an error coping result into the clipboard: ${error instanceof Error ? error.message : String(error)}`,
294+
variant: "destructive",
295+
});
296+
}
297+
}}
298+
>
299+
{copied ? (
300+
<CheckCheck className="h-4 w-4 mr-2 dark:text-green-700 text-green-600" />
301+
) : (
302+
<Copy className="h-4 w-4 mr-2" />
303+
)}
304+
Copy Input
305+
</Button>
306+
</div>
271307
<ToolResults
272308
toolResult={toolResult}
273309
selectedTool={selectedTool}

0 commit comments

Comments
 (0)