@modelcontextprotocol/inspector 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -168,20 +168,20 @@ DANGEROUSLY_OMIT_AUTH=true npm start
168
168
 
169
169
  #### Local-only Binding
170
170
 
171
- By default, the MCP Inspector proxy server binds only to `127.0.0.1` (localhost) to prevent network access. This ensures the server is not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable:
171
+ By default, both the MCP Inspector proxy server and client bind only to `localhost` to prevent network access. This ensures they are not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable:
172
172
 
173
173
  ```bash
174
174
  HOST=0.0.0.0 npm start
175
175
  ```
176
176
 
177
- **Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes.
177
+ **Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes and both services to network access.
178
178
 
179
179
  #### DNS Rebinding Protection
180
180
 
181
181
  To prevent DNS rebinding attacks, the MCP Inspector validates the `Origin` header on incoming requests. By default, only requests from the client origin are allowed (respects `CLIENT_PORT` if set, defaulting to port 6274). You can configure additional allowed origins by setting the `ALLOWED_ORIGINS` environment variable (comma-separated list):
182
182
 
183
183
  ```bash
184
- ALLOWED_ORIGINS=http://localhost:6274,http://127.0.0.1:6274,http://localhost:8000 npm start
184
+ ALLOWED_ORIGINS=http://localhost:6274,http://localhost:8000 npm start
185
185
  ```
186
186
 
187
187
  ### Configuration
@@ -254,6 +254,12 @@ Development mode:
254
254
 
255
255
  ```bash
256
256
  npm run dev
257
+
258
+ # To co-develop with the typescript-sdk package (assuming it's cloned in ../typescript-sdk; set MCP_SDK otherwise):
259
+ npm run dev:sdk "cd sdk && npm run examples:simple-server:w"
260
+ # then open http://localhost:3000/mcp as SHTTP in the inspector.
261
+ # To go back to the deployed SDK version:
262
+ # npm run unlink:sdk && npm i
257
263
  ```
258
264
 
259
265
  > **Note for Windows users:**
package/cli/build/cli.js CHANGED
@@ -24,50 +24,23 @@ function delay(ms) {
24
24
  return new Promise((resolve) => setTimeout(resolve, ms, true));
25
25
  }
