Skip to content

Commit 982e10d

Browse files
authored
Merge branch 'main' into crondinini/support-client-secret
2 parents bc1ca95 + ece0e27 commit 982e10d

File tree

6 files changed

+146
-38
lines changed

6 files changed

+146
-38
lines changed

AGENTS.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# MCP Inspector Development Guide
2+
3+
## Build Commands
4+
5+
- Build all: `npm run build`
6+
- Build client: `npm run build-client`
7+
- Build server: `npm run build-server`
8+
- Development mode: `npm run dev` (use `npm run dev:windows` on Windows)
9+
- Format code: `npm run prettier-fix`
10+
- Client lint: `cd client && npm run lint`
11+
12+
## Code Style Guidelines
13+
14+
- Use TypeScript with proper type annotations
15+
- Follow React functional component patterns with hooks
16+
- Use ES modules (import/export) not CommonJS
17+
- Use Prettier for formatting (auto-formatted on commit)
18+
- Follow existing naming conventions:
19+
- camelCase for variables and functions
20+
- PascalCase for component names and types
21+
- kebab-case for file names
22+
- Use async/await for asynchronous operations
23+
- Implement proper error handling with try/catch blocks
24+
- Use Tailwind CSS for styling in the client
25+
- Keep components small and focused on a single responsibility
26+
27+
## Project Organization
28+
29+
The project is organized as a monorepo with workspaces:
30+
31+
- `client/`: React frontend with Vite, TypeScript and Tailwind
32+
- `server/`: Express backend with TypeScript
33+
- `cli/`: Command-line interface for testing and invoking MCP server methods directly

CLAUDE.md

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1 @@
1-
# MCP Inspector Development Guide
2-
3-
## Build Commands
4-
5-
- Build all: `npm run build`
6-
- Build client: `npm run build-client`
7-
- Build server: `npm run build-server`
8-
- Development mode: `npm run dev` (use `npm run dev:windows` on Windows)
9-
- Format code: `npm run prettier-fix`
10-
- Client lint: `cd client && npm run lint`
11-
12-
## Code Style Guidelines
13-
14-
- Use TypeScript with proper type annotations
15-
- Follow React functional component patterns with hooks
16-
- Use ES modules (import/export) not CommonJS
17-
- Use Prettier for formatting (auto-formatted on commit)
18-
- Follow existing naming conventions:
19-
- camelCase for variables and functions
20-
- PascalCase for component names and types
21-
- kebab-case for file names
22-
- Use async/await for asynchronous operations
23-
- Implement proper error handling with try/catch blocks
24-
- Use Tailwind CSS for styling in the client
25-
- Keep components small and focused on a single responsibility
26-
27-
## Project Organization
28-
29-
The project is organized as a monorepo with workspaces:
30-
31-
- `client/`: React frontend with Vite, TypeScript and Tailwind
32-
- `server/`: Express backend with TypeScript
33-
- `cli/`: Command-line interface for testing and invoking MCP server methods directly
1+
@./AGENTS.md

