@modelcontextprotocol/inspector 2.0.0 → 2.1.0

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.
@@ -422,9 +422,13 @@ function loadMcpServersConfig(configPath, writable) {
422
422
  return { ...config, mcpServers: normalizedServers };
423
423
  } catch (error) {
424
424
  if (error instanceof Error) {
425
- throw new Error(`Error loading configuration: ${error.message}`);
425
+ throw new Error(`Error loading configuration: ${error.message}`, {
426
+ cause: error
427
+ });
426
428
  }
427
- throw new Error("Error loading configuration: Unknown error");
429
+ throw new Error("Error loading configuration: Unknown error", {
430
+ cause: error
431
+ });
428
432
  }
429
433
  }
430
434
  function loadServerFromConfig(configPath, serverName, writable) {
@@ -994,7 +998,9 @@ function parseHttpUrl(value, label) {
994
998
  return new URL(trimmed);
995
999
  } catch (err) {
996
1000
  const detail = err instanceof Error ? err.message : String(err);
997
- throw new Error(`Invalid ${label}: "${trimmed}" (${detail})`);
1001
+ throw new Error(`Invalid ${label}: "${trimmed}" (${detail})`, {
1002
+ cause: err
1003
+ });
998
1004
  }
999
1005
  }
1000
1006
  var parseOAuthCallbackParams = (location) => {
@@ -1734,7 +1740,7 @@ function parseRunnerOAuthCallbackUrl(cliCallbackUrl) {
1734
1740
  url = new URL(raw);
1735
1741
  } catch (err) {
1736
1742
  const reason = err?.message ?? String(err);
1737
- throw new Error(`Invalid OAuth callback URL: ${reason}`);
1743
+ throw new Error(`Invalid OAuth callback URL: ${reason}`, { cause: err });
1738
1744
  }
1739
1745
  if (url.protocol !== "http:") {
1740
1746
  throw new Error("OAuth callback URL must use http scheme");
@@ -1779,6 +1785,7 @@ import { Client } from "@modelcontextprotocol/client";
1779
1785
 
1780
1786
  // ../../core/json/xMcpHeader.ts
1781
1787
  var X_MCP_HEADER_KEY = "x-mcp-header";
1788
+ var MCP_PARAM_HEADER_PREFIX = "Mcp-Param-";
1782
1789
  var RFC9110_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
1783
1790
  var PERMITTED_X_MCP_HEADER_TYPES = /* @__PURE__ */ new Set([
1784
1791
  "string",
@@ -1868,6 +1875,66 @@ function scanXMcpHeaderDeclarations(inputSchema) {
1868
1875
  const fault = visit(inputSchema, [], true);
1869
1876
  return fault === void 0 ? { valid: true, declarations } : { valid: false, reason: fault };
1870
1877
  }
1878
+ var BASE64_SENTINEL_PREFIX = "=?base64?";
1879
+ var BASE64_SENTINEL_SUFFIX = "?=";
1880
+ function mcpParamPrimitiveToString(value) {
1881
+ if (typeof value === "string") return value;
1882
+ if (typeof value === "boolean") return value ? "true" : "false";
1883
+ if (typeof value === "number") {
1884
+ if (!Number.isFinite(value)) return void 0;
1885
+ if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
1886
+ return void 0;
1887
+ }
1888
+ return String(value);
1889
+ }
1890
+ return void 0;
1891
+ }
1892
+ function needsBase64(s) {
1893
+ if (s.length === 0) return true;
1894
+ if (s.startsWith(BASE64_SENTINEL_PREFIX) && s.endsWith(BASE64_SENTINEL_SUFFIX)) {
1895
+ return true;
1896
+ }
1897
+ if (s !== s.trim()) return true;
1898
+ for (let i = 0; i < s.length; i++) {
1899
+ const c = s.codePointAt(i);
1900
+ if (c === 9 || c >= 32 && c <= 126) continue;
1901
+ return true;
1902
+ }
1903
+ return false;
1904
+ }
1905
+ function utf8ToBase64(s) {
1906
+ const bytes = new TextEncoder().encode(s);
1907
+ let bin = "";
1908
+ for (const b of bytes) bin += String.fromCodePoint(b);
1909
+ return btoa(bin);
1910
+ }
1911
+ function encodeMcpParamValue(value) {
1912
+ return needsBase64(value) ? `${BASE64_SENTINEL_PREFIX}${utf8ToBase64(value)}${BASE64_SENTINEL_SUFFIX}` : value;
1913
+ }
1914
+ function valueAtPath(root, path3) {
1915
+ let node = root;
1916
+ for (const key of path3) {
1917
+ if (node === null || typeof node !== "object") return void 0;
1918
+ node = node[key];
1919
+ }
1920
+ return node;
1921
+ }
1922
+ function buildMcpParamHeaders(declarations, args) {
1923
+ const out = {};
1924
+ for (const decl of declarations) {
1925
+ const raw = valueAtPath(args, decl.path);
1926
+ if (raw === void 0 || raw === null) continue;
1927
+ const stringValue = mcpParamPrimitiveToString(raw);
1928
+ if (stringValue === void 0) continue;
1929
+ out[`${MCP_PARAM_HEADER_PREFIX}${decl.headerName}`] = encodeMcpParamValue(stringValue);
1930
+ }
1931
+ return out;
1932
+ }
1933
+ function mcpParamHeadersForTool(tool, args) {
1934
+ const scan = scanXMcpHeaderDeclarations(tool.inputSchema);
1935
+ if (!scan.valid || scan.declarations.length === 0) return {};
1936
+ return buildMcpParamHeaders(scan.declarations, args);
1937
+ }
1871
1938
 
1872
1939
  // ../../core/mcp/messageTrackingTransport.ts
1873
1940
  var MessageTrackingTransport = class {
@@ -2967,7 +3034,9 @@ function getAuthorizationServerUrl(serverUrl, resourceMetadata) {
2967
3034
  return new URL("/", serverUrl);
2968
3035
  } catch (err) {
2969
3036
  const detail = err instanceof Error ? err.message : String(err);
2970
- throw new Error(`Invalid MCP server URL: "${serverUrl}" (${detail})`);
3037
+ throw new Error(`Invalid MCP server URL: "${serverUrl}" (${detail})`, {
3038
+ cause: err
3039
+ });
2971
3040
  }
2972
3041
  }
2973
3042
 
@@ -4648,7 +4717,10 @@ var RemoteClientTransport = class {
4648
4717
  message,
4649
4718
  ...options?.relatedRequestId != null && {
4650
4719
  relatedRequestId: options.relatedRequestId
4651
- }
4720
+ },
4721
+ // Forward per-send `Mcp-Param-*` headers (SEP-2243) for the backend to
4722
+ // apply to the upstream send; the browser can't set them cross-origin.
4723
+ ...options?.headers != null && { headers: options.headers }
4652
4724
  };
4653
4725
  const res = await this.fetchFn(`${this.baseUrl}/api/mcp/send`, {
4654
4726
  method: "POST",
@@ -6898,6 +6970,43 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
6898
6970
  }
6899
6971
  }
6900
6972
  }
6973
+ /**
6974
+ * Coerce the string-valued entries of a tool's arguments to the types its
6975
+ * `inputSchema` declares (the Tools form hands everything over as text).
6976
+ * Shared by the two `tools/call` entry points — {@link attemptToolCall} and
6977
+ * {@link callToolStream} — so both put the SAME arguments on the wire.
6978
+ */
6979
+ convertStringToolArgs(tool, args) {
6980
+ const stringArgs = {};
6981
+ for (const [key, value] of Object.entries(args)) {
6982
+ if (typeof value === "string") {
6983
+ stringArgs[key] = value;
6984
+ }
6985
+ }
6986
+ if (Object.keys(stringArgs).length === 0) return args;
6987
+ return { ...args, ...convertToolParameters(tool, stringArgs) };
6988
+ }
6989
+ /**
6990
+ * SEP-2243: mirror `x-mcp-header`-annotated arguments into `Mcp-Param-*`
6991
+ * headers on a modern connection. The SDK only does this inside
6992
+ * `client.callTool()` (and skips it in the browser), but we route
6993
+ * `tools/call` through `client.request()` for manual MRTR driving (#1704), so
6994
+ * we mirror ourselves. `Protocol.request` forwards `headers` (preserved
6995
+ * across MRTR retry legs) to the transport, and the remote transport relays
6996
+ * them to the backend's upstream send — issued server-side, where the browser
6997
+ * skip doesn't apply. No-op on legacy/stdio (no annotations).
6998
+ *
6999
+ * Applied by BOTH `tools/call` entry points: a plain call
7000
+ * ({@link attemptToolCall}) and a task-augmented one
7001
+ * ({@link callToolStream}) — a strict modern server rejects either with
7002
+ * `-32020` when the mirrored header is missing.
7003
+ */
7004
+ applyMirroredParamHeaders(tool, convertedArgs, requestOptions) {
7005
+ if (this.protocolEra !== "modern") return;
7006
+ const paramHeaders = mcpParamHeadersForTool(tool, convertedArgs);
7007
+ if (Object.keys(paramHeaders).length === 0) return;
7008
+ requestOptions.headers = { ...requestOptions.headers, ...paramHeaders };
7009
+ }
6901
7010
  /**
6902
7011
  * Run a single tools/call attempt: convert args, issue the request, validate,
6903
7012
  * and return a successful {@link ToolCallInvocation}. Throws on any error
@@ -6917,17 +7026,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
6917
7026
  if (!client) {
6918
7027
  throw new Error("Client is not connected");
6919
7028
  }
6920
- let convertedArgs = args;
6921
- const stringArgs = {};
6922
- for (const [key, value] of Object.entries(args)) {
6923
- if (typeof value === "string") {
6924
- stringArgs[key] = value;
6925
- }
6926
- }
6927
- if (Object.keys(stringArgs).length > 0) {
6928
- const convertedStringArgs = convertToolParameters(tool, stringArgs);
6929
- convertedArgs = { ...args, ...convertedStringArgs };
6930
- }
7029
+ const convertedArgs = this.convertStringToolArgs(tool, args);
6931
7030
  const callMetadata = generalMetadata || toolSpecificMetadata ? { ...generalMetadata || {}, ...toolSpecificMetadata || {} } : void 0;
6932
7031
  const timestamp = /* @__PURE__ */ new Date();
6933
7032
  const metadata = this.mergeMeta(callMetadata);
@@ -6943,6 +7042,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
6943
7042
  metadata?.progressToken,
6944
7043
  signal
6945
7044
  );
