@modelcontextprotocol/inspector-cli 0.16.5 → 0.16.7

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/build/cli.js CHANGED
@@ -54,6 +54,10 @@ async function runWebClient(args) {
54
54
  await spawnPromise("node", [inspectorClientPath, ...startArgs], {
55
55
  signal: abort.signal,
56
56
  echoOutput: true,
57
+ // pipe the stdout through here, prevents issues with buffering and
58
+ // dropping the end of console.out after 8192 chars due to node
59
+ // closing the stdout pipe before the output has finished flushing
60
+ stdio: "inherit",
57
61
  });
58
62
  }
59
63
  catch (e) {
@@ -73,18 +77,28 @@ async function runCli(args) {
73
77
  try {
74
78
  // Build CLI arguments
75
79
  const cliArgs = [cliPath];
80
+ // Add target URL/command first
81
+ cliArgs.push(args.command, ...args.args);
76
82
  // Add transport flag if specified
77
83
  if (args.transport && args.transport !== "stdio") {
78
84
  // Convert streamable-http back to http for CLI mode
79
85
  const cliTransport = args.transport === "streamable-http" ? "http" : args.transport;
80
86
  cliArgs.push("--transport", cliTransport);
81
87
  }
82
- // Add command and remaining args
83
- cliArgs.push(args.command, ...args.args);
88
+ // Add headers if specified
89
+ if (args.headers) {
90
+ for (const [key, value] of Object.entries(args.headers)) {
91
+ cliArgs.push("--header", `${key}: ${value}`);
92
+ }
93
+ }
84
94
  await spawnPromise("node", cliArgs, {
85
95
  env: { ...process.env, ...args.envArgs },
86
96
  signal: abort.signal,
87
97
  echoOutput: true,
98
+ // pipe the stdout through here, prevents issues with buffering and
99
+ // dropping the end of console.out after 8192 chars due to node
100
+ // closing the stdout pipe before the output has finished flushing
101
+ stdio: "inherit",
88
102
  });
89
103
  }
90
104
  catch (e) {
@@ -126,6 +140,18 @@ function parseKeyValuePair(value, previous = {}) {
126
140
  }
127
141
  return { ...previous, [key]: val };
128
142
  }
143
+ function parseHeaderPair(value, previous = {}) {
144
+ const colonIndex = value.indexOf(":");
145
+ if (colonIndex === -1) {
146
+ throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
147
+ }
148
+ const key = value.slice(0, colonIndex).trim();
149
+ const val = value.slice(colonIndex + 1).trim();
150
+ if (key === "" || val === "") {
151
+ throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
152
+ }
153
+ return { ...previous, [key]: val };
154
+ }
129
155
  function parseArgs() {
130
156
  const program = new Command();
131
157
  const argSeparatorIndex = process.argv.indexOf("--");
@@ -144,7 +170,8 @@ function parseArgs() {
144
170
  .option("--server <n>", "server name from config file")
145
171
  .option("--cli", "enable CLI mode")
146
172
  .option("--transport <type>", "transport type (stdio, sse, http)")
147
- .option("--server-url <url>", "server URL for SSE/HTTP transport");
173
+ .option("--server-url <url>", "server URL for SSE/HTTP transport")
174
+ .option("--header <headers...>", 'HTTP headers as "HeaderName: Value" pairs (for HTTP/SSE transports)', parseHeaderPair, {});
148
175
  // Parse only the arguments before --
149
176
  program.parse(preArgs);
150
177
  const options = program.opts();
@@ -186,6 +213,7 @@ function parseArgs() {
186
213
  envArgs: { ...(config.env || {}), ...(options.e || {}) },
187
214
  cli: options.cli || false,
188
215
  transport: "stdio",
216
+ headers: options.header,
189
217
  };
190
218
  }
191
219
  else if (config.type === "sse" || config.type === "streamable-http") {
@@ -196,6 +224,7 @@ function parseArgs() {
196
224
  cli: options.cli || false,
197
225
  transport: config.type,
198
226
  serverUrl: config.url,
227
+ headers: options.header,
199
228
  };
200
229
  }
201
230
  else {
@@ -206,6 +235,7 @@ function parseArgs() {
206
235
  envArgs: { ...(config.env || {}), ...(options.e || {}) },
207
236
  cli: options.cli || false,
208
237
  transport: "stdio",
238
+ headers: options.header,
209
239
  };
210
240
  }
211
241
  }
@@ -224,6 +254,7 @@ function parseArgs() {
224
254
  cli: options.cli || false,
225
255
  transport: transport,
226
256
  serverUrl: options.serverUrl,
257
+ headers: options.header,
227
258
  };
228
259
  }
229
260
  async function main() {
@@ -11,9 +11,24 @@ export async function listPrompts(client) {
11
11
  // Get a prompt
12
12
  export async function getPrompt(client, name, args) {
13
13
  try {
14
+ // Convert all arguments to strings for prompt arguments
15
+ const stringArgs = {};
16
+ if (args) {
17
+ for (const [key, value] of Object.entries(args)) {
18
+ if (typeof value === "string") {
19
+ stringArgs[key] = value;
20
+ }
21
+ else if (value === null || value === undefined) {
22
+ stringArgs[key] = String(value);
23
+ }
24
+ else {
25
+ stringArgs[key] = JSON.stringify(value);
26
+ }
27
+ }
28
+ }
14
29
  const response = await client.getPrompt({
15
30
  name,
16
- arguments: args || {},
31
+ arguments: stringArgs,
17
32
  });
18
33
  return response;
19
34
  }
@@ -49,8 +49,18 @@ export async function callTool(client, name, args) {
49
49
  const tool = tools.find((t) => t.name === name);
50
50
  let convertedArgs = args;
51
51
  if (tool) {
52
- // Convert parameters based on the tool's schema
53
- convertedArgs = convertParameters(tool, args);
52
+ // Convert parameters based on the tool's schema, but only for string values
53
+ // since we now accept pre-parsed values from the CLI
54
+ const stringArgs = {};
55
+ for (const [key, value] of Object.entries(args)) {
56
+ if (typeof value === "string") {
57
+ stringArgs[key] = value;
58
+ }
59
+ }
60
+ if (Object.keys(stringArgs).length > 0) {
61
+ const convertedStringArgs = convertParameters(tool, stringArgs);
62
+ convertedArgs = { ...args, ...convertedStringArgs };
63
+ }
54
64
  }
55
65
  const response = await client.callTool({
56
66
  name: name,
package/build/index.js CHANGED
@@ -4,7 +4,8 @@ import { Command } from "commander";
4
4
  import { callTool, connect, disconnect, getPrompt, listPrompts, listResources, listResourceTemplates, listTools, readResource, setLoggingLevel, validLogLevels, } from "./client/index.js";
5
5
  import { handleError } from "./error-handler.js";
6
6
  import { createTransport } from "./transport.js";
7
- function createTransportOptions(target, transport) {
7
+ import { awaitableLog } from "./utils/awaitable-log.js";
8
+ function createTransportOptions(target, transport, headers) {
8
9
  if (target.length === 0) {
9
10
  throw new Error("Target is required. Specify a URL or a command to execute.");
10
11
  }
@@ -46,10 +47,11 @@ function createTransportOptions(target, transport) {
46
47
  command: isUrl ? undefined : command,
47
48
  args: isUrl ? undefined : commandArgs,
48
49
  url: isUrl ? command : undefined,
50
+ headers,
49
51
  };
50
52
  }
51
53
  async function callMethod(args) {
52
- const transportOptions = createTransportOptions(args.target, args.transport);
54
+ const transportOptions = createTransportOptions(args.target, args.transport, args.headers);
53
55
  const transport = createTransport(transportOptions);
54
56
  const client = new Client({
55
57
  name: "inspector-cli",
@@ -101,7 +103,7 @@ async function callMethod(args) {
101
103
  else {
102
104
  throw new Error(`Unsupported method: ${args.method}. Supported methods include: tools/list, tools/call, resources/list, resources/read, resources/templates/list, prompts/list, prompts/get, logging/setLevel`);
103
105
  }
104
- console.log(JSON.stringify(result, null, 2));
106
+ await awaitableLog(JSON.stringify(result, null, 2));
105
107
  }
106
108
  finally {
107
109
  try {
@@ -119,6 +121,27 @@ function parseKeyValuePair(value, previous = {}) {
119
121
  if (val === undefined || val === "") {
120
122
  throw new Error(`Invalid parameter format: ${value}. Use key=value format.`);
121
123
  }
124
+ // Try to parse as JSON first
125
+ let parsedValue;
126
+ try {
127
+ parsedValue = JSON.parse(val);
128
+ }
129
+ catch {
130
+ // If JSON parsing fails, keep as string
131
+ parsedValue = val;
132
+ }
133
+ return { ...previous, [key]: parsedValue };
134
+ }
135
+ function parseHeaderPair(value, previous = {}) {
136
+ const colonIndex = value.indexOf(":");
137
+ if (colonIndex === -1) {
138
+ throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
139
+ }
140
+ const key = value.slice(0, colonIndex).trim();
141
+ const val = value.slice(colonIndex + 1).trim();
142
+ if (key === "" || val === "") {
143
+ throw new Error(`Invalid header format: ${value}. Use "HeaderName: Value" format.`);
144
+ }
122
145
  return { ...previous, [key]: val };
123
146
  }
124
147
  function parseArgs() {
@@ -171,7 +194,11 @@ function parseArgs() {
171
194
  throw new Error(`Invalid transport type: ${value}. Valid types are: ${validTransports.join(", ")}`);
172
195
  }
173
196
  return value;
174
- });
197
+ })
198
+ //
199
+ // HTTP headers
200
+ //
201
+ .option("--header <headers...>", 'HTTP headers as "HeaderName: Value" pairs (for HTTP/SSE transports)', parseHeaderPair, {});
175
202
  // Parse only the arguments before --
176
203
  program.parse(preArgs);
177
204
  const options = program.opts();
@@ -184,6 +211,7 @@ function parseArgs() {
184
211
  return {
185
212
  target: finalArgs,
186
213
  ...options,
214
+ headers: options.header, // commander.js uses 'header' field, map to 'headers'
187
215
  };
188
216
  }
189
217
  async function main() {
@@ -38,10 +38,24 @@ export function createTransport(options) {
38
38
  }
39
39
  const url = new URL(options.url);
40
40
  if (transportType === "sse") {
41
- return new SSEClientTransport(url);
41
+ const transportOptions = options.headers
42
+ ? {
43
+ requestInit: {
44
+ headers: options.headers,
45
+ },
46
+ }
47
+ : undefined;
48
+ return new SSEClientTransport(url, transportOptions);
42
49
  }
43
50
  if (transportType === "http") {
44
- return new StreamableHTTPClientTransport(url);
51
+ const transportOptions = options.headers
52
+ ? {
53
+ requestInit: {
54
+ headers: options.headers,
55
+ },
56
+ }
57
+ : undefined;
58
+ return new StreamableHTTPClientTransport(url, transportOptions);
45
59
  }
46
60
  throw new Error(`Unsupported transport type: ${transportType}`);
47
61
  }
@@ -0,0 +1,7 @@
1
+ export function awaitableLog(logValue) {
2
+ return new Promise((resolve) => {
3
+ process.stdout.write(logValue, () => {
4
+ resolve();
5
+ });
6
+ });
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelcontextprotocol/inspector-cli",
3
- "version": "0.16.5",
3
+ "version": "0.16.7",
4
4
  "description": "CLI for the Model Context Protocol inspector",
5
5
  "license": "MIT",
6
6
  "author": "Anthropic, PBC (https://anthropic.com)",
@@ -17,11 +17,14 @@
17
17
  "scripts": {
18
18
  "build": "tsc",
19
19
  "postbuild": "node scripts/make-executable.js",
20
- "test": "node scripts/cli-tests.js"
20
+ "test": "node scripts/cli-tests.js && node scripts/cli-tool-tests.js && node scripts/cli-header-tests.js",
21
+ "test:cli": "node scripts/cli-tests.js",
22
+ "test:cli-tools": "node scripts/cli-tool-tests.js",
23
+ "test:cli-headers": "node scripts/cli-header-tests.js"
21
24
  },
22
25
  "devDependencies": {},
23
26
  "dependencies": {
24
- "@modelcontextprotocol/sdk": "^1.17.3",
27
+ "@modelcontextprotocol/sdk": "^1.18.0",
25
28
  "commander": "^13.1.0",
26
29
  "spawn-rx": "^5.1.2"
27
30
  }