Skip to content

Commit f8052df

Browse files
authored
Merge branch 'main' into bugfix/issue-114
2 parents 88ed9c0 + 98e6f0e commit f8052df

File tree

12 files changed

+235
-85
lines changed

12 files changed

+235
-85
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@v4
1616

17+
- name: Check formatting
18+
run: npx prettier --check .
19+
1720
- uses: actions/setup-node@v4
1821
with:
1922
node-version: 18

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
packages
22
server/build
3+
CODE_OF_CONDUCT.md
4+
SECURITY.md

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,20 @@ To inspect an MCP server implementation, there's no need to clone this repo. Ins
1414
npx @modelcontextprotocol/inspector build/index.js
1515
```
1616

17-
You can also pass arguments along which will get passed as arguments to your MCP server:
17+
You can pass both arguments and environment variables to your MCP server. Arguments are passed directly to your server, while environment variables can be set using the `-e` flag:
1818

19-
```
20-
npx @modelcontextprotocol/inspector build/index.js arg1 arg2 ...
19+
```bash
20+
# Pass arguments only
21+
npx @modelcontextprotocol/inspector build/index.js arg1 arg2
22+
23+
# Pass environment variables only
24+
npx @modelcontextprotocol/inspector -e KEY=value -e KEY2=$VALUE2 build/index.js
25+
26+
# Pass both environment variables and arguments
27+
npx @modelcontextprotocol/inspector -e KEY=value -e KEY2=$VALUE2 build/index.js arg1 arg2
28+
29+
# Use -- to separate inspector flags from server arguments
30+
npx @modelcontextprotocol/inspector -e KEY=$VALUE -- build/index.js -e server-flag
2131
```
2232

2333
The inspector runs both a client UI (default port 5173) and an MCP proxy server (default port 3000). Open the client UI in your browser to use the inspector. You can customize the ports if needed:

bin/cli.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,32 @@ function delay(ms) {
1111
}
1212

1313
async function main() {
14-
// Get command line arguments
15-
const [, , command, ...mcpServerArgs] = process.argv;
14+
// Parse command line arguments
15+
const args = process.argv.slice(2);
16+
const envVars = {};
17+
const mcpServerArgs = [];
18+
let command = null;
19+
let parsingFlags = true;
20+
21+
for (let i = 0; i < args.length; i++) {
22+
const arg = args[i];
23+
24+
if (parsingFlags && arg === "--") {
25+
parsingFlags = false;
26+
continue;
27+
}
28+
29+
if (parsingFlags && arg === "-e" && i + 1 < args.length) {
30+
const [key, value] = args[++i].split("=");
31+
if (key && value) {
32+
envVars[key] = value;
33+
}
34+
} else if (!command) {
35+
command = arg;
36+
} else {
37+
mcpServerArgs.push(arg);
38+
}
39+
}
1640

1741
const inspectorServerPath = resolve(
1842
__dirname,
@@ -52,7 +76,11 @@ async function main() {
5276
...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []),
5377
],
5478
{
55-
env: { ...process.env, PORT: SERVER_PORT },
79+
env: {
80+
...process.env,
81+
PORT: SERVER_PORT,
82+
MCP_ENV_VARS: JSON.stringify(envVars),
83+
},
5684
signal: abort.signal,
5785
echoOutput: true,
5886
},

client/src/App.tsx

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
ResourceTemplate,
1717
Root,
1818
ServerNotification,
19-
Tool
19+
Tool,
2020
} from "@modelcontextprotocol/sdk/types.js";
2121
import { useEffect, useRef, useState } from "react";
2222

