Skip to content

Commit

Permalink
allow passing env vars to server from command line
Browse files Browse the repository at this point in the history
  • Loading branch information
ashwin-ant committed Jan 9, 2025
1 parent 1797fbf commit 1db609c
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 24 deletions.
26 changes: 23 additions & 3 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,24 @@ 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;

for (let i = 0; i < args.length; i++) {
if (args[i] === "-e" && i + 1 < args.length) {
const [key, value] = args[++i].split("=");
if (key && value) {
envVars[key] = value;
}
} else if (!command) {
command = args[i];
} else {
mcpServerArgs.push(args[i]);
}
}

const inspectorServerPath = resolve(
__dirname,
Expand Down Expand Up @@ -52,7 +68,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,
},
Expand Down
93 changes: 74 additions & 19 deletions client/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { useState } from "react";
import { Play, ChevronDown, ChevronRight, CircleHelp, Bug, Github } from "lucide-react";
import {
Play,
ChevronDown,
ChevronRight,
Bug,
CircleHelp,
Github,
Eye,
EyeOff,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Expand Down Expand Up @@ -47,6 +56,7 @@ const Sidebar = ({
}: SidebarProps) => {
const [theme, setTheme] = useTheme();
const [showEnvVars, setShowEnvVars] = useState(false);
const [shownEnvVars, setShownEnvVars] = useState<Record<string, boolean>>({});

return (
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
Expand Down Expand Up @@ -127,20 +137,40 @@ const Sidebar = ({
{showEnvVars && (
<div className="space-y-2">
{Object.entries(env).map(([key, value], idx) => (
<div key={idx} className="grid grid-cols-[1fr,auto] gap-2">
<div className="space-y-1">
<div key={idx} className="space-y-2 pb-4">
<div className="flex gap-2">
<Input
placeholder="Key"
value={key}
onChange={(e) => {
const newKey = e.target.value;
const newEnv = { ...env };
delete newEnv[key];
newEnv[e.target.value] = value;
newEnv[newKey] = value;
setEnv(newEnv);
setShownEnvVars((prev) => {
const { [key]: shown, ...rest } = prev;
return shown ? { ...rest, [newKey]: true } : rest;
});
}}
className="font-mono"
/>
<Button
variant="destructive"
size="icon"
className="h-9 w-9 p-0 shrink-0"
onClick={() => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [key]: _removed, ...rest } = env;
setEnv(rest);
}}
>
×
</Button>
</div>
<div className="flex gap-2">
<Input
type={shownEnvVars[key] ? "text" : "password"}
placeholder="Value"
value={value}
onChange={(e) => {
Expand All @@ -150,25 +180,35 @@ const Sidebar = ({
}}
className="font-mono"
/>
<Button
variant="outline"
size="icon"
className="h-9 w-9 p-0 shrink-0"
onClick={() => {
setShownEnvVars((prev) => ({
...prev,
[key]: !prev[key],
}));
}}
>
{shownEnvVars[key] ? (
<Eye className="h-4 w-4" />
) : (
<EyeOff className="h-4 w-4" />
)}
</Button>
</div>
<Button
variant="destructive"
onClick={() => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [key]: removed, ...rest } = env;
setEnv(rest);
}}
>
Remove
</Button>
</div>
))}
<Button
variant="outline"
className="w-full mt-2"
onClick={() => {
const key = "";
const newEnv = { ...env };
newEnv[""] = "";
newEnv[key] = "";
setEnv(newEnv);
setShownEnvVars({});
}}
>
Add Environment Variable
Expand Down Expand Up @@ -243,18 +283,33 @@ const Sidebar = ({
</Select>

<div className="flex items-center space-x-2">
<a href="https://modelcontextprotocol.io/docs/tools/inspector" target="_blank" rel="noopener noreferrer">
<a
href="https://modelcontextprotocol.io/docs/tools/inspector"
target="_blank"
rel="noopener noreferrer"
>
<Button variant="ghost" title="Inspector Documentation">
<CircleHelp className="w-4 h-4 text-gray-800" />
</Button>
</a>
<a href="https://modelcontextprotocol.io/docs/tools/debugging" target="_blank" rel="noopener noreferrer">
<a
href="https://modelcontextprotocol.io/docs/tools/debugging"
target="_blank"
rel="noopener noreferrer"
>
<Button variant="ghost" title="Debugging Guide">
<Bug className="w-4 h-4 text-gray-800" />
</Button>
</a>
<a href="https://github.com/modelcontextprotocol/inspector" target="_blank" rel="noopener noreferrer">
<Button variant="ghost" title="Report bugs or contribute on GitHub">
<a
href="https://github.com/modelcontextprotocol/inspector"
target="_blank"
rel="noopener noreferrer"
>
<Button
variant="ghost"
title="Report bugs or contribute on GitHub"
>
<Github className="w-4 h-4 text-gray-800" />
</Button>
</a>
Expand Down
14 changes: 12 additions & 2 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import express from "express";
import mcpProxy from "./mcpProxy.js";
import { findActualExecutable } from "spawn-rx";

const defaultEnvironment = {
...getDefaultEnvironment(),
...(process.env.MCP_ENV_VARS ? JSON.parse(process.env.MCP_ENV_VARS) : {}),
};

// Polyfill EventSource for an SSE client in Node.js
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(global as any).EventSource = EventSource;
Expand All @@ -40,7 +45,8 @@ const createTransport = async (query: express.Request["query"]) => {
if (transportType === "stdio") {
const command = query.command as string;
const origArgs = shellParseArgs(query.args as string) as string[];
const env = query.env ? JSON.parse(query.env as string) : undefined;
const queryEnv = query.env ? JSON.parse(query.env as string) : {};
const env = { ...process.env, ...defaultEnvironment, ...queryEnv };

const { cmd, args } = findActualExecutable(command, origArgs);

Expand Down Expand Up @@ -136,7 +142,11 @@ app.post("/message", async (req, res) => {

app.get("/config", (req, res) => {
try {
const defaultEnvironment = getDefaultEnvironment();
res.json({
defaultEnvironment,
defaultCommand: values.env,
defaultArgs: values.args,
});

res.json({
defaultEnvironment,
Expand Down

0 comments on commit 1db609c

Please sign in to comment.