Skip to content

Commit bfc9e6e

Browse files
committed
get tools working
1 parent 88df0cd commit bfc9e6e

File tree

8 files changed

+92
-21
lines changed

8 files changed

+92
-21
lines changed

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@radix-ui/react-icons": "^1.3.0",
14+
"@radix-ui/react-label": "^2.1.0",
1415
"@radix-ui/react-slot": "^1.1.0",
1516
"@radix-ui/react-tabs": "^1.1.1",
1617
"class-variance-authority": "^0.7.0",

client/src/App.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ const App = () => {
207207
<Bell className="w-4 h-4 mr-2" />
208208
Notifications
209209
</TabsTrigger>
210-
<TabsTrigger value="tools" disabled>
210+
<TabsTrigger value="tools">
211211
<Hammer className="w-4 h-4 mr-2" />
212212
Tools
213213
</TabsTrigger>
@@ -243,7 +243,10 @@ const App = () => {
243243
listTools={listTools}
244244
callTool={callTool}
245245
selectedTool={selectedTool}
246-
setSelectedTool={setSelectedTool}
246+
setSelectedTool={(tool) => {
247+
setSelectedTool(tool);
248+
setToolResult("");
249+
}}
247250
toolResult={toolResult}
248251
error={error}
249252
/>

client/src/components/PromptsTab.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { TabsContent } from "@/components/ui/tabs";
55
import { Input } from "@/components/ui/input";
66
import { Textarea } from "@/components/ui/textarea";
77
import { useState } from "react";
8+
import { Label } from "@/components/ui/label";
89

910
export type Prompt = {
1011
name: string;
@@ -98,7 +99,9 @@ const PromptsTab = ({
9899
)}
99100
{selectedPrompt.arguments?.map((arg) => (
100101
<div key={arg.name}>
102+
<Label htmlFor={arg.name}>{arg.name}</Label>
101103
<Input
104+
id={arg.name}
102105
placeholder={`Enter ${arg.name}`}
103106
value={promptArgs[arg.name] || ""}
104107
onChange={(e) =>

client/src/components/ToolsTab.tsx

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import { TabsContent } from "@/components/ui/tabs";
22
import { Button } from "@/components/ui/button";
3-
import { Textarea } from "@/components/ui/textarea";
3+
import { Input } from "@/components/ui/input";
44
import { Send, AlertCircle } from "lucide-react";
55
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
66
import { useState } from "react";
7+
import { Label } from "@/components/ui/label";
78

89
export type Tool = {
910
name: string;
11+
description: string;
12+
inputSchema: {
13+
type: string;
14+
properties: Record<string, { type: string; description: string }>;
15+
};
1016
};
1117

1218
const ToolsTab = ({
@@ -26,7 +32,7 @@ const ToolsTab = ({
2632
toolResult: string;
2733
error: string | null;
2834
}) => {
29-
const [params, setParams] = useState("");
35+
const [params, setParams] = useState<Record<string, unknown>>({});
3036

3137
return (
3238
<TabsContent value="tools" className="grid grid-cols-2 gap-4">
@@ -46,6 +52,9 @@ const ToolsTab = ({
4652
onClick={() => setSelectedTool(tool)}
4753
>
4854
<span className="flex-1">{tool.name}</span>
55+
<span className="text-sm text-gray-500">
56+
{tool.description}
57+
</span>
4958
</div>
5059
))}
5160
</div>
@@ -67,22 +76,47 @@ const ToolsTab = ({
6776
</Alert>
6877
) : selectedTool ? (
6978
<div className="space-y-4">
70-
<Textarea
71-
placeholder="Tool parameters (JSON)"
72-
className="h-32 font-mono"
73-
value={params}
74-
onChange={(e) => setParams(e.target.value)}
75-
/>
76-
<Button
77-
onClick={() => callTool(selectedTool.name, JSON.parse(params))}
78-
>
79+
<p className="text-sm text-gray-600">
80+
{selectedTool.description}
81+
</p>
82+
{Object.entries(selectedTool.inputSchema.properties).map(
83+
([key, value]) => (
84+
<div key={key}>
85+
<Label
86+
htmlFor={key}
87+
className="block text-sm font-medium text-gray-700"
88+
>
89+
{key}
90+
</Label>
91+
<Input
92+
type={value.type === "number" ? "number" : "text"}
93+
id={key}
94+
name={key}
95+
placeholder={value.description}
96+
onChange={(e) =>
97+
setParams({
98+
...params,
99+
[key]:
100+
value.type === "number"
101+
? Number(e.target.value)
102+
: e.target.value,
103+
})
104+
}
105+
/>
106+
</div>
107+
),
108+
)}
109+
<Button onClick={() => callTool(selectedTool.name, params)}>
79110
<Send className="w-4 h-4 mr-2" />
80111
Run Tool
81112
</Button>
82113
{toolResult && (
83-
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
84-
{JSON.stringify(toolResult, null, 2)}
85-
</pre>
114+
<>
115+
<h4 className="font-semibold mb-2">Tool Result:</h4>
116+
<pre className="bg-gray-50 p-4 rounded text-sm overflow-auto max-h-64">
117+
{toolResult}
118+
</pre>
119+
</>
86120
)}
87121
</div>
88122
) : (

client/src/components/ui/label.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as React from "react"
2+
import * as LabelPrimitive from "@radix-ui/react-label"
3+
import { cva, type VariantProps } from "class-variance-authority"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
const labelVariants = cva(
8+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
9+
)
10+
11+
const Label = React.forwardRef<
12+
React.ElementRef<typeof LabelPrimitive.Root>,
13+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
14+
VariantProps<typeof labelVariants>
15+
>(({ className, ...props }, ref) => (
16+
<LabelPrimitive.Root
17+
ref={ref}
18+
className={cn(labelVariants(), className)}
19+
{...props}
20+
/>
21+
))
22+
Label.displayName = LabelPrimitive.Root.displayName
23+
24+
export { Label }

client/yarn.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,13 @@
499499
dependencies:
500500
"@radix-ui/react-use-layout-effect" "1.1.0"
501501

502+
"@radix-ui/react-label@^2.1.0":
503+
version "2.1.0"
504+
resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.0.tgz#3aa2418d70bb242be37c51ff5e51a2adcbc372e3"
505+
integrity sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==
506+
dependencies:
507+
"@radix-ui/react-primitive" "2.0.0"
508+
502509
"@radix-ui/[email protected]":
503510
version "1.1.1"
504511
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.1.tgz#98aba423dba5e0c687a782c0669dcd99de17f9b1"

server/src/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export class McpClient {
109109
return await this.client.request(
110110
{
111111
method: "tools/call",
112-
params: { name, ...params },
112+
params: { name, arguments: params },
113113
},
114114
CallToolResultSchema,
115115
);

server/src/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,10 @@ wss.on("connection", (ws: WebSocket) => {
4545
command.name &&
4646
command.params
4747
) {
48-
const result = await mcpClient.callTool(
49-
command.name + "asdf",
50-
command.params,
48+
const result = await mcpClient.callTool(command.name, command.params);
49+
ws.send(
50+
JSON.stringify({ type: "toolResult", data: result.toolResult }),
5151
);
52-
ws.send(JSON.stringify({ type: "toolResult", data: result }));
5352
}
5453
} catch (error) {
5554
console.error("Error:", error);

0 commit comments

Comments
 (0)