7045
+ this.applyMirroredParamHeaders(tool, convertedArgs, requestOptions);
6946
7046
  const rawResult = await this.invokeMcpClient(
6947
7047
  () => this.requestWithInputRequired(
6948
7048
  "tools/call",
@@ -7346,17 +7446,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
7346
7446
  throw new Error("Client is not connected");
7347
7447
  }
7348
7448
  try {
7349
- let convertedArgs = args;
7350
- const stringArgs = {};
7351
- for (const [key, value] of Object.entries(args)) {
7352
- if (typeof value === "string") {
7353
- stringArgs[key] = value;
7354
- }
7355
- }
7356
- if (Object.keys(stringArgs).length > 0) {
7357
- const convertedStringArgs = convertToolParameters(tool, stringArgs);
7358
- convertedArgs = { ...args, ...convertedStringArgs };
7359
- }
7449
+ const convertedArgs = this.convertStringToolArgs(tool, args);
7360
7450
  const callMetadata = generalMetadata || toolSpecificMetadata ? { ...generalMetadata || {}, ...toolSpecificMetadata || {} } : void 0;
7361
7451
  const timestamp = /* @__PURE__ */ new Date();
7362
7452
  const metadata = this.mergeMeta(callMetadata);
@@ -7374,6 +7464,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
7374
7464
  let taskId;
7375
7465
  let error;
7376
7466
  const requestOptions = this.getRequestOptions(metadata?.progressToken);
7467
+ this.applyMirroredParamHeaders(tool, convertedArgs, requestOptions);
7377
7468
  if (this.progress) {
7378
7469
  const innerOnProgress = requestOptions.onprogress;
7379
7470
  requestOptions.onprogress = (progress) => {
@@ -7479,7 +7570,8 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
7479
7570
  );
7480
7571
  } catch (resultError) {
7481
7572
  throw new Error(
7482
- `Tool call did not return a result: ${resultError instanceof Error ? resultError.message : String(resultError)}`
7573
+ `Tool call did not return a result: ${resultError instanceof Error ? resultError.message : String(resultError)}`,
7574
+ { cause: resultError }
7483
7575
  );
7484
7576
  }
7485
7577
  }
@@ -7622,7 +7714,8 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
7622
7714
  expandedUri = uriTemplate2.expand(params);
7623
7715
  } catch (error) {
7624
7716
  throw new Error(
7625
- `Failed to expand URI template "${uriTemplate}": ${error instanceof Error ? error.message : String(error)}`
7717
+ `Failed to expand URI template "${uriTemplate}": ${error instanceof Error ? error.message : String(error)}`,
7718
+ { cause: error }
7626
7719
  );
7627
7720
  }
