@modelcontextprotocol/inspector 0.16.2 → 0.16.4

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
@@ -234,6 +234,78 @@ Example server configuration file:
234
234
  }
235
235
  ```
236
236
 
237
+ #### Transport Types in Config Files
238
+
239
+ The inspector automatically detects the transport type from your config file. You can specify different transport types:
240
+
241
+ **STDIO (default):**
242
+
243
+ ```json
244
+ {
245
+ "mcpServers": {
246
+ "my-stdio-server": {
247
+ "type": "stdio",
248
+ "command": "npx",
249
+ "args": ["@modelcontextprotocol/server-everything"]
250
+ }
251
+ }
252
+ }
253
+ ```
254
+
255
+ **SSE (Server-Sent Events):**
256
+
257
+ ```json
258
+ {
259
+ "mcpServers": {
260
+ "my-sse-server": {
261
+ "type": "sse",
262
+ "url": "http://localhost:3000/sse"
263
+ }
264
+ }
265
+ }
266
+ ```
267
+
268
+ **Streamable HTTP:**
269
+
270
+ ```json
271
+ {
272
+ "mcpServers": {
273
+ "my-http-server": {
274
+ "type": "streamable-http",
275
+ "url": "http://localhost:3000/mcp"
276
+ }
277
+ }
278
+ }
279
+ ```
280
+
281
+ #### Default Server Selection
282
+
283
+ You can launch the inspector without specifying a server name if your config has:
284
+
285
+ 1. **A single server** - automatically selected:
286
+
287
+ ```bash
288
+ # Automatically uses "my-server" if it's the only one
289
+ npx @modelcontextprotocol/inspector --config mcp.json
290
+ ```
291
+
292
+ 2. **A server named "default-server"** - automatically selected:
293
+
294
+ ```json
295
+ {
296
+ "mcpServers": {
297
+ "default-server": {
298
+ "command": "npx",
299
+ "args": ["@modelcontextprotocol/server-everything"]
300
+ },
301
+ "other-server": {
302
+ "command": "node",
303
+ "args": ["other.js"]
304
+ }
305
+ }
306
+ }
307
+ ```
308
+
237
309
  > **Tip:** You can easily generate this configuration format using the **Server Entry** and **Servers File** buttons in the Inspector UI, as described in the Servers File Export section above.
238
310
 
239
311
  You can also set the initial `transport` type, `serverUrl`, `serverCommand`, and `serverArgs` via query params, for example:
package/cli/build/cli.js CHANGED
@@ -38,6 +38,14 @@ async function runWebClient(args) {
38
38
  for (const [key, value] of Object.entries(args.envArgs)) {
39
39
  startArgs.push("-e", `${key}=${value}`);
40
40
  }
41
+ // Pass transport type if specified
42
+ if (args.transport) {
43
+ startArgs.push("--transport", args.transport);
44
+ }
45
+ // Pass server URL if specified
46
+ if (args.serverUrl) {
47
+ startArgs.push("--server-url", args.serverUrl);
48
+ }
41
49
  // Pass command and args (using -- to separate them)
42
50
  if (args.command) {
43
51
  startArgs.push("--", args.command, ...args.args);
@@ -63,7 +71,17 @@ async function runCli(args) {
63
71
  abort.abort();
64
72
  });
65
73
  try {
66
- await spawnPromise("node", [cliPath, args.command, ...args.args], {
74
+ // Build CLI arguments
75
+ const cliArgs = [cliPath];
76
+ // Add transport flag if specified
77
+ if (args.transport && args.transport !== "stdio") {
78
+ // Convert streamable-http back to http for CLI mode
79
+ const cliTransport = args.transport === "streamable-http" ? "http" : args.transport;
80
+ cliArgs.push("--transport", cliTransport);
81
+ }
82
+ // Add command and remaining args
83
+ cliArgs.push(args.command, ...args.args);
84
+ await spawnPromise("node", cliArgs, {
67
85
  env: { ...process.env, ...args.envArgs },
68
86
  signal: abort.signal,
69
87
  echoOutput: true,
@@ -124,38 +142,88 @@ function parseArgs() {
124
142
  .option("-e <env>", "environment variables in KEY=VALUE format", parseKeyValuePair, {})
125
143
  .option("--config <path>", "config file path")
126
144
  .option("--server <n>", "server name from config file")
127
- .option("--cli", "enable CLI mode");
145
+ .option("--cli", "enable CLI mode")
146
+ .option("--transport <type>", "transport type (stdio, sse, http)")
147
+ .option("--server-url <url>", "server URL for SSE/HTTP transport");
128
148
  // Parse only the arguments before --
129
149
  program.parse(preArgs);
130
150
  const options = program.opts();
131
151
  const remainingArgs = program.args;
132
152
  // Add back any arguments that came after --
133
153
  const finalArgs = [...remainingArgs, ...postArgs];
134
- // Validate that config and server are provided together
135
- if ((options.config && !options.server) ||
136
- (!options.config && options.server)) {
137
- throw new Error("Both --config and --server must be provided together. If you specify one, you must specify the other.");
154
+ // Validate config and server options
155
+ if (!options.config && options.server) {
156
+ throw new Error("--server requires --config to be specified");
157
+ }
158
+ // If config is provided without server, try to auto-select
159
+ if (options.config && !options.server) {
160
+ const configContent = fs.readFileSync(path.isAbsolute(options.config)
161
+ ? options.config
162
+ : path.resolve(process.cwd(), options.config), "utf8");
163
+ const parsedConfig = JSON.parse(configContent);
164
+ const servers = Object.keys(parsedConfig.mcpServers || {});
165
+ if (servers.length === 1) {
166
+ // Use the only server if there's just one
167
+ options.server = servers[0];
168
+ }
169
+ else if (servers.length === 0) {
170
+ throw new Error("No servers found in config file");
171
+ }
172
+ else {
173
+ // Multiple servers, require explicit selection
174
+ throw new Error(`Multiple servers found in config file. Please specify one with --server.\nAvailable servers: ${servers.join(", ")}`);
175
+ }
138
176
  }
139
177
  // If config file is specified, load and use the options from the file. We must merge the args
140
178
  // from the command line and the file together, or we will miss the method options (--method,
141
179
  // etc.)
142
180
  if (options.config && options.server) {
143
181
  const config = loadConfigFile(options.config, options.server);
144
- return {
145
- command: config.command,
146
- args: [...(config.args || []), ...finalArgs],
147
- envArgs: { ...(config.env || {}), ...(options.e || {}) },
148
- cli: options.cli || false,
149
- };
182
+ if (config.type === "stdio") {
183
+ return {
184
+ command: config.command,
185
+ args: [...(config.args || []), ...finalArgs],
186
+ envArgs: { ...(config.env || {}), ...(options.e || {}) },
187
+ cli: options.cli || false,
188
+ transport: "stdio",
189
+ };
190
+ }
191
+ else if (config.type === "sse" || config.type === "streamable-http") {
192
+ return {
193
+ command: config.url,
194
+ args: finalArgs,
195
+ envArgs: options.e || {},
196
+ cli: options.cli || false,
197
+ transport: config.type,
198
+ serverUrl: config.url,
199
+ };
200
+ }
201
+ else {
202
+ // Backwards compatibility: if no type field, assume stdio
203
+ return {
204
+ command: config.command || "",
205
+ args: [...(config.args || []), ...finalArgs],
206
+ envArgs: { ...(config.env || {}), ...(options.e || {}) },
207
+ cli: options.cli || false,
208
+ transport: "stdio",
209
+ };
210
+ }
150
211
  }
151
212
  // Otherwise use command line arguments
152
213
  const command = finalArgs[0] || "";
153
214
  const args = finalArgs.slice(1);
215
+ // Map "http" shorthand to "streamable-http"
216
+ let transport = options.transport;
217
+ if (transport === "http") {
218
+ transport = "streamable-http";
219
+ }
154
220
  return {
155
221
  command,
156
222
  args,
157
223
  envArgs: options.e || {},
158
224
  cli: options.cli || false,
225
+ transport: transport,
226
+ serverUrl: options.serverUrl,
159
227
  };
160
228
  }
161
229
  async function main() {
@@ -8,6 +8,11 @@ export const validLogLevels = [
8
8
  export async function connect(client, transport) {
9
9
  try {
10
10
  await client.connect(transport);
11
+ if (client.getServerCapabilities()?.logging) {
12
+ // default logging level is undefined in the spec, but the user of the
13
+ // inspector most likely wants debug.
14
+ await client.setLoggingLevel("debug");
15
+ }
11
16
  }
12
17
  catch (error) {
13
18
  throw new Error(`Failed to connect to MCP server: ${error instanceof Error ? error.message : String(error)}`);
@@ -28,8 +28,15 @@ function getClientUrl(port, authDisabled, sessionToken, serverPort) {
28
28
  }
29
29
 
30
30
  async function startDevServer(serverOptions) {
31
- const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } =
32
- serverOptions;
31
+ const {
32
+ SERVER_PORT,
33
+ CLIENT_PORT,
34
+ sessionToken,
35
+ envVars,
36
+ abort,
37
+ transport,
38
+ serverUrl,
39
+ } = serverOptions;
33
40
  const serverCommand = "npx";
34
41
  const serverArgs = ["tsx", "watch", "--clear-screen=false", "src/index.ts"];
35
42
  const isWindows = process.platform === "win32";
@@ -42,6 +49,8 @@ async function startDevServer(serverOptions) {
42
49
  CLIENT_PORT,
43
50
  MCP_PROXY_AUTH_TOKEN: sessionToken,
44
51
  MCP_ENV_VARS: JSON.stringify(envVars),
52
+ ...(transport ? { MCP_TRANSPORT: transport } : {}),
53
+ ...(serverUrl ? { MCP_SERVER_URL: serverUrl } : {}),
45
54
  },
46
55
  signal: abort.signal,
47
56
  echoOutput: true,
@@ -78,6 +87,8 @@ async function startProdServer(serverOptions) {
78
87
  abort,
79
88
  command,
80
89
  mcpServerArgs,
90
+ transport,
91
+ serverUrl,
81
92
  } = serverOptions;
82
93
  const inspectorServerPath = resolve(
83
94
  __dirname,
@@ -91,10 +102,12 @@ async function startProdServer(serverOptions) {
91
102
  "node",
92
103
  [
93
104
  inspectorServerPath,
94
- ...(command ? [`--command`, command] : []),
105
+ ...(command ? [`--command=${command}`] : []),
95
106
  ...(mcpServerArgs && mcpServerArgs.length > 0
96
- ? [`--args`, mcpServerArgs.join(" ")]
107
+ ? [`--args=${mcpServerArgs.join(" ")}`]
97
108
  : []),
109
+ ...(transport ? [`--transport=${transport}`] : []),
110
+ ...(serverUrl ? [`--server-url=${serverUrl}`] : []),
98
111
  ],
99
112
  {
100
113
  env: {
@@ -208,6 +221,8 @@ async function main() {
208
221
  let command = null;
209
222
  let parsingFlags = true;
210
223
  let isDev = false;
224
+ let transport = null;
225
+ let serverUrl = null;
211
226
 
212
227
  for (let i = 0; i < args.length; i++) {
213
228
  const arg = args[i];
@@ -222,6 +237,16 @@ async function main() {
222
237
  continue;
223
238
  }
224
239
 
240
+ if (parsingFlags && arg === "--transport" && i + 1 < args.length) {
241
+ transport = args[++i];
242
+ continue;
243
+ }
244
+
245
+ if (parsingFlags && arg === "--server-url" && i + 1 < args.length) {
246
+ serverUrl = args[++i];
247
+ continue;
248
+ }
249
+
225
250
  if (parsingFlags && arg === "-e" && i + 1 < args.length) {
226
251
  const envVar = args[++i];
227
252
  const equalsIndex = envVar.indexOf("=");
@@ -273,6 +298,8 @@ async function main() {
273
298
  abort,
274
299
  command,
275
300
  mcpServerArgs,
301
+ transport,
302
+ serverUrl,
276
303
  };
277
304
 
278
305
  const result = isDev
@@ -1,5 +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-DLtnCiTW.js";
2
- import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
1
+ import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-MFoeZZBS.js";
3
2
  const OAuthCallback = ({ onConnect }) => {
4
3
  const { toast } = useToast();
5
4
  const hasProcessedRef = reactExports.useRef(false);
@@ -1,5 +1,4 @@
1
- import { r as reactExports, S as SESSION_KEYS, j as jsxRuntimeExports } from "./index-DLtnCiTW.js";
2
- import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-MFoeZZBS.js";
3
2
  const OAuthDebugCallback = ({ onConnect }) => {
4
3
  reactExports.useEffect(() => {
5
4
  let isProcessed = false;
@@ -56,8 +56,6 @@ pre[class*="language-"] {
56
56
  -moz-tab-size: 4;
57
57
  -o-tab-size: 4;
58
58
  tab-size: 4;
59
-
60
- -webkit-hyphens: none;
61
59
  hyphens: none;
62
60
  }
63
61
 
@@ -1631,9 +1629,7 @@ video {
1631
1629
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
1632
1630
  }
1633
1631
  .transition {
1634
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
1635
1632
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
1636
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
1637
1633
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1638
1634
  transition-duration: 150ms;
1639
1635
  }