@@ -124,10 +124,7 @@ const App = () => {
124124
const [nextToolCursor, setNextToolCursor] = useState<string | undefined>();
125125
const progressTokenRef = useRef(0);
126126

127-
const {
128-
height: historyPaneHeight,
129-
handleDragStart
130-
} = useDraggablePane(300);
127+
const { height: historyPaneHeight, handleDragStart } = useDraggablePane(300);
131128

132129
const {
133130
connectionStatus,
@@ -136,7 +133,7 @@ const App = () => {
136133
requestHistory,
137134
makeRequest: makeConnectionRequest,
138135
sendNotification,
139-
connect: connectMcpServer
136+
connect: connectMcpServer,
140137
} = useConnection({
141138
transportType,
142139
command,
@@ -145,18 +142,21 @@ const App = () => {
145142
env,
146143
proxyServerUrl: PROXY_SERVER_URL,
147144
onNotification: (notification) => {
148-
setNotifications(prev => [...prev, notification as ServerNotification]);
145+
setNotifications((prev) => [...prev, notification as ServerNotification]);
149146
},
150147
onStdErrNotification: (notification) => {
151-
setStdErrNotifications(prev => [...prev, notification as StdErrNotification]);
148+
setStdErrNotifications((prev) => [
149+
...prev,
150+
notification as StdErrNotification,
151+
]);
152152
},
153153
onPendingRequest: (request, resolve, reject) => {
154-
setPendingSampleRequests(prev => [
154+
setPendingSampleRequests((prev) => [
155155
...prev,
156-
{ id: nextRequestId.current++, request, resolve, reject }
156+
{ id: nextRequestId.current++, request, resolve, reject },
157157
]);
158158
},
159-
getRoots: () => rootsRef.current
159+
getRoots: () => rootsRef.current,
160160
});
161161

162162
const makeRequest = async <T extends z.ZodType>(
@@ -345,26 +345,40 @@ const App = () => {
345345
{mcpClient ? (
346346
<Tabs
347347
defaultValue={
348-
Object.keys(serverCapabilities ?? {}).includes(window.location.hash.slice(1)) ?
349-
window.location.hash.slice(1) :
350-
serverCapabilities?.resources ? "resources" :
351-
serverCapabilities?.prompts ? "prompts" :
352-
serverCapabilities?.tools ? "tools" :
353-
"ping"
348+
Object.keys(serverCapabilities ?? {}).includes(
349+
window.location.hash.slice(1),
350+
)
351+
? window.location.hash.slice(1)
352+
: serverCapabilities?.resources
353+
? "resources"
354+
: serverCapabilities?.prompts
355+
? "prompts"
356+
: serverCapabilities?.tools
357+
? "tools"
358+
: "ping"
354359
}
355360
className="w-full p-4"
356361
onValueChange={(value) => (window.location.hash = value)}
357362
>
358363
<TabsList className="mb-4 p-0">
359-
<TabsTrigger value="resources" disabled={!serverCapabilities?.resources}>
364+
<TabsTrigger
365+
value="resources"
366+
disabled={!serverCapabilities?.resources}
367+
>
360368
<Files className="w-4 h-4 mr-2" />
361369
Resources
362370
</TabsTrigger>
363-
<TabsTrigger value="prompts" disabled={!serverCapabilities?.prompts}>
371+
<TabsTrigger
372+
value="prompts"
373+
disabled={!serverCapabilities?.prompts}
374+
>
364375
<MessageSquare className="w-4 h-4 mr-2" />
365376
Prompts
366377
</TabsTrigger>
367-
<TabsTrigger value="tools" disabled={!serverCapabilities?.tools}>
378+
<TabsTrigger
379+
value="tools"
380+
disabled={!serverCapabilities?.tools}
381+
>
368382
<Hammer className="w-4 h-4 mr-2" />
369383
Tools
370384
</TabsTrigger>
@@ -388,7 +402,9 @@ const App = () => {
388402
</TabsList>
389403

390404
<div className="w-full">
391-
{!serverCapabilities?.resources && !serverCapabilities?.prompts && !serverCapabilities?.tools ? (
405+
{!serverCapabilities?.resources &&
406+
!serverCapabilities?.prompts &&
407+
!serverCapabilities?.tools ? (
392408
<div className="flex items-center justify-center p-4">
393409
<p className="text-lg text-gray-500">
394410
The connected server does not support any MCP capabilities

client/src/components/Sidebar.tsx

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { useState } from "react";
2-
import { Play, ChevronDown, ChevronRight, CircleHelp, Bug, Github } from "lucide-react";
2+
import {
3+
Play,
4+
ChevronDown,
5+
ChevronRight,
6+
CircleHelp,
7+
Bug,
8+
Github,
9+
Eye,
10+
EyeOff,
11+
} from "lucide-react";
312
import { Button } from "@/components/ui/button";
413
import { Input } from "@/components/ui/input";
514
import {
@@ -47,6 +56,7 @@ const Sidebar = ({
4756
}: SidebarProps) => {
4857
const [theme, setTheme] = useTheme();
4958
const [showEnvVars, setShowEnvVars] = useState(false);
59+
const [shownEnvVars, setShownEnvVars] = useState<Set<string>>(new Set());
5060

5161
return (
5262
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
@@ -127,20 +137,44 @@ const Sidebar = ({
127137
{showEnvVars && (
128138
<div className="space-y-2">
129139
{Object.entries(env).map(([key, value], idx) => (
130-
<div key={idx} className="grid grid-cols-[1fr,auto] gap-2">
131-
<div className="space-y-1">
140+
<div key={idx} className="space-y-2 pb-4">
141+
<div className="flex gap-2">
132142
<Input
133143
placeholder="Key"
134144
value={key}
135145
onChange={(e) => {
146+
const newKey = e.target.value;
136147
const newEnv = { ...env };
137148
delete newEnv[key];
138-
newEnv[e.target.value] = value;
149+
newEnv[newKey] = value;
139150
setEnv(newEnv);
151+
setShownEnvVars((prev) => {
152+
const next = new Set(prev);
153+
if (next.has(key)) {
154+
next.delete(key);
155+
next.add(newKey);
156+
}
157+
return next;
158+
});
140159
}}
141160
className="font-mono"
142161
/>
162+
<Button
163+
variant="destructive"
164+
size="icon"
165+
className="h-9 w-9 p-0 shrink-0"
166+
onClick={() => {
167+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
168+
const { [key]: _removed, ...rest } = env;
169+
setEnv(rest);
170+
}}
171+
>
172+
×
173+
</Button>
174+
</div>
175+
<div className="flex gap-2">
143176
<Input
177+
type={shownEnvVars.has(key) ? "text" : "password"}
144178
placeholder="Value"
145179
value={value}
146180
onChange={(e) => {
@@ -150,24 +184,45 @@ const Sidebar = ({
150184
}}
151185
className="font-mono"
152186
/>
187+
<Button
188+
variant="outline"
189+
size="icon"
190+
className="h-9 w-9 p-0 shrink-0"
191+
onClick={() => {
192+
setShownEnvVars((prev) => {
193+
const next = new Set(prev);
194+
if (next.has(key)) {
195+
next.delete(key);
196+
} else {
197+
next.add(key);
198+
}
199+
return next;
200+
});
201+
}}
202+
aria-label={
203+
shownEnvVars.has(key) ? "Hide value" : "Show value"
204+
}
205+
aria-pressed={shownEnvVars.has(key)}
206+
title={
207+
shownEnvVars.has(key) ? "Hide value" : "Show value"
208+
}
209+
>
210+
{shownEnvVars.has(key) ? (
211+
<Eye className="h-4 w-4" aria-hidden="true" />
212+
) : (
213+
<EyeOff className="h-4 w-4" aria-hidden="true" />
214+
)}
215+
</Button>
153216
</div>
154-
<Button
155-
variant="destructive"
156-
onClick={() => {
157-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
158-
const { [key]: removed, ...rest } = env;
159-
setEnv(rest);
160-
}}
161-
>
162-
Remove
163-
</Button>
164217
</div>
165218
))}
166219
<Button
167220
variant="outline"
221+
className="w-full mt-2"
168222
onClick={() => {
223+
const key = "";
169224
const newEnv = { ...env };
170-
newEnv[""] = "";
225+
newEnv[key] = "";
171226
setEnv(newEnv);
172227
}}
173228
>
@@ -243,18 +298,33 @@ const Sidebar = ({
243298
</Select>
244299

245300
<div className="flex items-center space-x-2">
246-
<a href="https://modelcontextprotocol.io/docs/tools/inspector" target="_blank" rel="noopener noreferrer">
301+
<a
302+
href="https://modelcontextprotocol.io/docs/tools/inspector"
303+
target="_blank"
304+
rel="noopener noreferrer"
305+
>
247306
<Button variant="ghost" title="Inspector Documentation">
248307
<CircleHelp className="w-4 h-4 text-gray-800" />
249308
</Button>
250309
</a>
251-
<a href="https://modelcontextprotocol.io/docs/tools/debugging" target="_blank" rel="noopener noreferrer">
310+
<a
311+
href="https://modelcontextprotocol.io/docs/tools/debugging"
312+
target="_blank"
313+
rel="noopener noreferrer"
314+
>
252315
<Button variant="ghost" title="Debugging Guide">
253316
<Bug className="w-4 h-4 text-gray-800" />
254317
</Button>
255318
</a>
256-
<a href="https://github.com/modelcontextprotocol/inspector" target="_blank" rel="noopener noreferrer">
257-
<Button variant="ghost" title="Report bugs or contribute on GitHub">
319+
<a
320+
href="https://github.com/modelcontextprotocol/inspector"
321+
target="_blank"
322+
rel="noopener noreferrer"
323+
>
324+
<Button
325+
variant="ghost"
326+
title="Report bugs or contribute on GitHub"
327+
>
258328
<Github className="w-4 h-4 text-gray-800" />
259329
</Button>
260330
</a>

client/src/components/ToolsTab.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,7 @@ const ToolsTab = ({
174174
}
175175
className="mt-1"
176176
/>
177-
) :
178-
/* @ts-expect-error value type is currently unknown */
177+
) : /* @ts-expect-error value type is currently unknown */
179178
value.type === "object" ? (
180179
<Textarea
181180
id={key}

0 commit comments

Comments
 (0)