7628
7721
  const readInvocation = await this.readResource(expandedUri, metadata);
@@ -7820,7 +7913,8 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
7820
7913
  return { values: [] };
7821
7914
  }
7822
7915
  throw new Error(
7823
- `Failed to get completions: ${error instanceof Error ? error.message : String(error)}`
7916
+ `Failed to get completions: ${error instanceof Error ? error.message : String(error)}`,
7917
+ { cause: error }
7824
7918
  );
7825
7919
  }
7826
7920
  }
@@ -8222,7 +8316,8 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
8222
8316
  this.dispatchSubscriptionsChange();
8223
8317
  } catch (error) {
8224
8318
  throw new Error(
8225
- `Failed to subscribe to resource: ${error instanceof Error ? error.message : String(error)}`
8319
+ `Failed to subscribe to resource: ${error instanceof Error ? error.message : String(error)}`,
8320
+ { cause: error }
8226
8321
  );
8227
8322
  }
8228
8323
  }
@@ -8266,7 +8361,8 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
8266
8361
  }
8267
8362
  } catch (error) {
8268
8363
  throw new Error(
8269
- `Failed to unsubscribe from resource: ${error instanceof Error ? error.message : String(error)}`
8364
+ `Failed to unsubscribe from resource: ${error instanceof Error ? error.message : String(error)}`,
8365
+ { cause: error }
8270
8366
  );
8271
8367
  }
