Skip to content

Commit aeac3ac

Browse files
authored
Merge branch 'main' into set-header
2 parents a98db77 + a3a1ad4 commit aeac3ac

27 files changed

+1208
-593
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
The MCP inspector is a developer tool for testing and debugging MCP servers.
44

5-
![MCP Inspector Screenshot](mcp-inspector.png)
5+
![MCP Inspector Screenshot](https://raw.githubusercontent.com/modelcontextprotocol/inspector/main/mcp-inspector.png)
66

77
## Running the Inspector
88

@@ -48,12 +48,16 @@ The MCP Inspector includes a proxy server that can run and communicate with loca
4848

4949
### Configuration
5050

51-
The MCP Inspector supports the following configuration settings. To change them click on the `Configuration` button in the MCP Inspector UI :
51+
The MCP Inspector supports the following configuration settings. To change them, click on the `Configuration` button in the MCP Inspector UI:
5252

53-
| Name | Purpose | Default Value |
54-
| -------------------------- | ----------------------------------------------------------------------------------------- | ------------- |
55-
| MCP_SERVER_REQUEST_TIMEOUT | Maximum time in milliseconds to wait for a response from the MCP server before timing out | 10000 |
56-
| MCP_PROXY_FULL_ADDRESS | The full URL of the MCP Inspector proxy server (e.g. `http://10.2.1.14:2277`) | `null` |
53+
| Setting | Description | Default |
54+
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------- |
55+
| `MCP_SERVER_REQUEST_TIMEOUT` | Timeout for requests to the MCP server (ms) | 10000 |
56+
| `MCP_REQUEST_TIMEOUT_RESET_ON_PROGRESS` | Reset timeout on progress notifications | true |
57+
| `MCP_REQUEST_MAX_TOTAL_TIMEOUT` | Maximum total timeout for requests sent to the MCP server (ms) (Use with progress notifications) | 60000 |
58+
| `MCP_PROXY_FULL_ADDRESS` | Set this if you are running the MCP Inspector Proxy on a non-default address. Example: http://10.1.1.22:5577 | "" |
59+
60+
These settings can be adjusted in real-time through the UI and will persist across sessions.
5761

5862
### From this repository
5963

client/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-client",
3-
"version": "0.8.1",
3+
"version": "0.8.2",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -23,7 +23,7 @@
2323
"test:watch": "jest --config jest.config.cjs --watch"
2424
},
2525
"dependencies": {
26-
"@modelcontextprotocol/sdk": "^1.8.0",
26+
"@modelcontextprotocol/sdk": "^1.9.0",
2727
"@radix-ui/react-checkbox": "^1.1.4",
2828
"@radix-ui/react-dialog": "^1.1.3",
2929
"@radix-ui/react-icons": "^1.3.0",
@@ -32,9 +32,8 @@
3232
"@radix-ui/react-select": "^2.1.2",
3333
"@radix-ui/react-slot": "^1.1.0",
3434
"@radix-ui/react-tabs": "^1.1.1",
35-
"@radix-ui/react-tooltip": "^1.1.8",
3635
"@radix-ui/react-toast": "^1.2.6",
37-
"@types/prismjs": "^1.26.5",
36+
"@radix-ui/react-tooltip": "^1.1.8",
3837
"class-variance-authority": "^0.7.0",
3938
"clsx": "^2.1.1",
4039
"cmdk": "^1.0.4",
@@ -55,6 +54,7 @@
5554
"@testing-library/react": "^16.2.0",
5655
"@types/jest": "^29.5.14",
5756
"@types/node": "^22.7.5",
57+
"@types/prismjs": "^1.26.5",
5858
"@types/react": "^18.3.10",
5959
"@types/react-dom": "^18.3.0",
6060
"@types/serve-handler": "^6.1.4",

client/src/App.tsx

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,7 @@ import Sidebar from "./components/Sidebar";
4545
import ToolsTab from "./components/ToolsTab";
4646
import { DEFAULT_INSPECTOR_CONFIG } from "./lib/constants";
4747
import { InspectorConfig } from "./lib/configurationTypes";
48-
import {
49-
getMCPProxyAddress,
50-
getMCPServerRequestTimeout,
51-
} from "./utils/configUtils";
48+
import { getMCPProxyAddress } from "./utils/configUtils";
5249
import { useToast } from "@/hooks/use-toast";
5350

5451
const params = new URLSearchParams(window.location.search);
@@ -98,10 +95,21 @@ const App = () => {
9895
const [config, setConfig] = useState<InspectorConfig>(() => {
9996
const savedConfig = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY);
10097
if (savedConfig) {
101-
return {
98+
// merge default config with saved config
99+
const mergedConfig = {
102100
...DEFAULT_INSPECTOR_CONFIG,
103101
...JSON.parse(savedConfig),
104102
} as InspectorConfig;
103+
104+
// update description of keys to match the new description (in case of any updates to the default config description)
105+
Object.entries(mergedConfig).forEach(([key, value]) => {
106+
mergedConfig[key as keyof InspectorConfig] = {
107+
...value,
108+
label: DEFAULT_INSPECTOR_CONFIG[key as keyof InspectorConfig].label,
109+
};
110+
});
111+
112+
return mergedConfig;
105113
}
106114
return DEFAULT_INSPECTOR_CONFIG;
107115
});
@@ -152,7 +160,7 @@ const App = () => {
152160
serverCapabilities,
153161
mcpClient,
154162
requestHistory,
155-
makeRequest: makeConnectionRequest,
163+
makeRequest,
156164
sendNotification,
157165
handleCompletion,
158166
completionsSupported,
@@ -168,6 +176,7 @@ const App = () => {
168176
headerName,
169177
proxyServerUrl: getMCPProxyAddress(config),
170178
requestTimeout: getMCPServerRequestTimeout(config),
179+
config,
171180
onNotification: (notification) => {
172181
setNotifications((prev) => [...prev, notification as ServerNotification]);
173182
},
@@ -288,13 +297,13 @@ const App = () => {
288297
setErrors((prev) => ({ ...prev, [tabKey]: null }));
289298
};
290299

291-
const makeRequest = async <T extends z.ZodType>(
300+
const sendMCPRequest = async <T extends z.ZodType>(
292301
request: ClientRequest,
293302
schema: T,
294303
tabKey?: keyof typeof errors,
295304
) => {
296305
try {
297-
const response = await makeConnectionRequest(request, schema);
306+
const response = await makeRequest(request, schema);
298307
if (tabKey !== undefined) {
299308
clearError(tabKey);
300309
}
@@ -312,7 +321,7 @@ const App = () => {
312321
};
313322

314323
const listResources = async () => {
315-
const response = await makeRequest(
324+
const response = await sendMCPRequest(
316325
{
317326
method: "resources/list" as const,
318327
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
@@ -325,7 +334,7 @@ const App = () => {
325334
};
326335

327336
const listResourceTemplates = async () => {
328-
const response = await makeRequest(
337+
const response = await sendMCPRequest(
329338
{
330339
method: "resources/templates/list" as const,
331340
params: nextResourceTemplateCursor
@@ -342,7 +351,7 @@ const App = () => {
342351
};
343352

344353
const readResource = async (uri: string) => {
345-
const response = await makeRequest(
354+
const response = await sendMCPRequest(
346355
{
347356
method: "resources/read" as const,
348357
params: { uri },
@@ -355,7 +364,7 @@ const App = () => {
355364

356365
const subscribeToResource = async (uri: string) => {
357366
if (!resourceSubscriptions.has(uri)) {
358-
await makeRequest(
367+
await sendMCPRequest(
359368
{
360369
method: "resources/subscribe" as const,
361370
params: { uri },
@@ -371,7 +380,7 @@ const App = () => {
371380

372381
const unsubscribeFromResource = async (uri: string) => {
373382
if (resourceSubscriptions.has(uri)) {
374-
await makeRequest(
383+
await sendMCPRequest(
375384
{
376385
method: "resources/unsubscribe" as const,
377386
params: { uri },
@@ -386,7 +395,7 @@ const App = () => {
386395
};
387396

388397
const listPrompts = async () => {
389-
const response = await makeRequest(
398+
const response = await sendMCPRequest(
390399
{
391400
method: "prompts/list" as const,
392401
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
@@ -399,7 +408,7 @@ const App = () => {
399408
};
400409

401410
const getPrompt = async (name: string, args: Record<string, string> = {}) => {
402-
const response = await makeRequest(
411+
const response = await sendMCPRequest(
403412
{
404413
method: "prompts/get" as const,
405414
params: { name, arguments: args },
@@ -411,7 +420,7 @@ const App = () => {
411420
};
412421

413422
const listTools = async () => {
414-
const response = await makeRequest(
423+
const response = await sendMCPRequest(
415424
{
416425
method: "tools/list" as const,
417426
params: nextToolCursor ? { cursor: nextToolCursor } : {},
@@ -424,29 +433,42 @@ const App = () => {
424433
};
425434

426435
const callTool = async (name: string, params: Record<string, unknown>) => {
427-
const response = await makeRequest(
428-
{
429-
method: "tools/call" as const,
430-
params: {
431-
name,
432-
arguments: params,
433-
_meta: {
434-
progressToken: progressTokenRef.current++,
436+
try {
437+
const response = await sendMCPRequest(
438+
{
439+
method: "tools/call" as const,
440+
params: {
441+
name,
442+
arguments: params,
443+
_meta: {
444+
progressToken: progressTokenRef.current++,
445+
},
435446
},
436447
},
437-
},
438-
CompatibilityCallToolResultSchema,
439-
"tools",
440-
);
441-
setToolResult(response);
448+
CompatibilityCallToolResultSchema,
449+
"tools",
450+
);
451+
setToolResult(response);
452+
} catch (e) {
453+
const toolResult: CompatibilityCallToolResult = {
454+
content: [
455+
{
456+
type: "text",
457+
text: (e as Error).message ?? String(e),
458+
},
459+
],
460+
isError: true,
461+
};
462+
setToolResult(toolResult);
463+
}
442464
};
443465

444466
const handleRootsChange = async () => {
445467
await sendNotification({ method: "notifications/roots/list_changed" });
446468
};
447469

448470
const sendLogLevelRequest = async (level: LoggingLevel) => {
449-
await makeRequest(
471+
await sendMCPRequest(
450472
{
451473
method: "logging/setLevel" as const,
452474
params: { level },
@@ -648,9 +670,10 @@ const App = () => {
648670
setTools([]);
649671
setNextToolCursor(undefined);
650672
}}
651-
callTool={(name, params) => {
673+
callTool={async (name, params) => {
652674
clearError("tools");
653-
callTool(name, params);
675+
setToolResult(null);
676+
await callTool(name, params);
654677
}}
655678
selectedTool={selectedTool}
656679
setSelectedTool={(tool) => {
@@ -665,7 +688,7 @@ const App = () => {
665688
<ConsoleTab />
666689
<PingTab
667690
onPingClick={() => {
668-
void makeRequest(
691+
void sendMCPRequest(
669692
{
670693
method: "ping" as const,
671694
},

client/src/components/DynamicJsonForm.tsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,9 @@ import { Button } from "@/components/ui/button";
33
import { Input } from "@/components/ui/input";
44
import { Label } from "@/components/ui/label";
55
import JsonEditor from "./JsonEditor";
6-
import { updateValueAtPath, JsonObject } from "@/utils/jsonPathUtils";
6+
import { updateValueAtPath } from "@/utils/jsonUtils";
77
import { generateDefaultValue, formatFieldLabel } from "@/utils/schemaUtils";
8-
9-
export type JsonValue =
10-
| string
11-
| number
12-
| boolean
13-
| null
14-
| undefined
15-
| JsonValue[]
16-
| { [key: string]: JsonValue };
17-
18-
export type JsonSchemaType = {
19-
type:
20-
| "string"
21-
| "number"
22-
| "integer"
23-
| "boolean"
24-
| "array"
25-
| "object"
26-
| "null";
27-
description?: string;
28-
required?: boolean;
29-
default?: JsonValue;
30-
properties?: Record<string, JsonSchemaType>;
31-
items?: JsonSchemaType;
32-
};
8+
import type { JsonValue, JsonSchemaType, JsonObject } from "@/utils/jsonUtils";
339

3410
interface DynamicJsonFormProps {
3511
schema: JsonSchemaType;

0 commit comments

Comments
 (0)