client/src/components/PromptsTab.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ const PromptsTab = ({
131131
<Alert variant="destructive">
132132
<AlertCircle className="h-4 w-4" />
133133
<AlertTitle>Error</AlertTitle>
134-
<AlertDescription>{error}</AlertDescription>
134+
<AlertDescription className="break-all">
135+
{error}
136+
</AlertDescription>
135137
</Alert>
136138
) : selectedPrompt ? (
137139
<div className="space-y-4">

client/src/components/ResourcesTab.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ const ResourcesTab = ({
225225
<Alert variant="destructive">
226226
<AlertCircle className="h-4 w-4" />
227227
<AlertTitle>Error</AlertTitle>
228-
<AlertDescription>{error}</AlertDescription>
228+
<AlertDescription className="break-all">
229+
{error}
230+
</AlertDescription>
229231
</Alert>
230232
) : selectedResource ? (
231233
<JsonView

client/src/components/ToolsTab.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import { Input } from "@/components/ui/input";
55
import { Label } from "@/components/ui/label";
66
import { TabsContent } from "@/components/ui/tabs";
77
import { Textarea } from "@/components/ui/textarea";
8+
import {
9+
Select,
10+
SelectContent,
11+
SelectItem,
12+
SelectTrigger,
13+
SelectValue,
14+
} from "@/components/ui/select";
815
import DynamicJsonForm, { DynamicJsonFormRef } from "./DynamicJsonForm";
916
import type { JsonValue, JsonSchemaType } from "@/utils/jsonUtils";
1017
import {
@@ -114,7 +121,7 @@ const ToolsTab = ({
114121
renderItem={(tool) => (
115122
<div className="flex flex-col items-start">
116123
<span className="flex-1">{tool.name}</span>
117-
<span className="text-sm text-gray-500 text-left">
124+
<span className="text-sm text-gray-500 text-left line-clamp-3">
118125
{tool.description}
119126
</span>
120127
</div>
@@ -137,10 +144,12 @@ const ToolsTab = ({
137144
<Alert variant="destructive">
138145
<AlertCircle className="h-4 w-4" />
139146
<AlertTitle>Error</AlertTitle>
140-
<AlertDescription>{error}</AlertDescription>
147+
<AlertDescription className="break-all">
148+
{error}
149+
</AlertDescription>
141150
</Alert>
142151
)}
143-
<p className="text-sm text-gray-600 dark:text-gray-400">
152+
<p className="text-sm text-gray-600 dark:text-gray-400 whitespace-pre-wrap max-h-48 overflow-y-auto">
144153
{selectedTool.description}
145154
</p>
146155
{Object.entries(selectedTool.inputSchema.properties ?? []).map(
@@ -180,6 +189,42 @@ const ToolsTab = ({
180189
{prop.description || "Toggle this option"}
181190
</label>
182191
</div>
192+
) : prop.type === "string" && prop.enum ? (
193+
<Select
194+
value={
195+
params[key] === undefined
196+
? ""
197+
: String(params[key])
198+
}
199+
onValueChange={(value) => {
200+
if (value === "") {
201+
setParams({
202+
...params,
203+
[key]: undefined,
204+
});
205+
} else {
206+
setParams({
207+
...params,
208+
[key]: value,
209+
});
210+
}
211+
}}
212+
>
213+
<SelectTrigger id={key} className="mt-1">
214+
<SelectValue
215+
placeholder={
216+
prop.description || "Select an option"
217+
}
218+
/>
219+
</SelectTrigger>
220+
<SelectContent>
221+
{prop.enum.map((option) => (
222+
<SelectItem key={option} value={option}>
223+
{option}
224+
</SelectItem>
225+
))}
226+
</SelectContent>
227+
</Select>
183228
) : prop.type === "string" ? (
184229
<Textarea
185230
id={key}

client/src/components/__tests__/ToolsTab.test.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,64 @@ describe("ToolsTab", () => {
638638
});
639639
});
640640

641+
describe("Enum Parameters", () => {
642+
const toolWithEnumParam: Tool = {
643+
name: "enumTool",
644+
description: "Tool with enum parameter",
645+
inputSchema: {
646+
type: "object" as const,
647+
properties: {
648+
format: {
649+
type: "string" as const,
650+
enum: ["json", "xml", "csv", "yaml"],
651+
description: "Output format",
652+
},
653+
},
654+
},
655+
};
656+
657+
beforeEach(() => {
658+
// Mock scrollIntoView for Radix UI Select
659+
Element.prototype.scrollIntoView = jest.fn();
660+
});
661+
662+
it("should render enum parameter as dropdown", () => {
663+
renderToolsTab({
664+
tools: [toolWithEnumParam],
665+
selectedTool: toolWithEnumParam,
666+
});
667+
668+
// Should render a select button instead of textarea
669+
const selectTrigger = screen.getByRole("combobox", { name: /format/i });
670+
expect(selectTrigger).toBeInTheDocument();
671+
});
672+
673+
it("should render non-enum string parameter as textarea", () => {
674+
const toolWithStringParam: Tool = {
675+
name: "stringTool",
676+
description: "Tool with regular string parameter",
677+
inputSchema: {
678+
type: "object" as const,
679+
properties: {
680+
text: {
681+
type: "string" as const,
682+
description: "Some text input",
683+
},
684+
},
685+
},
686+
};
687+
688+
renderToolsTab({
689+
tools: [toolWithStringParam],
690+
selectedTool: toolWithStringParam,
691+
});
692+
693+
// Should render textarea, not select
694+
expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
695+
expect(screen.getByRole("textbox")).toBeInTheDocument();
696+
});
697+
});
698+
641699
describe("JSON Validation Integration", () => {
642700
const toolWithJsonParams: Tool = {
643701
name: "jsonTool",

0 commit comments

Comments
 (0)