Skip to content

Commit a715d18

Browse files
Merge branch 'main' into notification-expansion-state
2 parents 78eaa17 + a7336cd commit a715d18

File tree

8 files changed

+228
-78
lines changed

8 files changed

+228
-78
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ The MCP Inspector proxy server requires authentication by default. When starting
148148
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=3a1c267fad21f7150b7d624c160b7f09b0b8c4f623c7107bbf13378f051538d4
149149
```
150150

151-
This token must be included as a Bearer token in the Authorization header for all requests to the server. When authentication is enabled, auto-open is disabled by default to ensure you use the secure URL.
151+
This token must be included as a Bearer token in the Authorization header for all requests to the server. The inspector will automatically open your browser with the token pre-filled in the URL.
152152

153-
**Recommended: Use the pre-filled URL** - Click or copy the link shown in the console to open the inspector with the token already configured.
153+
**Automatic browser opening** - The inspector now automatically opens your browser with the token pre-filled in the URL when authentication is enabled.
154154

155155
**Alternative: Manual configuration** - If you already have the inspector open:
156156

@@ -188,13 +188,13 @@ ALLOWED_ORIGINS=http://localhost:6274,http://127.0.0.1:6274,http://localhost:800
188188

189189
The MCP Inspector supports the following configuration settings. To change them, click on the `Configuration` button in the MCP Inspector UI:
190190

191-
| Setting | Description | Default |
192-
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------- |
193-
| `MCP_SERVER_REQUEST_TIMEOUT` | Timeout for requests to the MCP server (ms) | 10000 |
194-
| `MCP_REQUEST_TIMEOUT_RESET_ON_PROGRESS` | Reset timeout on progress notifications | true |
195-
| `MCP_REQUEST_MAX_TOTAL_TIMEOUT` | Maximum total timeout for requests sent to the MCP server (ms) (Use with progress notifications) | 60000 |
196-
| `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 | "" |
197-
| `MCP_AUTO_OPEN_ENABLED` | Enable automatic browser opening when inspector starts. Only as environment var, not configurable in browser. | true |
191+
| Setting | Description | Default |
192+
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
193+
| `MCP_SERVER_REQUEST_TIMEOUT` | Timeout for requests to the MCP server (ms) | 10000 |
194+
| `MCP_REQUEST_TIMEOUT_RESET_ON_PROGRESS` | Reset timeout on progress notifications | true |
195+
| `MCP_REQUEST_MAX_TOTAL_TIMEOUT` | Maximum total timeout for requests sent to the MCP server (ms) (Use with progress notifications) | 60000 |
196+
| `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 | "" |
197+
| `MCP_AUTO_OPEN_ENABLED` | Enable automatic browser opening when inspector starts (works with authentication enabled). Only as environment var, not configurable in browser. | true |
198198

199199
These settings can be adjusted in real-time through the UI and will persist across sessions.
200200

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-cli",
3-
"version": "0.14.2",
3+
"version": "0.14.3",
44
"description": "CLI for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",

client/bin/start.js

Lines changed: 198 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,175 @@
22

33
import open from "open";
44
import { resolve, dirname } from "path";
5-
import { spawnPromise } from "spawn-rx";
5+
import { spawnPromise, spawn } from "spawn-rx";
66
import { fileURLToPath } from "url";
7+
import { randomBytes } from "crypto";
78

89
const __dirname = dirname(fileURLToPath(import.meta.url));
910

1011
function delay(ms) {
1112
return new Promise((resolve) => setTimeout(resolve, ms, true));
1213
}
1314

15+
async function startDevServer(serverOptions) {
16+
const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } =
17+
serverOptions;
18+
const serverCommand = "npx";
19+
const serverArgs = ["tsx", "watch", "--clear-screen=false", "src/index.ts"];
20+
const isWindows = process.platform === "win32";
21+
22+
const spawnOptions = {
23+
cwd: resolve(__dirname, "../..", "server"),
24+
env: {
25+
...process.env,
26+
PORT: SERVER_PORT,
27+
CLIENT_PORT: CLIENT_PORT,
28+
MCP_PROXY_TOKEN: sessionToken,
29+
MCP_ENV_VARS: JSON.stringify(envVars),
30+
},
31+
signal: abort.signal,
32+
echoOutput: true,
33+
};
34+
35+
// For Windows, we need to use stdin: 'ignore' to simulate < NUL
36+
if (isWindows) {
37+
spawnOptions.stdin = "ignore";
38+
}
39+
40+
const server = spawn(serverCommand, serverArgs, spawnOptions);
41+
42+
// Give server time to start
43+
const serverOk = await Promise.race([
44+
new Promise((resolve) => {
45+
server.subscribe({
46+
complete: () => resolve(false),
47+
error: () => resolve(false),
48+
next: () => {}, // We're using echoOutput
49+
});
50+
}),
51+
delay(3000).then(() => true),
52+
]);
53+
54+
return { server, serverOk };
55+
}
56+
57+
async function startProdServer(serverOptions) {
58+
const {
59+
SERVER_PORT,
60+
CLIENT_PORT,
61+
sessionToken,
62+
envVars,
63+
abort,
64+
command,
65+
mcpServerArgs,
66+
} = serverOptions;
67+
const inspectorServerPath = resolve(
68+
__dirname,
69+
"../..",
70+
"server",
71+
"build",
72+
"index.js",
73+
);
74+
75+
const server = spawnPromise(
76+
"node",
77+
[
78+
inspectorServerPath,
79+
...(command ? [`--env`, command] : []),
80+
...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []),
81+
],
82+
{
83+
env: {
84+
...process.env,
85+
PORT: SERVER_PORT,
86+
CLIENT_PORT: CLIENT_PORT,
87+
MCP_PROXY_TOKEN: sessionToken,
88+
MCP_ENV_VARS: JSON.stringify(envVars),
89+
},
90+
signal: abort.signal,
91+
echoOutput: true,
92+
},
93+
);
94+
95+
// Make sure server started before starting client
96+
const serverOk = await Promise.race([server, delay(2 * 1000)]);
97+
98+
return { server, serverOk };
99+
}
100+
101+
async function startDevClient(clientOptions) {
102+
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } =
103+
clientOptions;
104+
const clientCommand = "npx";
105+
const clientArgs = ["vite", "--port", CLIENT_PORT];
106+
107+
const client = spawn(clientCommand, clientArgs, {
108+
cwd: resolve(__dirname, ".."),
109+
env: { ...process.env, PORT: CLIENT_PORT },
110+
signal: abort.signal,
111+
echoOutput: true,
112+
});
113+
114+
// Auto-open browser after vite starts
115+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
116+
const url = authDisabled
117+
? `http://127.0.0.1:${CLIENT_PORT}`
118+
: `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
119+
120+
// Give vite time to start before opening browser
121+
setTimeout(() => {
122+
open(url);
123+
console.log(`\n🔗 Opening browser at: ${url}\n`);
124+
}, 3000);
125+
}
126+
127+
await new Promise((resolve) => {
128+
client.subscribe({
129+
complete: resolve,
130+
error: (err) => {
131+
if (!cancelled || process.env.DEBUG) {
132+
console.error("Client error:", err);
133+
}
134+
resolve(null);
135+
},
136+
next: () => {}, // We're using echoOutput
137+
});
138+
});
139+
}
140+
141+
async function startProdClient(clientOptions) {
142+
const { CLIENT_PORT, authDisabled, sessionToken, abort } = clientOptions;
143+
const inspectorClientPath = resolve(
144+
__dirname,
145+
"../..",
146+
"client",
147+
"bin",
148+
"client.js",
149+
);
150+
151+
// Auto-open browser with token
152+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
153+
const url = authDisabled
154+
? `http://127.0.0.1:${CLIENT_PORT}`
155+
: `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
156+
open(url);
157+
}
158+
159+
await spawnPromise("node", [inspectorClientPath], {
160+
env: { ...process.env, PORT: CLIENT_PORT },
161+
signal: abort.signal,
162+
echoOutput: true,
163+
});
164+
}
165+
14166
async function main() {
15167
// Parse command line arguments
16168
const args = process.argv.slice(2);
17169
const envVars = {};
18170
const mcpServerArgs = [];
19171
let command = null;
20172
let parsingFlags = true;
173+
let isDev = false;
21174

22175
for (let i = 0; i < args.length; i++) {
23176
const arg = args[i];
@@ -27,6 +180,11 @@ async function main() {
27180
continue;
28181
}
29182

183+
if (parsingFlags && arg === "--dev") {
184+
isDev = true;
185+
continue;
186+
}
187+
30188
if (parsingFlags && arg === "-e" && i + 1 < args.length) {
31189
const envVar = args[++i];
32190
const equalsIndex = envVar.indexOf("=");
@@ -38,34 +196,25 @@ async function main() {
38196
} else {
39197
envVars[envVar] = "";
40198
}
41-
} else if (!command) {
199+
} else if (!command && !isDev) {
42200
command = arg;
43-
} else {
201+
} else if (!isDev) {
44202
mcpServerArgs.push(arg);
45203
}
46204
}
47205

48-
const inspectorServerPath = resolve(
49-
__dirname,
50-
"../..",
51-
"server",
52-
"build",
53-
"index.js",
54-
);
55-
56-
// Path to the client entry point
57-
const inspectorClientPath = resolve(
58-
__dirname,
59-
"../..",
60-
"client",
61-
"bin",
62-
"client.js",
63-
);
64-
65206
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
66207
const SERVER_PORT = process.env.SERVER_PORT ?? "6277";
67208

68-
console.log("Starting MCP inspector...");
209+
console.log(
210+
isDev
211+
? "Starting MCP inspector in development mode..."
212+
: "Starting MCP inspector...",
213+
);
214+
215+
// Generate session token for authentication
216+
const sessionToken = randomBytes(32).toString("hex");
217+
const authDisabled = !!process.env.DANGEROUSLY_OMIT_AUTH;
69218

70219
const abort = new AbortController();
71220

@@ -74,42 +223,41 @@ async function main() {
74223
cancelled = true;
75224
abort.abort();
76225
});
226+
77227
let server, serverOk;
228+
78229
try {
79-
server = spawnPromise(
80-
"node",
81-
[
82-
inspectorServerPath,
83-
...(command ? [`--env`, command] : []),
84-
...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []),
85-
],
86-
{
87-
env: {
88-
...process.env,
89-
PORT: SERVER_PORT,
90-
MCP_ENV_VARS: JSON.stringify(envVars),
91-
},
92-
signal: abort.signal,
93-
echoOutput: true,
94-
},
95-
);
230+
const serverOptions = {
231+
SERVER_PORT,
232+
CLIENT_PORT,
233+
sessionToken,
234+
envVars,
235+
abort,
236+
command,
237+
mcpServerArgs,
238+
};
96239

97-
// Make sure server started before starting client
98-
serverOk = await Promise.race([server, delay(2 * 1000)]);
240+
const result = isDev
241+
? await startDevServer(serverOptions)
242+
: await startProdServer(serverOptions);
243+
244+
server = result.server;
245+
serverOk = result.serverOk;
99246
} catch (error) {}
100247

101248
if (serverOk) {
102249
try {
103-
// Only auto-open when auth is disabled
104-
const authDisabled = !!process.env.DANGEROUSLY_OMIT_AUTH;
105-
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false" && authDisabled) {
106-
open(`http://127.0.0.1:${CLIENT_PORT}`);
107-
}
108-
await spawnPromise("node", [inspectorClientPath], {
109-
env: { ...process.env, PORT: CLIENT_PORT },
110-
signal: abort.signal,
111-
echoOutput: true,
112-
});
250+
const clientOptions = {
251+
CLIENT_PORT,
252+
authDisabled,
253+
sessionToken,
254+
abort,
255+
cancelled,
256+
};
257+
258+
await (isDev
259+
? startDevClient(clientOptions)
260+
: startProdClient(clientOptions));
113261
} catch (e) {
114262
if (!cancelled || process.env.DEBUG) throw e;
115263
}

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-client",
3-
"version": "0.14.2",
3+
"version": "0.14.3",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",

0 commit comments

Comments
 (0)