diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2665e9d..572e79e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Check formatting + run: npx prettier --check . + - uses: actions/setup-node@v4 with: node-version: 18 diff --git a/.prettierignore b/.prettierignore index b7c83c0..c8824c9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ packages server/build +CODE_OF_CONDUCT.md +SECURITY.md diff --git a/README.md b/README.md index b02f1b1..98b5704 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,20 @@ To inspect an MCP server implementation, there's no need to clone this repo. Ins npx @modelcontextprotocol/inspector build/index.js ``` -You can also pass arguments along which will get passed as arguments to your MCP server: +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: -``` -npx @modelcontextprotocol/inspector build/index.js arg1 arg2 ... +```bash +# Pass arguments only +npx @modelcontextprotocol/inspector build/index.js arg1 arg2 + +# Pass environment variables only +npx @modelcontextprotocol/inspector -e KEY=value -e KEY2=$VALUE2 build/index.js + +# Pass both environment variables and arguments +npx @modelcontextprotocol/inspector -e KEY=value -e KEY2=$VALUE2 build/index.js arg1 arg2 + +# Use -- to separate inspector flags from server arguments +npx @modelcontextprotocol/inspector -e KEY=$VALUE -- build/index.js -e server-flag ``` 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: diff --git a/bin/cli.js b/bin/cli.js index 2dcc613..94348fb 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -11,8 +11,32 @@ function delay(ms) { } async function main() { - // Get command line arguments - const [, , command, ...mcpServerArgs] = process.argv; + // Parse command line arguments + const args = process.argv.slice(2); + const envVars = {}; + const mcpServerArgs = []; + let command = null; + let parsingFlags = true; + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + if (parsingFlags && arg === "--") { + parsingFlags = false; + continue; + } + + if (parsingFlags && arg === "-e" && i + 1 < args.length) { + const [key, value] = args[++i].split("="); + if (key && value) { + envVars[key] = value; + } + } else if (!command) { + command = arg; + } else { + mcpServerArgs.push(arg); + } + } const inspectorServerPath = resolve( __dirname, @@ -52,7 +76,11 @@ async function main() { ...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []), ], { - env: { ...process.env, PORT: SERVER_PORT }, + env: { + ...process.env, + PORT: SERVER_PORT, + MCP_ENV_VARS: JSON.stringify(envVars), + }, signal: abort.signal, echoOutput: true, }, diff --git a/client/src/App.tsx b/client/src/App.tsx index c225c30..f3791b2 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -16,7 +16,7 @@ import { ResourceTemplate, Root, ServerNotification, - Tool + Tool, } from "@modelcontextprotocol/sdk/types.js"; import { useEffect, useRef, useState } from "react"; @@ -124,10 +124,7 @@ const App = () => { const [nextToolCursor, setNextToolCursor] = useState(); const progressTokenRef = useRef(0); - const { - height: historyPaneHeight, - handleDragStart - } = useDraggablePane(300); + const { height: historyPaneHeight, handleDragStart } = useDraggablePane(300); const { connectionStatus, @@ -136,7 +133,7 @@ const App = () => { requestHistory, makeRequest: makeConnectionRequest, sendNotification, - connect: connectMcpServer + connect: connectMcpServer, } = useConnection({ transportType, command, @@ -145,18 +142,21 @@ const App = () => { env, proxyServerUrl: PROXY_SERVER_URL, onNotification: (notification) => { - setNotifications(prev => [...prev, notification as ServerNotification]); + setNotifications((prev) => [...prev, notification as ServerNotification]); }, onStdErrNotification: (notification) => { - setStdErrNotifications(prev => [...prev, notification as StdErrNotification]); - }, - onPendingRequest: (request, resolve, reject) => { - setPendingSampleRequests(prev => [ + setStdErrNotifications((prev) => [ ...prev, - { id: nextRequestId.current++, request, resolve, reject } + notification as StdErrNotification, ]); }, - getRoots: () => rootsRef.current + onPendingRequest: (request, resolve, reject) => { + setPendingSampleRequests((prev) => [ + ...prev, + { id: nextRequestId.current++, request, resolve, reject }, + ]); + }, + getRoots: () => rootsRef.current, }); const makeRequest = async ( @@ -345,26 +345,40 @@ const App = () => { {mcpClient ? ( (window.location.hash = value)} > - + Resources - + Prompts - + Tools @@ -388,7 +402,9 @@ const App = () => {
- {!serverCapabilities?.resources && !serverCapabilities?.prompts && !serverCapabilities?.tools ? ( + {!serverCapabilities?.resources && + !serverCapabilities?.prompts && + !serverCapabilities?.tools ? (

The connected server does not support any MCP capabilities diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx index c716bd2..c95f621 100644 --- a/client/src/components/Sidebar.tsx +++ b/client/src/components/Sidebar.tsx @@ -1,5 +1,14 @@ import { useState } from "react"; -import { Play, ChevronDown, ChevronRight, CircleHelp, Bug, Github } from "lucide-react"; +import { + Play, + ChevronDown, + ChevronRight, + CircleHelp, + Bug, + Github, + Eye, + EyeOff, +} from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { @@ -47,6 +56,7 @@ const Sidebar = ({ }: SidebarProps) => { const [theme, setTheme] = useTheme(); const [showEnvVars, setShowEnvVars] = useState(false); + const [shownEnvVars, setShownEnvVars] = useState>(new Set()); return (

@@ -127,20 +137,44 @@ const Sidebar = ({ {showEnvVars && (
{Object.entries(env).map(([key, value], idx) => ( -
-
+
+
{ + const newKey = e.target.value; const newEnv = { ...env }; delete newEnv[key]; - newEnv[e.target.value] = value; + newEnv[newKey] = value; setEnv(newEnv); + setShownEnvVars((prev) => { + const next = new Set(prev); + if (next.has(key)) { + next.delete(key); + next.add(newKey); + } + return next; + }); }} className="font-mono" /> + +
+
{ @@ -150,24 +184,45 @@ const Sidebar = ({ }} className="font-mono" /> +
-
))} - + - - diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 77a97e7..6b64c01 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -174,8 +174,7 @@ const ToolsTab = ({ } className="mt-1" /> - ) : - /* @ts-expect-error value type is currently unknown */ + ) : /* @ts-expect-error value type is currently unknown */ value.type === "object" ? (