Skip to content

Commit 5696c19

Browse files
Merge branch 'main' into sampling-form
2 parents 71bb89d + 645a256 commit 5696c19

37 files changed

+1273
-646
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ jobs:
2626
# - run: npm ci
2727
- run: npm install --no-package-lock
2828

29+
- name: Check linting
30+
working-directory: ./client
31+
run: npm run lint
32+
2933
- name: Run client tests
3034
working-directory: ./client
3135
run: npm test

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 & 35 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
});
@@ -148,7 +156,7 @@ const App = () => {
148156
serverCapabilities,
149157
mcpClient,
150158
requestHistory,
151-
makeRequest: makeConnectionRequest,
159+
makeRequest,
152160
sendNotification,
153161
handleCompletion,
154162
completionsSupported,
@@ -161,8 +169,7 @@ const App = () => {
161169
sseUrl,
162170
env,
163171
bearerToken,
164-
proxyServerUrl: getMCPProxyAddress(config),
165-
requestTimeout: getMCPServerRequestTimeout(config),
172+
config,
166173
onNotification: (notification) => {
167174
setNotifications((prev) => [...prev, notification as ServerNotification]);
168175
},
@@ -279,13 +286,13 @@ const App = () => {
279286
setErrors((prev) => ({ ...prev, [tabKey]: null }));
280287
};
281288

282-
const makeRequest = async <T extends z.ZodType>(
289+
const sendMCPRequest = async <T extends z.ZodType>(
283290
request: ClientRequest,
284291
schema: T,
285292
tabKey?: keyof typeof errors,
286293
) => {
287294
try {
288-
const response = await makeConnectionRequest(request, schema);
295+
const response = await makeRequest(request, schema);
289296
if (tabKey !== undefined) {
290297
clearError(tabKey);
291298
}
@@ -303,7 +310,7 @@ const App = () => {
303310
};
304311

305312
const listResources = async () => {
306-
const response = await makeRequest(
313+
const response = await sendMCPRequest(
307314
{
308315
method: "resources/list" as const,
309316
params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
@@ -316,7 +323,7 @@ const App = () => {
316323
};
317324

318325
const listResourceTemplates = async () => {
319-
const response = await makeRequest(
326+
const response = await sendMCPRequest(
320327
{
321328
method: "resources/templates/list" as const,
322329
params: nextResourceTemplateCursor
@@ -333,7 +340,7 @@ const App = () => {
333340
};
334341

335342
const readResource = async (uri: string) => {
336-
const response = await makeRequest(
343+
const response = await sendMCPRequest(
337344
{
338345
method: "resources/read" as const,
339346
params: { uri },
@@ -346,7 +353,7 @@ const App = () => {
346353

347354
const subscribeToResource = async (uri: string) => {
348355
if (!resourceSubscriptions.has(uri)) {
349-
await makeRequest(
356+
await sendMCPRequest(
350357
{
351358
method: "resources/subscribe" as const,
352359
params: { uri },
@@ -362,7 +369,7 @@ const App = () => {
362369

363370
const unsubscribeFromResource = async (uri: string) => {
364371
if (resourceSubscriptions.has(uri)) {
365-
await makeRequest(
372+
await sendMCPRequest(
366373
{
367374
method: "resources/unsubscribe" as const,
368375
params: { uri },
@@ -377,7 +384,7 @@ const App = () => {
377384
};
378385

379386
const listPrompts = async () => {
380-
const response = await makeRequest(
387+
const response = await sendMCPRequest(
381388
{
382389
method: "prompts/list" as const,
383390
params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
@@ -390,7 +397,7 @@ const App = () => {
390397
};
391398

392399
const getPrompt = async (name: string, args: Record<string, string> = {}) => {
393-
const response = await makeRequest(
400+
const response = await sendMCPRequest(
394401
{
395402
method: "prompts/get" as const,
396403
params: { name, arguments: args },
@@ -402,7 +409,7 @@ const App = () => {
402409
};
403410

404411
const listTools = async () => {
405-
const response = await makeRequest(
412+
const response = await sendMCPRequest(
406413
{
407414
method: "tools/list" as const,
408415
params: nextToolCursor ? { cursor: nextToolCursor } : {},
@@ -415,29 +422,42 @@ const App = () => {
415422
};
416423

417424
const callTool = async (name: string, params: Record<string, unknown>) => {
418-
const response = await makeRequest(
419-
{
420-
method: "tools/call" as const,
421-
params: {
422-
name,
423-
arguments: params,
424-
_meta: {
425-
progressToken: progressTokenRef.current++,
425+
try {
426+
const response = await sendMCPRequest(
427+
{
428+
method: "tools/call" as const,
429+
params: {
430+
name,
431+
arguments: params,
432+
_meta: {
433+
progressToken: progressTokenRef.current++,
434+
},
426435
},
427436
},
428-
},
429-
CompatibilityCallToolResultSchema,
430-
"tools",
431-
);
432-
setToolResult(response);
437+
CompatibilityCallToolResultSchema,
438+
"tools",
439+
);
440+
setToolResult(response);
441+
} catch (e) {
442+
const toolResult: CompatibilityCallToolResult = {
443+
content: [
444+
{
445+
type: "text",
446+
text: (e as Error).message ?? String(e),
447+
},
448+
],
449+
isError: true,
450+
};
451+
setToolResult(toolResult);
452+
}
433453
};
434454

435455
const handleRootsChange = async () => {
436456
await sendNotification({ method: "notifications/roots/list_changed" });
437457
};
438458

439459
const sendLogLevelRequest = async (level: LoggingLevel) => {
440-
await makeRequest(
460+
await sendMCPRequest(
441461
{
442462
method: "logging/setLevel" as const,
443463
params: { level },
@@ -637,9 +657,10 @@ const App = () => {
637657
setTools([]);
638658
setNextToolCursor(undefined);
639659
}}
640-
callTool={(name, params) => {
660+
callTool={async (name, params) => {
641661
clearError("tools");
642-
callTool(name, params);
662+
setToolResult(null);
663+
await callTool(name, params);
643664
}}
644665
selectedTool={selectedTool}
645666
setSelectedTool={(tool) => {
@@ -654,7 +675,7 @@ const App = () => {
654675
<ConsoleTab />
655676
<PingTab
656677
onPingClick={() => {
657-
void makeRequest(
678+
void sendMCPRequest(
658679
{
659680
method: "ping" as const,
660681
},

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)