Skip to content

Commit 291c59e

Browse files
authored
Merge branch 'main' into clarify-proxy-role-in-readme
2 parents 11757ef + 2c527ca commit 291c59e

File tree

11 files changed

+164
-56
lines changed

11 files changed

+164
-56
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ Note that the proxy is not a network proxy for intercepting traffic. Instead, it
1919

2020
- Node.js: ^22.7.5
2121

22+
### Quick Start (UI mode)
23+
24+
To get up and running right away with the UI, just execute the following:
25+
26+
```bash
27+
npx @modelcontextprotocol/inspector
28+
```
29+
30+
The server will start up and the UI will be accessible at `http://localhost:6274`.
31+
2232
### From an MCP server repository
2333

2434
To inspect an MCP server implementation, there's no need to clone this repo. Instead, use `npx`. For example, if your server is built at `build/index.js`:

client/src/App.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ const App = () => {
611611
className="w-full p-4"
612612
onValueChange={(value) => (window.location.hash = value)}
613613
>
614-
<TabsList className="mb-4 p-0">
614+
<TabsList className="mb-4 py-0">
615615
<TabsTrigger
616616
value="resources"
617617
disabled={!serverCapabilities?.resources}
@@ -662,7 +662,7 @@ const App = () => {
662662
!serverCapabilities?.tools ? (
663663
<>
664664
<div className="flex items-center justify-center p-4">
665-
<p className="text-lg text-gray-500">
665+
<p className="text-lg text-gray-500 dark:text-gray-400">
666666
The connected server does not support any MCP
667667
capabilities
668668
</p>
@@ -816,7 +816,7 @@ const App = () => {
816816
</Tabs>
817817
) : (
818818
<div className="flex flex-col items-center justify-center h-full gap-4">
819-
<p className="text-lg text-gray-500">
819+
<p className="text-lg text-gray-500 dark:text-gray-400">
820820
Connect to an MCP server to start inspecting
821821
</p>
822822
<div className="flex items-center gap-2">
@@ -841,7 +841,7 @@ const App = () => {
841841
}}
842842
>
843843
<div
844-
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50"
844+
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50 dark:hover:bg-input/40"
845845
onMouseDown={handleDragStart}
846846
>
847847
<div className="w-8 h-1 rounded-full bg-border" />

client/src/components/History.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ const HistoryAndNotifications = ({
2929
<div className="flex-1 overflow-y-auto p-4 border-r">
3030
<h2 className="text-lg font-semibold mb-4">History</h2>
3131
{requestHistory.length === 0 ? (
32-
<p className="text-sm text-gray-500 italic">No history yet</p>
32+
<p className="text-sm text-gray-500 dark:text-gray-400 italic">
33+
No history yet
34+
</p>
3335
) : (
3436
<ul className="space-y-3">
3537
{requestHistory
@@ -38,7 +40,7 @@ const HistoryAndNotifications = ({
3840
.map((request, index) => (
3941
<li
4042
key={index}
41-
className="text-sm text-foreground bg-secondary p-2 rounded"
43+
className="text-sm text-foreground bg-secondary py-2 px-3 rounded"
4244
>
4345
<div
4446
className="flex justify-between items-center cursor-pointer"
@@ -93,7 +95,9 @@ const HistoryAndNotifications = ({
9395
<div className="flex-1 overflow-y-auto p-4">
9496
<h2 className="text-lg font-semibold mb-4">Server Notifications</h2>
9597
{serverNotifications.length === 0 ? (
96-
<p className="text-sm text-gray-500 italic">No notifications yet</p>
98+
<p className="text-sm text-gray-500 dark:text-gray-400 italic">
99+
No notifications yet
100+
</p>
97101
) : (
98102
<ul className="space-y-3">
99103
{serverNotifications
@@ -102,7 +106,7 @@ const HistoryAndNotifications = ({
102106
.map((notification, index) => (
103107
<li
104108
key={index}
105-
className="text-sm text-foreground bg-secondary p-2 rounded"
109+
className="text-sm text-foreground bg-secondary py-2 px-3 rounded"
106110
>
107111
<div
108112
className="flex justify-between items-center cursor-pointer"

client/src/components/ListPane.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ const ListPane = <T extends object>({
2121
buttonText,
2222
isButtonDisabled,
2323
}: ListPaneProps<T>) => (
24-
<div className="bg-card rounded-lg shadow">
25-
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
24+
<div className="bg-card border border-border rounded-lg shadow">
25+
<div className="p-4 border-b border-gray-200 dark:border-border">
2626
<h3 className="font-semibold dark:text-white">{title}</h3>
2727
</div>
2828
<div className="p-4">
@@ -46,7 +46,7 @@ const ListPane = <T extends object>({
4646
{items.map((item, index) => (
4747
<div
4848
key={index}
49-
className="flex items-center p-2 rounded hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer"
49+
className="flex items-center py-2 px-4 rounded hover:bg-gray-50 dark:hover:bg-secondary cursor-pointer"
5050
onClick={() => setSelectedItem(item)}
5151
>
5252
{renderItem(item)}

client/src/components/PromptsTab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ const PromptsTab = ({
110110
isButtonDisabled={!nextCursor && prompts.length > 0}
111111
/>
112112

113-
<div className="bg-card rounded-lg shadow">
114-
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
113+
<div className="bg-card border border-border rounded-lg shadow">
114+
<div className="p-4 border-b border-gray-200 dark:border-border">
115115
<h3 className="font-semibold">
116116
{selectedPrompt ? selectedPrompt.name : "Select a prompt"}
117117
</h3>
@@ -126,7 +126,7 @@ const PromptsTab = ({
126126
) : selectedPrompt ? (
127127
<div className="space-y-4">
128128
{selectedPrompt.description && (
129-
<p className="text-sm text-gray-600">
129+
<p className="text-sm text-gray-600 dark:text-gray-400">
130130
{selectedPrompt.description}
131131
</p>
132132
)}

client/src/components/ResourcesTab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ const ResourcesTab = ({
173173
isButtonDisabled={!nextTemplateCursor && resourceTemplates.length > 0}
174174
/>
175175

176-
<div className="bg-card rounded-lg shadow">
177-
<div className="p-4 border-b border-gray-200 dark:border-gray-800 flex justify-between items-center">
176+
<div className="bg-card border border-border rounded-lg shadow">
177+
<div className="p-4 border-b border-gray-200 dark:border-border flex justify-between items-center">
178178
<h3
179179
className="font-semibold truncate"
180180
title={selectedResource?.name || selectedTemplate?.name}
@@ -234,7 +234,7 @@ const ResourcesTab = ({
234234
/>
235235
) : selectedTemplate ? (
236236
<div className="space-y-4">
237-
<p className="text-sm text-gray-600">
237+
<p className="text-sm text-gray-600 dark:text-gray-400">
238238
{selectedTemplate.description}
239239
</p>
240240
{selectedTemplate.uriTemplate

client/src/components/Sidebar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const Sidebar = ({
215215

216216
return (
217217
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
218-
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800">
218+
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-border">
219219
<div className="flex items-center">
220220
<h1 className="ml-2 text-lg font-semibold">
221221
MCP Inspector v{version}
@@ -646,7 +646,7 @@ const Sidebar = ({
646646
}
647647
})()}`}
648648
/>
649-
<span className="text-sm text-gray-600">
649+
<span className="text-sm text-gray-600 dark:text-gray-400">
650650
{(() => {
651651
switch (connectionStatus) {
652652
case "connected":

client/src/components/ToolsTab.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ const ToolsTab = ({
7777
isButtonDisabled={!nextCursor && tools.length > 0}
7878
/>
7979

80-
<div className="bg-card rounded-lg shadow">
81-
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
80+
<div className="bg-card border border-border rounded-lg shadow">
81+
<div className="p-4 border-b border-gray-200 dark:border-border">
8282
<h3 className="font-semibold">
8383
{selectedTool ? selectedTool.name : "Select a tool"}
8484
</h3>
8585
</div>
8686
<div className="p-4">
8787
{selectedTool ? (
8888
<div className="space-y-4">
89-
<p className="text-sm text-gray-600">
89+
<p className="text-sm text-gray-600 dark:text-gray-400">
9090
{selectedTool.description}
9191
</p>
9292
{Object.entries(selectedTool.inputSchema.properties ?? []).map(
@@ -96,7 +96,7 @@ const ToolsTab = ({
9696
<div key={key}>
9797
<Label
9898
htmlFor={key}
99-
className="block text-sm font-medium text-gray-700"
99+
className="block text-sm font-medium text-gray-700 dark:text-gray-300"
100100
>
101101
{key}
102102
</Label>

client/src/index.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ h1 {
9393
--accent-foreground: 210 40% 98%;
9494
--destructive: 0 62.8% 30.6%;
9595
--destructive-foreground: 210 40% 98%;
96-
--border: 217.2 32.6% 17.5%;
97-
--input: 217.2 32.6% 17.5%;
96+
--border: 217.2 24% 24%;
97+
--input: 217.2 24% 24%;
9898
--ring: 212.7 26.8% 83.9%;
9999
--chart-1: 220 70% 50%;
100100
--chart-2: 160 60% 45%;

client/src/lib/hooks/__tests__/useConnection.test.tsx

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,18 @@ jest.mock("@modelcontextprotocol/sdk/client/index.js", () => ({
2828
}));
2929

3030
jest.mock("@modelcontextprotocol/sdk/client/sse.js", () => ({
31-
SSEClientTransport: jest.fn(),
31+
SSEClientTransport: jest.fn((url) => ({
32+
toString: () => url,
33+
})),
3234
SseError: jest.fn(),
3335
}));
3436

37+
jest.mock("@modelcontextprotocol/sdk/client/streamableHttp.js", () => ({
38+
StreamableHTTPClientTransport: jest.fn((url) => ({
39+
toString: () => url,
40+
})),
41+
}));
42+
3543
jest.mock("@modelcontextprotocol/sdk/client/auth.js", () => ({
3644
auth: jest.fn().mockResolvedValue("AUTHORIZED"),
3745
}));
@@ -163,4 +171,92 @@ describe("useConnection", () => {
163171
result.current.makeRequest(mockRequest, mockSchema),
164172
).rejects.toThrow("MCP client not connected");
165173
});
174+
175+
describe("URL Port Handling", () => {
176+
const SSEClientTransport = jest.requireMock(
177+
"@modelcontextprotocol/sdk/client/sse.js",
178+
).SSEClientTransport;
179+
const StreamableHTTPClientTransport = jest.requireMock(
180+
"@modelcontextprotocol/sdk/client/streamableHttp.js",
181+
).StreamableHTTPClientTransport;
182+
183+
beforeEach(() => {
184+
jest.clearAllMocks();
185+
});
186+
187+
test("preserves HTTPS port number when connecting", async () => {
188+
const props = {
189+
...defaultProps,
190+
sseUrl: "https://example.com:8443/api",
191+
transportType: "sse" as const,
192+
};
193+
194+
const { result } = renderHook(() => useConnection(props));
195+
196+
await act(async () => {
197+
await result.current.connect();
198+
});
199+
200+
const call = SSEClientTransport.mock.calls[0][0];
201+
expect(call.toString()).toContain(
202+
"url=https%3A%2F%2Fexample.com%3A8443%2Fapi",
203+
);
204+
});
205+
206+
test("preserves HTTP port number when connecting", async () => {
207+
const props = {
208+
...defaultProps,
209+
sseUrl: "http://localhost:3000/api",
210+
transportType: "sse" as const,
211+
};
212+
213+
const { result } = renderHook(() => useConnection(props));
214+
215+
await act(async () => {
216+
await result.current.connect();
217+
});
218+
219+
const call = SSEClientTransport.mock.calls[0][0];
220+
expect(call.toString()).toContain(
221+
"url=http%3A%2F%2Flocalhost%3A3000%2Fapi",
222+
);
223+
});
224+
225+
test("uses default port for HTTPS when not specified", async () => {
226+
const props = {
227+
...defaultProps,
228+
sseUrl: "https://example.com/api",
229+
transportType: "sse" as const,
230+
};
231+
232+
const { result } = renderHook(() => useConnection(props));
233+
234+
await act(async () => {
235+
await result.current.connect();
236+
});
237+
238+
const call = SSEClientTransport.mock.calls[0][0];
239+
expect(call.toString()).toContain("url=https%3A%2F%2Fexample.com%2Fapi");
240+
expect(call.toString()).not.toContain("%3A443");
241+
});
242+
243+
test("preserves port number in streamable-http transport", async () => {
244+
const props = {
245+
...defaultProps,
246+
sseUrl: "https://example.com:8443/api",
247+
transportType: "streamable-http" as const,
248+
};
249+
250+
const { result } = renderHook(() => useConnection(props));
251+
252+
await act(async () => {
253+
await result.current.connect();
254+
});
255+
256+
const call = StreamableHTTPClientTransport.mock.calls[0][0];
257+
expect(call.toString()).toContain(
258+
"url=https%3A%2F%2Fexample.com%3A8443%2Fapi",
259+
);
260+
});
261+
});
166262
});

0 commit comments

Comments
 (0)