26
26
  async function runWebClient(args) {
27
- const inspectorServerPath = resolve(__dirname, "../../", "server", "build", "index.js");
28
27
  // Path to the client entry point
29
- const inspectorClientPath = resolve(__dirname, "../../", "client", "bin", "client.js");
30
- const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
31
- const SERVER_PORT = process.env.SERVER_PORT ?? "6277";
32
- console.log("Starting MCP inspector...");
28
+ const inspectorClientPath = resolve(__dirname, "../../", "client", "bin", "start.js");
33
29
  const abort = new AbortController();
34
30
  let cancelled = false;
35
31
  process.on("SIGINT", () => {
36
32
  cancelled = true;
37
33
  abort.abort();
38
34
  });
39
- let server;
40
- let serverOk;
41
35
  try {
42
- server = spawnPromise("node", [
43
- inspectorServerPath,
44
- ...(args.command ? [`--env`, args.command] : []),
45
- ...(args.args ? [`--args=${args.args.join(" ")}`] : []),
46
- ], {
47
- env: {
48
- ...process.env,
49
- PORT: SERVER_PORT,
50
- MCP_ENV_VARS: JSON.stringify(args.envArgs),
51
- },
36
+ await spawnPromise("node", [inspectorClientPath], {
52
37
  signal: abort.signal,
53
38
  echoOutput: true,
54
39
  });
55
- // Make sure server started before starting client
56
- serverOk = await Promise.race([server, delay(2 * 1000)]);
57
40
  }
58
- catch (error) { }
59
- if (serverOk) {
60
- try {
61
- await spawnPromise("node", [inspectorClientPath], {
62
- env: { ...process.env, PORT: CLIENT_PORT },
63
- signal: abort.signal,
64
- echoOutput: true,
65
- });
66
- }
67
- catch (e) {
68
- if (!cancelled || process.env.DEBUG)
69
- throw e;
70
- }
41
+ catch (e) {
42
+ if (!cancelled || process.env.DEBUG)
43
+ throw e;
71
44
  }
72
45
  }
73
46
  async function runCli(args) {
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import open from "open";
3
4
  import { join, dirname } from "path";
4
5
  import { fileURLToPath } from "url";
5
6
  import handler from "serve-handler";
@@ -39,19 +40,23 @@ const server = http.createServer((request, response) => {
39
40
  return handler(request, response, handlerOptions);
40
41
  });
41
42
 
42
- const port = process.env.PORT || 6274;
43
+ const port = parseInt(process.env.CLIENT_PORT || "6274", 10);
44
+ const host = process.env.HOST || "localhost";
43
45
  server.on("listening", () => {
44
- console.log(
45
- `🔍 MCP Inspector is up and running at http://127.0.0.1:${port} 🚀`,
46
- );
46
+ const url = process.env.INSPECTOR_URL || `http://${host}:${port}`;
47
+ console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
48
+ if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
49
+ console.log(`🌐 Opening browser...`);
50
+ open(url);
51
+ }
47
52
  });
48
53
  server.on("error", (err) => {
49
54
  if (err.message.includes(`EADDRINUSE`)) {
50
55
  console.error(
51
- `❌ MCP Inspector PORT IS IN USE at http://127.0.0.1:${port} ❌ `,
56
+ `❌ MCP Inspector PORT IS IN USE at http://${host}:${port} ❌ `,
52
57
  );
53
58
  } else {
54
59
  throw err;
55
60
  }
56
61
  });
57
- server.listen(port);
62
+ server.listen(port, host);
@@ -7,11 +7,26 @@ import { fileURLToPath } from "url";
7
7
  import { randomBytes } from "crypto";
8
8
 
9
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
10
11
 
11
12
  function delay(ms) {
12
13
  return new Promise((resolve) => setTimeout(resolve, ms, true));
13
14
  }
14
15
 
16
+ function getClientUrl(port, authDisabled, sessionToken, serverPort) {
17
+ const host = process.env.HOST || "localhost";
18
+ const baseUrl = `http://${host}:${port}`;
19
+
20
+ const params = new URLSearchParams();
21
+ if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) {
22
+ params.set("MCP_PROXY_PORT", serverPort);
23
+ }
24
+ if (!authDisabled) {
25
+ params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
26
+ }
27
+ return params.size > 0 ? `${baseUrl}/?${params.toString()}` : baseUrl;
28
+ }
29
+
15
30
  async function startDevServer(serverOptions) {
16
31
  const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } =
17
32
  serverOptions;
@@ -23,8 +38,8 @@ async function startDevServer(serverOptions) {
23
38
  cwd: resolve(__dirname, "../..", "server"),
24
39
  env: {
25
40
  ...process.env,
26
- PORT: SERVER_PORT,
27
- CLIENT_PORT: CLIENT_PORT,
41
+ SERVER_PORT,
42
+ CLIENT_PORT,
28
43
  MCP_PROXY_TOKEN: sessionToken,
29
44
  MCP_ENV_VARS: JSON.stringify(envVars),
30
45
  },
@@ -82,8 +97,8 @@ async function startProdServer(serverOptions) {
82
97
  {
83
98
  env: {
84
99
  ...process.env,
85
- PORT: SERVER_PORT,
86
- CLIENT_PORT: CLIENT_PORT,
100
+ SERVER_PORT,
101
+ CLIENT_PORT,
87
102
  MCP_PROXY_TOKEN: sessionToken,
88
103
  MCP_ENV_VARS: JSON.stringify(envVars),
89
104
  },
@@ -99,30 +114,40 @@ async function startProdServer(serverOptions) {
99
114
  }
100
115
 
101
116
  async function startDevClient(clientOptions) {
102
- const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } =
103
- clientOptions;
117
+ const {
118
+ CLIENT_PORT,
119
+ SERVER_PORT,
120
+ authDisabled,
121
+ sessionToken,
122
+ abort,
123
+ cancelled,
124
+ } = clientOptions;
104
125
  const clientCommand = "npx";
105
- const clientArgs = ["vite", "--port", CLIENT_PORT];
126
+ const host = process.env.HOST || "localhost";
127
+ const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
106
128
 
107
129
  const client = spawn(clientCommand, clientArgs, {
108
130
  cwd: resolve(__dirname, ".."),
109
- env: { ...process.env, PORT: CLIENT_PORT },
131
+ env: { ...process.env, CLIENT_PORT },
110
132
  signal: abort.signal,
111
133
  echoOutput: true,
112
134
  });
113
135
 
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}`;
136
+ const url = getClientUrl(
137
+ CLIENT_PORT,
138
+ authDisabled,
139
+ sessionToken,
140
+ SERVER_PORT,
141
+ );
119
142
 
120
- // Give vite time to start before opening browser
121
- setTimeout(() => {
143
+ // Give vite time to start before opening or logging the URL
144
+ setTimeout(() => {
145
+ console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
146
+ if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
147
+ console.log("🌐 Opening browser...");
122
148
  open(url);
123
- console.log(`\n🔗 Opening browser at: ${url}\n`);
124
- }, 3000);
125
- }
149
+ }
150
+ }, 3000);
126
151
 
127
152
  await new Promise((resolve) => {
128
153
  client.subscribe({
@@ -139,7 +164,14 @@ async function startDevClient(clientOptions) {
139
164
  }
140
165
 
141
166
  async function startProdClient(clientOptions) {
142
- const { CLIENT_PORT, authDisabled, sessionToken, abort } = clientOptions;
167
+ const {
168
+ CLIENT_PORT,
169
+ SERVER_PORT,
170
+ authDisabled,
171
+ sessionToken,
172
+ abort,
173
+ cancelled,
174
+ } = clientOptions;
143
175
  const inspectorClientPath = resolve(
144
176
  __dirname,
145
177
  "../..",
@@ -148,16 +180,19 @@ async function startProdClient(clientOptions) {
148
180
  "client.js",
149
181
  );
150
182
 
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
- }
183
+ const url = getClientUrl(
184
+ CLIENT_PORT,
185
+ authDisabled,
186
+ sessionToken,
187
+ SERVER_PORT,
188
+ );
158
189
 
159
190
  await spawnPromise("node", [inspectorClientPath], {
160
- env: { ...process.env, PORT: CLIENT_PORT },
191
+ env: {
192
+ ...process.env,
193
+ CLIENT_PORT,
194
+ INSPECTOR_URL: url,
195
+ },
161
196
  signal: abort.signal,
162
197
  echoOutput: true,
163
198
  });
@@ -204,7 +239,7 @@ async function main() {
204
239
  }
205
240
 
206
241
  const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
207
- const SERVER_PORT = process.env.SERVER_PORT ?? "6277";
242
+ const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT;
208
243
 
209
244
  console.log(
210
245
  isDev
@@ -249,6 +284,7 @@ async function main() {
249
284
  try {
250
285
  const clientOptions = {
251
286
  CLIENT_PORT,
287
+ SERVER_PORT,
252
288
  authDisabled,
253
289
  sessionToken,
254
290
  abort,
@@ -1,4 +1,4 @@
1
- import { u as useToast, r as reactExports, j as jsxRuntimeExports, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-BNqYF5Na.js";
1
+ import { u as useToast, r as reactExports, j as jsxRuntimeExports, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-CPgI0-gs.js";
2
2
  import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
3
3
  const OAuthCallback = ({ onConnect }) => {
4
4
  const { toast } = useToast();
@@ -1,4 +1,4 @@
1
- import { r as reactExports, S as SESSION_KEYS, j as jsxRuntimeExports } from "./index-BNqYF5Na.js";
1
+ import { r as reactExports, S as SESSION_KEYS, j as jsxRuntimeExports } from "./index-CPgI0-gs.js";
2
2
  import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
3
3
  const OAuthDebugCallback = ({ onConnect }) => {
4
4
  reactExports.useEffect(() => {
@@ -1,7 +1,3 @@
1
- #root {
2
- margin: 0 auto;
3
- }
4
-
5
1
  .logo {
6
2
  height: 6em;
7
3
  padding: 1.5em;