8272
8368
  }
@@ -453,9 +453,13 @@ function loadMcpServersConfig(configPath, writable) {
453
453
  return { ...config, mcpServers: normalizedServers };
454
454
  } catch (error) {
455
455
  if (error instanceof Error) {
456
- throw new Error(`Error loading configuration: ${error.message}`);
456
+ throw new Error(`Error loading configuration: ${error.message}`, {
457
+ cause: error
458
+ });
457
459
  }
458
- throw new Error("Error loading configuration: Unknown error");
460
+ throw new Error("Error loading configuration: Unknown error", {
461
+ cause: error
462
+ });
459
463
  }
460
464
  }
461
465
  function loadServerFromConfig(configPath, serverName, writable) {
@@ -1507,6 +1511,9 @@ function createTransportNode(config, options = {}) {
1507
1511
  }
1508
1512
  }
1509
1513
 
1514
+ // ../../core/json/xMcpHeader.ts
1515
+ var MCP_PARAM_HEADER_PREFIX = "Mcp-Param-";
1516
+
1510
1517
  // ../../core/mcp/import/clientConfig.ts
1511
1518
  function parseJsonObject(raw) {
1512
1519
  let data;
@@ -1514,7 +1521,7 @@ function parseJsonObject(raw) {
1514
1521
  data = JSON.parse(raw);
1515
1522
  } catch (err) {
1516
1523
  const detail = err instanceof Error ? err.message : String(err);
1517
- throw new Error(`Invalid JSON: ${detail}`);
1524
+ throw new Error(`Invalid JSON: ${detail}`, { cause: err });
1518
1525
  }
1519
1526
  if (!data || typeof data !== "object" || Array.isArray(data)) {
1520
1527
  throw new Error("Expected a JSON object at the top level");
@@ -2347,6 +2354,16 @@ function requestIdForSendWait(message) {
2347
2354
  }
2348
2355
  return void 0;
2349
2356
  }
2357
+ function mcpParamHeadersOnly(headers) {
2358
+ if (headers === null || typeof headers !== "object") return void 0;
2359
+ const out = {};
2360
+ for (const [key, value] of Object.entries(headers)) {
2361
+ if (typeof value === "string" && key.toLowerCase().startsWith(MCP_PARAM_HEADER_PREFIX.toLowerCase())) {
2362
+ out[key] = value;
2363
+ }
2364
+ }
2365
+ return Object.keys(out).length > 0 ? out : void 0;
2366
+ }
2350
2367
  function createRemoteApp(options) {
2351
2368
  const dangerouslyOmitAuth = !!options.dangerouslyOmitAuth;
2352
2369
  const authToken = dangerouslyOmitAuth ? "" : options.authToken || process.env[API_SERVER_ENV_VARS.AUTH_TOKEN] || randomBytes(32).toString("hex");
@@ -2554,7 +2571,7 @@ function createRemoteApp(options) {
2554
2571
  } catch {
2555
2572
  return c.json({ error: "Invalid JSON body" }, 400);
2556
2573
  }
2557
- const { sessionId, message, relatedRequestId } = body;
2574
+ const { sessionId, message, relatedRequestId, headers } = body;
2558
2575
  if (!sessionId || !message) {
2559
2576
  return c.json({ error: "Missing sessionId or message" }, 400);
2560
2577
  }
@@ -2575,8 +2592,10 @@ function createRemoteApp(options) {
2575
2592
  });
2576
2593
  }
2577
2594
  try {
2595
+ const paramHeaders = mcpParamHeadersOnly(headers);
2578
2596
  await session.transport.send(message, {
2579
- relatedRequestId
2597
+ relatedRequestId,
2598
+ ...paramHeaders && { headers: paramHeaders }
2580
2599
  });
2581
2600
  if (responseWait) {
2582
2601
  await responseWait;