diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2665e9d9..572e79e1 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 b7c83c0e..c8824c9a 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 b02f1b11..98b57047 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 2dcc6134..94348fbc 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 c225c305..f3791b2d 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 c716bd2c..c95f621a 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 77a97e73..6b64c014 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" ? (