@modelcontextprotocol/inspector 0.17.0 → 0.17.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.
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ import * as fs from "fs";
2
3
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
4
  import { Command } from "commander";
4
5
  import { callTool, connect, disconnect, getPrompt, listPrompts, listResources, listResourceTemplates, listTools, readResource, setLoggingLevel, validLogLevels, } from "./client/index.js";
5
6
  import { handleError } from "./error-handler.js";
6
7
  import { createTransport } from "./transport.js";
7
8
  import { awaitableLog } from "./utils/awaitable-log.js";
8
- import packageJson from "../package.json" with { type: "json" };
9
9
  function createTransportOptions(target, transport, headers) {
10
10
  if (target.length === 0) {
11
11
  throw new Error("Target is required. Specify a URL or a command to execute.");
@@ -52,6 +52,14 @@ function createTransportOptions(target, transport, headers) {
52
52
  };
53
53
  }
54
54
  async function callMethod(args) {
55
+ // Read package.json to get name and version for client identity
56
+ const pathA = "../package.json"; // We're in package @modelcontextprotocol/inspector-cli
57
+ const pathB = "../../package.json"; // We're in package @modelcontextprotocol/inspector
58
+ let packageJson;
59
+ let packageJsonData = await import(fs.existsSync(pathA) ? pathA : pathB, {
60
+ with: { type: "json" },
61
+ });
62
+ packageJson = packageJsonData.default;
55
63
  const transportOptions = createTransportOptions(args.target, args.transport, args.headers);
56
64
  const transport = createTransport(transportOptions);
57
65
  const [, name = packageJson.name] = packageJson.name.split("/");
@@ -1,4 +1,4 @@
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-BB0Z_sAV.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-9_nBaufL.js";
2
2
  const OAuthCallback = ({ onConnect }) => {
3
3
  const { toast } = useToast();
4
4
  const hasProcessedRef = reactExports.useRef(false);
@@ -1,4 +1,4 @@
1
- import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-BB0Z_sAV.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-9_nBaufL.js";
2
2
  const OAuthDebugCallback = ({ onConnect }) => {
3
3
  reactExports.useEffect(() => {
4
4
  let isProcessed = false;
@@ -15123,12 +15123,7 @@ const optionalType = ZodOptional.create;
15123
15123
  ZodNullable.create;
15124
15124
  const NEVER = INVALID;
15125
15125
  const LATEST_PROTOCOL_VERSION = "2025-06-18";
15126
- const SUPPORTED_PROTOCOL_VERSIONS = [
15127
- LATEST_PROTOCOL_VERSION,
15128
- "2025-03-26",
15129
- "2024-11-05",
15130
- "2024-10-07"
15131
- ];
15126
+ const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-03-26", "2024-11-05", "2024-10-07"];
15132
15127
  const JSONRPC_VERSION = "2.0";
15133
15128
  const ProgressTokenSchema = unionType([stringType(), numberType().int()]);
15134
15129
  const CursorSchema = stringType();
@@ -15208,12 +15203,7 @@ const JSONRPCErrorSchema = objectType({
15208
15203
  })
15209
15204
  }).strict();
15210
15205
  const isJSONRPCError = (value) => JSONRPCErrorSchema.safeParse(value).success;
15211
- const JSONRPCMessageSchema = unionType([
15212
- JSONRPCRequestSchema,
15213
- JSONRPCNotificationSchema,
15214
- JSONRPCResponseSchema,
15215
- JSONRPCErrorSchema
15216
- ]);
15206
+ const JSONRPCMessageSchema = unionType([JSONRPCRequestSchema, JSONRPCNotificationSchema, JSONRPCResponseSchema, JSONRPCErrorSchema]);
15217
15207
  const EmptyResultSchema = ResultSchema.strict();
15218
15208
  const CancelledNotificationSchema = NotificationSchema.extend({
15219
15209
  method: literalType("notifications/cancelled"),
@@ -15240,21 +15230,38 @@ const IconSchema = objectType({
15240
15230
  */
15241
15231
  mimeType: optionalType(stringType()),
15242
15232
  /**
15243
- * Optional string specifying icon dimensions (e.g., "48x48 96x96").
15233
+ * Optional array of strings that specify sizes at which the icon can be used.
15234
+ * Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG.
15235
+ *
15236
+ * If not provided, the client should assume that the icon can be used at any size.
15237
+ */
15238
+ sizes: optionalType(arrayType(stringType()))
15239
+ }).passthrough();
15240
+ const IconsSchema = objectType({
15241
+ /**
15242
+ * Optional set of sized icons that the client can display in a user interface.
15243
+ *
15244
+ * Clients that support rendering icons MUST support at least the following MIME types:
15245
+ * - `image/png` - PNG images (safe, universal compatibility)
15246
+ * - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)
15247
+ *
15248
+ * Clients that support rendering icons SHOULD also support:
15249
+ * - `image/svg+xml` - SVG images (scalable but requires security precautions)
15250
+ * - `image/webp` - WebP images (modern, efficient format)
15244
15251
  */
15245
- sizes: optionalType(stringType())
15252
+ icons: arrayType(IconSchema).optional()
15246
15253
  }).passthrough();
15247
15254
  const BaseMetadataSchema = objectType({
15248
15255
  /** Intended for programmatic or logical use, but used as a display name in past specs or fallback */
15249
15256
  name: stringType(),
15250
15257
  /**
15251
- * Intended for UI and end-user contexts — optimized to be human-readable and easily understood,
15252
- * even by those unfamiliar with domain-specific terminology.
15253
- *
15254
- * If not provided, the name should be used for display (except for Tool,
15255
- * where `annotations.title` should be given precedence over using `name`,
15256
- * if present).
15257
- */
15258
+ * Intended for UI and end-user contexts — optimized to be human-readable and easily understood,
15259
+ * even by those unfamiliar with domain-specific terminology.
15260
+ *
15261
+ * If not provided, the name should be used for display (except for Tool,
15262
+ * where `annotations.title` should be given precedence over using `name`,
15263
+ * if present).
15264
+ */
15258
15265
  title: optionalType(stringType())
15259
15266
  }).passthrough();
15260
15267
  const ImplementationSchema = BaseMetadataSchema.extend({
@@ -15262,17 +15269,8 @@ const ImplementationSchema = BaseMetadataSchema.extend({
15262
15269
  /**
15263
15270
  * An optional URL of the website for this implementation.
15264
15271
  */
15265
- websiteUrl: optionalType(stringType()),
15266
- /**
15267
- * An optional list of icons for this implementation.
15268
- * This can be used by clients to display the implementation in a user interface.
15269
- * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property.
15270
- * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml".
15271
- * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG.
15272
- * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size.
15273
- */
15274
- icons: optionalType(arrayType(IconSchema))
15275
- });
15272
+ websiteUrl: optionalType(stringType())
15273
+ }).merge(IconsSchema);
15276
15274
  const ClientCapabilitiesSchema = objectType({
15277
15275
  /**
15278
15276
  * Experimental, non-standard capabilities that the client supports.
@@ -15462,16 +15460,12 @@ const ResourceSchema = BaseMetadataSchema.extend({
15462
15460
  * The MIME type of this resource, if known.
15463
15461
  */
15464
15462
  mimeType: optionalType(stringType()),
15465
- /**
15466
- * An optional list of icons for this resource.
15467
- */
15468
- icons: optionalType(arrayType(IconSchema)),
15469
15463
  /**
15470
15464
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
15471
15465
  * for notes on _meta usage.
15472
15466
  */
15473
15467
  _meta: optionalType(objectType({}).passthrough())
15474
- });
15468
+ }).merge(IconsSchema);
15475
15469
  const ResourceTemplateSchema = BaseMetadataSchema.extend({
15476
15470
  /**
15477
15471
  * A URI template (according to RFC 6570) that can be used to construct resource URIs.
@@ -15492,7 +15486,7 @@ const ResourceTemplateSchema = BaseMetadataSchema.extend({
15492
15486
  * for notes on _meta usage.
15493
15487
  */
15494
15488
  _meta: optionalType(objectType({}).passthrough())
15495
- });
15489
+ }).merge(IconsSchema);
15496
15490
  const ListResourcesRequestSchema = PaginatedRequestSchema.extend({
15497
15491
  method: literalType("resources/list")
15498
15492
  });
@@ -15570,16 +15564,12 @@ const PromptSchema = BaseMetadataSchema.extend({
15570
15564
  * A list of arguments to use for templating the prompt.
15571
15565
  */
15572
15566
  arguments: optionalType(arrayType(PromptArgumentSchema)),
15573
- /**
15574
- * An optional list of icons for this prompt.
15575
- */
15576
- icons: optionalType(arrayType(IconSchema)),
15577
15567
  /**
15578
15568
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
15579
15569
  * for notes on _meta usage.
15580
15570
  */
15581
15571
  _meta: optionalType(objectType({}).passthrough())
15582
- });
15572
+ }).merge(IconsSchema);
15583
15573
  const ListPromptsRequestSchema = PaginatedRequestSchema.extend({
15584
15574
  method: literalType("prompts/list")
15585
15575
  });
@@ -15741,16 +15731,12 @@ const ToolSchema = BaseMetadataSchema.extend({
15741
15731
  * Optional additional tool information.
15742
15732
  */
15743
15733
  annotations: optionalType(ToolAnnotationsSchema),
15744
- /**
15745
- * An optional list of icons for this tool.
15746
- */
15747
- icons: optionalType(arrayType(IconSchema)),
15748
15734
  /**
15749
15735
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
15750
15736
  * for notes on _meta usage.
15751
15737
  */
15752
15738
  _meta: optionalType(objectType({}).passthrough())
15753
- });
15739
+ }).merge(IconsSchema);
15754
15740
  const ListToolsRequestSchema = PaginatedRequestSchema.extend({
15755
15741
  method: literalType("tools/list")
15756
15742
  });
@@ -15800,16 +15786,7 @@ const CallToolRequestSchema = RequestSchema.extend({
15800
15786
  const ToolListChangedNotificationSchema = NotificationSchema.extend({
15801
15787
  method: literalType("notifications/tools/list_changed")
15802
15788
  });
15803
- const LoggingLevelSchema = enumType([
15804
- "debug",
15805
- "info",
15806
- "notice",
15807
- "warning",
15808
- "error",
15809
- "critical",
15810
- "alert",
15811
- "emergency"
15812
- ]);
15789
+ const LoggingLevelSchema = enumType(["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]);
15813
15790
  const SetLevelRequestSchema = RequestSchema.extend({
15814
15791
  method: literalType("logging/setLevel"),
15815
15792
  params: BaseRequestParamsSchema.extend({
@@ -15902,11 +15879,7 @@ const CreateMessageResultSchema = ResultSchema.extend({
15902
15879
  */
15903
15880
  stopReason: optionalType(enumType(["endTurn", "stopSequence", "maxTokens"]).or(stringType())),
15904
15881
  role: enumType(["user", "assistant"]),
15905
- content: discriminatedUnionType("type", [
15906
- TextContentSchema,
15907
- ImageContentSchema,
15908
- AudioContentSchema
15909
- ])
15882
+ content: discriminatedUnionType("type", [TextContentSchema, ImageContentSchema, AudioContentSchema])
15910
15883
  });
15911
15884
  const BooleanSchemaSchema = objectType({
15912
15885
  type: literalType("boolean"),
@@ -15936,12 +15909,7 @@ const EnumSchemaSchema = objectType({
15936
15909
  enum: arrayType(stringType()),
15937
15910
  enumNames: optionalType(arrayType(stringType()))
15938
15911
  }).passthrough();
15939
- const PrimitiveSchemaDefinitionSchema = unionType([
15940
- BooleanSchemaSchema,
15941
- StringSchemaSchema,
15942
- NumberSchemaSchema,
15943
- EnumSchemaSchema
15944
- ]);
15912
+ const PrimitiveSchemaDefinitionSchema = unionType([BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, EnumSchemaSchema]);
15945
15913
  const ElicitRequestSchema = RequestSchema.extend({
15946
15914
  method: literalType("elicitation/create"),
15947
15915
  params: BaseRequestParamsSchema.extend({
@@ -16069,18 +16037,8 @@ unionType([
16069
16037
  InitializedNotificationSchema,
16070
16038
  RootsListChangedNotificationSchema
16071
16039
  ]);
16072
- unionType([
16073
- EmptyResultSchema,
16074
- CreateMessageResultSchema,
16075
- ElicitResultSchema,
16076
- ListRootsResultSchema
16077
- ]);
16078
- unionType([
16079
- PingRequestSchema,
16080
- CreateMessageRequestSchema,
16081
- ElicitRequestSchema,
16082
- ListRootsRequestSchema
16083
- ]);
16040
+ unionType([EmptyResultSchema, CreateMessageResultSchema, ElicitResultSchema, ListRootsResultSchema]);
16041
+ unionType([PingRequestSchema, CreateMessageRequestSchema, ElicitRequestSchema, ListRootsRequestSchema]);
16084
16042
  unionType([
16085
16043
  CancelledNotificationSchema,
16086
16044
  ProgressNotificationSchema,
@@ -16247,7 +16205,7 @@ objectType({
16247
16205
  token_type_hint: stringType().optional()
16248
16206
  }).strip();
16249
16207
  const name = "@modelcontextprotocol/inspector-client";
16250
- const version$1 = "0.17.0";
16208
+ const version$1 = "0.17.1";
16251
16209
  const packageJson = {
16252
16210
  name,
16253
16211
  version: version$1
@@ -16466,6 +16424,8 @@ class UnauthorizedError extends Error {
16466
16424
  super(message !== null && message !== void 0 ? message : "Unauthorized");
16467
16425
  }
16468
16426
  }
16427
+ const AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
16428
+ const AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
16469
16429
  function selectClientAuthMethod(clientInformation, supportedMethods) {
16470
16430
  const hasClientSecret = clientInformation.client_secret !== void 0;
16471
16431
  if (supportedMethods.length === 0) {
@@ -16755,7 +16715,6 @@ function buildDiscoveryUrls(authorizationServerUrl) {
16755
16715
  return urlsToTry;
16756
16716
  }
16757
16717
  async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
16758
- var _a;
16759
16718
  const headers = { "MCP-Protocol-Version": protocolVersion };
16760
16719
  const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
16761
16720
  for (const { url: endpointUrl, type: type2 } of urlsToTry) {
@@ -16772,26 +16731,20 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fet
16772
16731
  if (type2 === "oauth") {
16773
16732
  return OAuthMetadataSchema.parse(await response.json());
16774
16733
  } else {
16775
- const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
16776
- if (!((_a = metadata.code_challenge_methods_supported) === null || _a === void 0 ? void 0 : _a.includes("S256"))) {
16777
- throw new Error(`Incompatible OIDC provider at ${endpointUrl}: does not support S256 code challenge method required by MCP specification`);
16778
- }
16779
- return metadata;
16734
+ return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
16780
16735
  }
16781
16736
  }
16782
16737
  return void 0;
16783
16738
  }
16784
16739
  async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
16785
- const responseType = "code";
16786
- const codeChallengeMethod = "S256";
16787
16740
  let authorizationUrl;
16788
16741
  if (metadata) {
16789
16742
  authorizationUrl = new URL(metadata.authorization_endpoint);
16790
- if (!metadata.response_types_supported.includes(responseType)) {
16791
- throw new Error(`Incompatible auth server: does not support response type ${responseType}`);
16743
+ if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
16744
+ throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
16792
16745
  }
16793
- if (!metadata.code_challenge_methods_supported || !metadata.code_challenge_methods_supported.includes(codeChallengeMethod)) {
16794
- throw new Error(`Incompatible auth server: does not support code challenge method ${codeChallengeMethod}`);
16746
+ if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
16747
+ throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
16795
16748
  }
16796
16749
  } else {
16797
16750
  authorizationUrl = new URL("/authorize", authorizationServerUrl);
@@ -16799,10 +16752,10 @@ async function startAuthorization(authorizationServerUrl, { metadata, clientInfo
16799
16752
  const challenge = await pkceChallenge();
16800
16753
  const codeVerifier = challenge.code_verifier;
16801
16754
  const codeChallenge = challenge.code_challenge;
16802
- authorizationUrl.searchParams.set("response_type", responseType);
16755
+ authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
16803
16756
  authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
16804
16757
  authorizationUrl.searchParams.set("code_challenge", codeChallenge);
16805
- authorizationUrl.searchParams.set("code_challenge_method", codeChallengeMethod);
16758
+ authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
16806
16759
  authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
16807
16760
  if (state) {
16808
16761
  authorizationUrl.searchParams.set("state", state);
@@ -16827,7 +16780,7 @@ async function exchangeAuthorization(authorizationServerUrl, { metadata, clientI
16827
16780
  }
16828
16781
  const headers = new Headers({
16829
16782
  "Content-Type": "application/x-www-form-urlencoded",
16830
- "Accept": "application/json"
16783
+ Accept: "application/json"
16831
16784
  });
16832
16785
  const params = new URLSearchParams({
16833
16786
  grant_type: grantType,
@@ -17027,9 +16980,12 @@ class InspectorOAuthClientProvider {
17027
16980
  get debugRedirectUrl() {
17028
16981
  return window.location.origin + "/oauth/callback/debug";
17029
16982
  }
16983
+ get redirect_uris() {
16984
+ return [.../* @__PURE__ */ new Set([this.redirectUrl, this.debugRedirectUrl])];
16985
+ }
17030
16986
  get clientMetadata() {
17031
16987
  return {
17032
- redirect_uris: [this.redirectUrl, this.debugRedirectUrl],
16988
+ redirect_uris: this.redirect_uris,
17033
16989
  token_endpoint_auth_method: "none",
17034
16990
  grant_types: ["authorization_code", "refresh_token"],
17035
16991
  response_types: ["code"],
@@ -23409,28 +23365,28 @@ function isPropertyRequired(propertyName, schema) {
23409
23365
  }
23410
23366
  function normalizeUnionType(schema) {
23411
23367
  if (schema.anyOf && schema.anyOf.length === 2 && schema.anyOf.some((t) => t.type === "string") && schema.anyOf.some((t) => t.type === "null")) {
23412
- return { ...schema, type: "string", anyOf: void 0 };
23368
+ return { ...schema, type: "string", anyOf: void 0, nullable: true };
23413
23369
  }
23414
23370
  if (schema.anyOf && schema.anyOf.length === 2 && schema.anyOf.some((t) => t.type === "boolean") && schema.anyOf.some((t) => t.type === "null")) {
23415
- return { ...schema, type: "boolean", anyOf: void 0 };
23371
+ return { ...schema, type: "boolean", anyOf: void 0, nullable: true };
23416
23372
  }
23417
23373
  if (schema.anyOf && schema.anyOf.length === 2 && schema.anyOf.some((t) => t.type === "number") && schema.anyOf.some((t) => t.type === "null")) {
23418
- return { ...schema, type: "number", anyOf: void 0 };
23374
+ return { ...schema, type: "number", anyOf: void 0, nullable: true };
23419
23375
  }
23420
23376
  if (schema.anyOf && schema.anyOf.length === 2 && schema.anyOf.some((t) => t.type === "integer") && schema.anyOf.some((t) => t.type === "null")) {
23421
- return { ...schema, type: "integer", anyOf: void 0 };
23377
+ return { ...schema, type: "integer", anyOf: void 0, nullable: true };
23422
23378
  }
23423
23379
  if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("string") && schema.type.includes("null")) {
23424
- return { ...schema, type: "string" };
23380
+ return { ...schema, type: "string", nullable: true };
23425
23381
  }
23426
23382
  if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("boolean") && schema.type.includes("null")) {
23427
- return { ...schema, type: "boolean" };
23383
+ return { ...schema, type: "boolean", nullable: true };
23428
23384
  }
23429
23385
  if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("number") && schema.type.includes("null")) {
23430
- return { ...schema, type: "number" };
23386
+ return { ...schema, type: "number", nullable: true };
23431
23387
  }
23432
23388
  if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("integer") && schema.type.includes("null")) {
23433
- return { ...schema, type: "integer" };
23389
+ return { ...schema, type: "integer", nullable: true };
23434
23390
  }
23435
23391
  return schema;
23436
23392
  }
@@ -23491,7 +23447,10 @@ class Protocol {
23491
23447
  const totalElapsed = Date.now() - info.startTime;
23492
23448
  if (info.maxTotalTimeout && totalElapsed >= info.maxTotalTimeout) {
23493
23449
  this._timeoutInfo.delete(messageId);
23494
- throw new McpError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", { maxTotalTimeout: info.maxTotalTimeout, totalElapsed });
23450
+ throw new McpError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", {
23451
+ maxTotalTimeout: info.maxTotalTimeout,
23452
+ totalElapsed
23453
+ });
23495
23454
  }
23496
23455
  clearTimeout(info.timeoutId);
23497
23456
  info.timeoutId = setTimeout(info.onTimeout, info.timeout);
@@ -24442,7 +24401,11 @@ class SSEClientTransport {
24442
24401
  }
24443
24402
  let result;
24444
24403
  try {
24445
- result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24404
+ result = await auth(this._authProvider, {
24405
+ serverUrl: this._url,
24406
+ resourceMetadataUrl: this._resourceMetadataUrl,
24407
+ fetchFn: this._fetch
24408
+ });
24446
24409
  } catch (error) {
24447
24410
  (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
24448
24411
  throw error;
@@ -24541,7 +24504,12 @@ class SSEClientTransport {
24541
24504
  if (!this._authProvider) {
24542
24505
  throw new UnauthorizedError("No auth provider");
24543
24506
  }
24544
- const result = await auth(this._authProvider, { serverUrl: this._url, authorizationCode, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24507
+ const result = await auth(this._authProvider, {
24508
+ serverUrl: this._url,
24509
+ authorizationCode,
24510
+ resourceMetadataUrl: this._resourceMetadataUrl,
24511
+ fetchFn: this._fetch
24512
+ });
24545
24513
  if (result !== "AUTHORIZED") {
24546
24514
  throw new UnauthorizedError("Failed to authorize");
24547
24515
  }
@@ -24571,7 +24539,11 @@ class SSEClientTransport {
24571
24539
  if (!response.ok) {
24572
24540
  if (response.status === 401 && this._authProvider) {
24573
24541
  this._resourceMetadataUrl = extractResourceMetadataUrl(response);
24574
- const result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24542
+ const result = await auth(this._authProvider, {
24543
+ serverUrl: this._url,
24544
+ resourceMetadataUrl: this._resourceMetadataUrl,
24545
+ fetchFn: this._fetch
24546
+ });
24575
24547
  if (result !== "AUTHORIZED") {
24576
24548
  throw new UnauthorizedError();
24577
24549
  }
@@ -24626,6 +24598,7 @@ class StreamableHTTPError extends Error {
24626
24598
  class StreamableHTTPClientTransport {
24627
24599
  constructor(url, opts) {
24628
24600
  var _a;
24601
+ this._hasCompletedAuthFlow = false;
24629
24602
  this._url = url;
24630
24603
  this._resourceMetadataUrl = void 0;
24631
24604
  this._requestInit = opts === null || opts === void 0 ? void 0 : opts.requestInit;
@@ -24641,7 +24614,11 @@ class StreamableHTTPClientTransport {
24641
24614
  }
24642
24615
  let result;
24643
24616
  try {
24644
- result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24617
+ result = await auth(this._authProvider, {
24618
+ serverUrl: this._url,
24619
+ resourceMetadataUrl: this._resourceMetadataUrl,
24620
+ fetchFn: this._fetch
24621
+ });
24645
24622
  } catch (error) {
24646
24623
  (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
24647
24624
  throw error;
@@ -24807,7 +24784,12 @@ class StreamableHTTPClientTransport {
24807
24784
  if (!this._authProvider) {
24808
24785
  throw new UnauthorizedError("No auth provider");
24809
24786
  }
24810
- const result = await auth(this._authProvider, { serverUrl: this._url, authorizationCode, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24787
+ const result = await auth(this._authProvider, {
24788
+ serverUrl: this._url,
24789
+ authorizationCode,
24790
+ resourceMetadataUrl: this._resourceMetadataUrl,
24791
+ fetchFn: this._fetch
24792
+ });
24811
24793
  if (result !== "AUTHORIZED") {
24812
24794
  throw new UnauthorizedError("Failed to authorize");
24813
24795
  }
@@ -24845,16 +24827,25 @@ class StreamableHTTPClientTransport {
24845
24827
  }
24846
24828
  if (!response.ok) {
24847
24829
  if (response.status === 401 && this._authProvider) {
24830
+ if (this._hasCompletedAuthFlow) {
24831
+ throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
24832
+ }
24848
24833
  this._resourceMetadataUrl = extractResourceMetadataUrl(response);
24849
- const result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
24834
+ const result = await auth(this._authProvider, {
24835
+ serverUrl: this._url,
24836
+ resourceMetadataUrl: this._resourceMetadataUrl,
24837
+ fetchFn: this._fetch
24838
+ });
24850
24839
  if (result !== "AUTHORIZED") {
24851
24840
  throw new UnauthorizedError();
24852
24841
  }
24842
+ this._hasCompletedAuthFlow = true;
24853
24843
  return this.send(message);
24854
24844
  }
24855
24845
  const text = await response.text().catch(() => null);
24856
24846
  throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
24857
24847
  }
24848
+ this._hasCompletedAuthFlow = false;
24858
24849
  if (response.status === 202) {
24859
24850
  if (isInitializedNotification(message)) {
24860
24851
  this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => {
@@ -25053,6 +25044,7 @@ function useConnection({
25053
25044
  env,
25054
25045
  customHeaders,
25055
25046
  oauthClientId,
25047
+ oauthClientSecret,
25056
25048
  oauthScope,
25057
25049
  config,
25058
25050
  connectionType = "proxy",
@@ -25083,12 +25075,18 @@ function useConnection({
25083
25075
  });
25084
25076
  return;
25085
25077
  }
25078
+ const clientInformation = {
25079
+ client_id: oauthClientId
25080
+ };
25081
+ if (oauthClientSecret) {
25082
+ clientInformation.client_secret = oauthClientSecret;
25083
+ }
25086
25084
  saveClientInformationToSessionStorage({
25087
25085
  serverUrl: sseUrl,
25088
- clientInformation: { client_id: oauthClientId },
25086
+ clientInformation,
25089
25087
  isPreregistered: true
25090
25088
  });
25091
- }, [oauthClientId, sseUrl]);
25089
+ }, [oauthClientId, oauthClientSecret, sseUrl]);
25092
25090
  const pushHistory = (request, response) => {
25093
25091
  setRequestHistory((prev) => [
25094
25092
  ...prev,
@@ -26874,7 +26872,7 @@ const OAuthFlowProgress = ({
26874
26872
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-blue-600 mt-1", children: [
26875
26873
  "Resource metadata was added in the",
26876
26874
  " ",
26877
- /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "https://modelcontextprotocol.io/specification/draft/basic/authorization#2-3-1-authorization-server-location", children: "2025-DRAFT-v2 specification update" }),
26875
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location", children: "2025-06-18 specification update" }),
26878
26876
  /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
26879
26877
  authState.resourceMetadataError.message,
26880
26878
  authState.resourceMetadataError instanceof TypeError && " (This could indicate the endpoint doesn't exist or does not have CORS configured)"
@@ -27369,7 +27367,7 @@ function useCopy({ timeout = 500 } = {}) {
27369
27367
  clearTimeout(timeoutId);
27370
27368
  }
27371
27369
  };
27372
- }, [copied]);
27370
+ }, [copied, timeout]);
27373
27371
  return { copied, setCopied };
27374
27372
  }
27375
27373
  const JsonView = reactExports.memo(
@@ -27399,7 +27397,7 @@ const JsonView = reactExports.memo(
27399
27397
  variant: "destructive"
27400
27398
  });
27401
27399
  }
27402
- }, [toast2, normalizedData]);
27400
+ }, [toast2, normalizedData, setCopied]);
27403
27401
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx("p-4 border rounded relative", className), children: [
27404
27402
  withCopyButton && /* @__PURE__ */ jsxRuntimeExports.jsx(
27405
27403
  Button,
@@ -27433,6 +27431,7 @@ const JsonNode = reactExports.memo(
27433
27431
  initialExpandDepth,
27434
27432
  isError = false
27435
27433
  }) => {
27434
+ const { toast: toast2 } = useToast();
27436
27435
  const [isExpanded, setIsExpanded] = reactExports.useState(depth < initialExpandDepth);
27437
27436
  const [typeStyleMap] = reactExports.useState({
27438
27437
  number: "text-blue-600",
@@ -27444,6 +27443,50 @@ const JsonNode = reactExports.memo(
27444
27443
  default: "text-gray-700"
27445
27444
  });
27446
27445
  const dataType = getDataType(data2);
27446
+ const [copied, setCopied] = reactExports.useState(false);
27447
+ reactExports.useEffect(() => {
27448
+ let timeoutId;
27449
+ if (copied) {
27450
+ timeoutId = setTimeout(() => setCopied(false), 500);
27451
+ }
27452
+ return () => {
27453
+ if (timeoutId) clearTimeout(timeoutId);
27454
+ };
27455
+ }, [copied]);
27456
+ const handleCopyValue = reactExports.useCallback(
27457
+ (value) => {
27458
+ try {
27459
+ let text;
27460
+ const valueType = getDataType(value);
27461
+ switch (valueType) {
27462
+ case "string":
27463
+ text = value;
27464
+ break;
27465
+ case "number":
27466
+ case "boolean":
27467
+ text = String(value);
27468
+ break;
27469
+ case "null":
27470
+ text = "null";
27471
+ break;
27472
+ case "undefined":
27473
+ text = "undefined";
27474
+ break;
27475
+ default:
27476
+ text = JSON.stringify(value);
27477
+ }
27478
+ navigator.clipboard.writeText(text);
27479
+ setCopied(true);
27480
+ } catch (error) {
27481
+ toast2({
27482
+ title: "Error",
27483
+ description: `There was an error coping result into the clipboard: ${error instanceof Error ? error.message : String(error)}`,
27484
+ variant: "destructive"
27485
+ });
27486
+ }
27487
+ },
27488
+ [toast2]
27489
+ );
27447
27490
  const renderCollapsible = (isArray) => {
27448
27491
  const items2 = isArray ? data2 : Object.entries(data2);
27449
27492
  const itemCount = items2.length;
@@ -27511,7 +27554,7 @@ const JsonNode = reactExports.memo(
27511
27554
  const maxLength = 100;
27512
27555
  const isTooLong = value.length > maxLength;
27513
27556
  if (!isTooLong) {
27514
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex mr-1 rounded hover:bg-gray-800/20", children: [
27557
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex mr-1 rounded hover:bg-gray-800/20 group items-start", children: [
27515
27558
  name2 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mr-1 text-gray-600 dark:text-gray-400", children: [
27516
27559
  name2,
27517
27560
  ":"
@@ -27529,10 +27572,24 @@ const JsonNode = reactExports.memo(
27529
27572
  '"'
27530
27573
  ]
27531
27574
  }
27575
+ ),
27576
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
27577
+ Button,
27578
+ {
27579
+ variant: "ghost",
27580
+ className: "ml-1 h-6 w-6 p-0 opacity-0 group-hover:opacity-100",
27581
+ onClick: (e) => {
27582
+ e.stopPropagation();
27583
+ handleCopyValue(value);
27584
+ },
27585
+ "aria-label": name2 ? `Copy value of ${name2}` : "Copy value",
27586
+ title: name2 ? `Copy value of ${name2}` : "Copy value",
27587
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCheck, { className: "size-4 dark:text-green-700 text-green-600" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4 text-foreground" })
27588
+ }
27532
27589
  )
27533
27590
  ] });
27534
27591
  }
27535
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex mr-1 rounded group hover:bg-gray-800/20", children: [
27592
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex mr-1 rounded group hover:bg-gray-800/20 items-start", children: [
27536
27593
  name2 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mr-1 text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-100 group-hover:text-gray-400", children: [
27537
27594
  name2,
27538
27595
  ":"
@@ -27548,6 +27605,20 @@ const JsonNode = reactExports.memo(
27548
27605
  title: isExpanded ? "Click to collapse" : "Click to expand",
27549
27606
  children: isExpanded ? `"${value}"` : `"${value.slice(0, maxLength)}..."`
27550
27607
  }
27608
+ ),
27609
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
27610
+ Button,
27611
+ {
27612
+ variant: "ghost",
27613
+ className: "ml-1 h-6 w-6 p-0 opacity-0 group-hover:opacity-100",
27614
+ onClick: (e) => {
27615
+ e.stopPropagation();
27616
+ handleCopyValue(value);
27617
+ },
27618
+ "aria-label": name2 ? `Copy value of ${name2}` : "Copy value",
27619
+ title: name2 ? `Copy value of ${name2}` : "Copy value",
27620
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCheck, { className: "size-4 dark:text-green-700 text-green-600" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4 text-foreground" })
27621
+ }
27551
27622
  )
27552
27623
  ] });
27553
27624
  };
@@ -27558,12 +27629,26 @@ const JsonNode = reactExports.memo(
27558
27629
  case "string":
27559
27630
  return renderString(data2);
27560
27631
  default:
27561
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center mr-1 rounded hover:bg-gray-800/20", children: [
27632
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center mr-1 rounded hover:bg-gray-800/20 group", children: [
27562
27633
  name2 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "mr-1 text-gray-600 dark:text-gray-400", children: [
27563
27634
  name2,
27564
27635
  ":"
27565
27636
  ] }),
27566
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: typeStyleMap[dataType] || typeStyleMap.default, children: data2 === null ? "null" : String(data2) })
27637
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: typeStyleMap[dataType] || typeStyleMap.default, children: data2 === null ? "null" : String(data2) }),
27638
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
27639
+ Button,
27640
+ {
27641
+ variant: "ghost",
27642
+ className: "ml-1 h-6 w-6 p-0 opacity-0 group-hover:opacity-100",
27643
+ onClick: (e) => {
27644
+ e.stopPropagation();
27645
+ handleCopyValue(data2);
27646
+ },
27647
+ "aria-label": name2 ? `Copy value of ${name2}` : "Copy value",
27648
+ title: name2 ? `Copy value of ${name2}` : "Copy value",
27649
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCheck, { className: "size-4 dark:text-green-700 text-green-600" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-4 text-foreground" })
27650
+ }
27651
+ )
27567
27652
  ] });
27568
27653
  }
27569
27654
  }
@@ -31997,12 +32082,22 @@ function Combobox({
31997
32082
  value,
31998
32083
  onChange,
31999
32084
  onInputChange,
32085
+ onFocus,
32000
32086
  options = [],
32001
32087
  placeholder = "Select...",
32002
32088
  emptyMessage = "No results found.",
32003
32089
  id
32004
32090
  }) {
32005
32091
  const [open, setOpen] = React.useState(false);
32092
+ const handleOpenChange = React.useCallback(
32093
+ (newOpen) => {
32094
+ setOpen(newOpen);
32095
+ if (newOpen && onFocus) {
32096
+ onFocus();
32097
+ }
32098
+ },
32099
+ [onFocus]
32100
+ );
32006
32101
  const handleSelect = React.useCallback(
32007
32102
  (option) => {
32008
32103
  onChange(option);
@@ -32016,7 +32111,7 @@ function Combobox({
32016
32111
  },
32017
32112
  [onInputChange]
32018
32113
  );
32019
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(Popover, { open, onOpenChange: setOpen, children: [
32114
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
32020
32115
  /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
32021
32116
  Button,
32022
32117
  {
@@ -32326,8 +32421,7 @@ const PromptsTab = ({
32326
32421
  reactExports.useEffect(() => {
32327
32422
  clearCompletions();
32328
32423
  }, [clearCompletions, selectedPrompt]);
32329
- const handleInputChange = async (argName, value) => {
32330
- setPromptArgs((prev) => ({ ...prev, [argName]: value }));
32424
+ const triggerCompletions = (argName, value) => {
32331
32425
  if (selectedPrompt) {
32332
32426
  requestCompletions(
32333
32427
  {
@@ -32340,6 +32434,14 @@ const PromptsTab = ({
32340
32434
  );
32341
32435
  }
32342
32436
  };
32437
+ const handleInputChange = async (argName, value) => {
32438
+ setPromptArgs((prev) => ({ ...prev, [argName]: value }));
32439
+ triggerCompletions(argName, value);
32440
+ };
32441
+ const handleFocus = async (argName) => {
32442
+ const currentValue = promptArgs[argName] || "";
32443
+ triggerCompletions(argName, currentValue);
32444
+ };
32343
32445
  const handleGetPrompt = () => {
32344
32446
  if (selectedPrompt) {
32345
32447
  getPrompt(selectedPrompt.name, promptArgs);
@@ -32373,7 +32475,7 @@ const PromptsTab = ({
32373
32475
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4", children: error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
32374
32476
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
32375
32477
  /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error" }),
32376
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: error })
32478
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { className: "break-all", children: error })
32377
32479
  ] }) : selectedPrompt ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
32378
32480
  selectedPrompt.description && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: selectedPrompt.description }),
32379
32481
  (_a = selectedPrompt.arguments) == null ? void 0 : _a.map((arg) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
@@ -32386,6 +32488,7 @@ const PromptsTab = ({
32386
32488
  value: promptArgs[arg.name] || "",
32387
32489
  onChange: (value) => handleInputChange(arg.name, value),
32388
32490
  onInputChange: (value) => handleInputChange(arg.name, value),
32491
+ onFocus: () => handleFocus(arg.name),
32389
32492
  options: completions[arg.name] || []
32390
32493
  }
32391
32494
  ),
@@ -32774,7 +32877,7 @@ const ResourcesTab = ({
32774
32877
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4", children: error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
32775
32878
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
32776
32879
  /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error" }),
32777
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: error })
32880
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { className: "break-all", children: error })
32778
32881
  ] }) : selectedResource ? /* @__PURE__ */ jsxRuntimeExports.jsx(
32779
32882
  JsonView,
32780
32883
  {
@@ -35358,7 +35461,7 @@ const SamplingRequest = ({
35358
35461
  },
35359
35462
  role: {
35360
35463
  type: "string",
35361
- default: "endTurn",
35464
+ default: "assistant",
35362
35465
  description: "Role of the model"
35363
35466
  },
35364
35467
  content: {
@@ -36778,7 +36881,7 @@ const useTheme = () => {
36778
36881
  [theme, setThemeWithSideEffect]
36779
36882
  );
36780
36883
  };
36781
- const version = "0.17.0";
36884
+ const version = "0.17.1";
36782
36885
  var [createTooltipContext] = createContextScope("Tooltip", [
36783
36886
  createPopperScope
36784
36887
  ]);
@@ -37665,6 +37768,8 @@ const Sidebar = ({
37665
37768
  setCustomHeaders,
37666
37769
  oauthClientId,
37667
37770
  setOauthClientId,
37771
+ oauthClientSecret,
37772
+ setOauthClientSecret,
37668
37773
  oauthScope,
37669
37774
  setOauthScope,
37670
37775
  onConnect,
@@ -37682,6 +37787,7 @@ const Sidebar = ({
37682
37787
  const [showAuthConfig, setShowAuthConfig] = reactExports.useState(false);
37683
37788
  const [showConfig, setShowConfig] = reactExports.useState(false);
37684
37789
  const [shownEnvVars, setShownEnvVars] = reactExports.useState(/* @__PURE__ */ new Set());
37790
+ const [showClientSecret, setShowClientSecret] = reactExports.useState(false);
37685
37791
  const [copiedServerEntry, setCopiedServerEntry] = reactExports.useState(false);
37686
37792
  const [copiedServerFile, setCopiedServerFile] = reactExports.useState(false);
37687
37793
  const { toast: toast2 } = useToast();
@@ -38085,6 +38191,33 @@ const Sidebar = ({
38085
38191
  className: "font-mono"
38086
38192
  }
38087
38193
  ),
38194
+ /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
38195
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
38196
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
38197
+ Input,
38198
+ {
38199
+ type: showClientSecret ? "text" : "password",
38200
+ placeholder: "Client Secret (optional)",
38201
+ onChange: (e) => setOauthClientSecret(e.target.value),
38202
+ value: oauthClientSecret,
38203
+ "data-testid": "oauth-client-secret-input",
38204
+ className: "font-mono"
38205
+ }
38206
+ ),
38207
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
38208
+ Button,
38209
+ {
38210
+ variant: "outline",
38211
+ size: "icon",
38212
+ className: "h-9 w-9 p-0 shrink-0",
38213
+ onClick: () => setShowClientSecret(!showClientSecret),
38214
+ "aria-label": showClientSecret ? "Hide secret" : "Show secret",
38215
+ "aria-pressed": showClientSecret,
38216
+ title: showClientSecret ? "Hide secret" : "Show secret",
38217
+ children: showClientSecret ? /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "h-4 w-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { className: "h-4 w-4", "aria-hidden": "true" })
38218
+ }
38219
+ )
38220
+ ] }),
38088
38221
  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium", children: "Redirect URL" }),
38089
38222
  /* @__PURE__ */ jsxRuntimeExports.jsx(
38090
38223
  Input,
@@ -38905,7 +39038,7 @@ const ToolsTab = ({
38905
39038
  setSelectedItem: setSelectedTool,
38906
39039
  renderItem: (tool) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-start", children: [
38907
39040
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1", children: tool.name }),
38908
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-500 text-left", children: tool.description })
39041
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-500 text-left line-clamp-3", children: tool.description })
38909
39042
  ] }),
38910
39043
  title: "Tools",
38911
39044
  buttonText: nextCursor ? "List More Tools" : "List Tools",
@@ -38918,141 +39051,199 @@ const ToolsTab = ({
38918
39051
  error && /* @__PURE__ */ jsxRuntimeExports.jsxs(Alert, { variant: "destructive", children: [
38919
39052
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "h-4 w-4" }),
38920
39053
  /* @__PURE__ */ jsxRuntimeExports.jsx(AlertTitle, { children: "Error" }),
38921
- /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { children: error })
39054
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AlertDescription, { className: "break-all", children: error })
38922
39055
  ] }),
38923
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: selectedTool.description }),
39056
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 whitespace-pre-wrap max-h-48 overflow-y-auto", children: selectedTool.description }),
38924
39057
  Object.entries(selectedTool.inputSchema.properties ?? []).map(
38925
39058
  ([key, value]) => {
38926
39059
  const prop = normalizeUnionType(value);
38927
39060
  const inputSchema = selectedTool.inputSchema;
38928
39061
  const required2 = isPropertyRequired(key, inputSchema);
38929
39062
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
38930
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
38931
- Label$1,
38932
- {
38933
- htmlFor: key,
38934
- className: "block text-sm font-medium text-gray-700 dark:text-gray-300",
38935
- children: [
38936
- key,
38937
- required2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
38938
- ]
38939
- }
38940
- ),
38941
- prop.type === "boolean" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2 mt-2", children: [
38942
- /* @__PURE__ */ jsxRuntimeExports.jsx(
38943
- Checkbox,
38944
- {
38945
- id: key,
38946
- name: key,
38947
- checked: !!params[key],
38948
- onCheckedChange: (checked) => setParams({
38949
- ...params,
38950
- [key]: checked
38951
- })
38952
- }
38953
- ),
38954
- /* @__PURE__ */ jsxRuntimeExports.jsx(
38955
- "label",
39063
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
39064
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
39065
+ Label$1,
38956
39066
  {
38957
39067
  htmlFor: key,
38958
- className: "text-sm font-medium text-gray-700 dark:text-gray-300",
38959
- children: prop.description || "Toggle this option"
39068
+ className: "block text-sm font-medium text-gray-700 dark:text-gray-300",
39069
+ children: [
39070
+ key,
39071
+ required2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
39072
+ ]
38960
39073
  }
38961
- )
38962
- ] }) : prop.type === "string" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
38963
- Textarea,
38964
- {
38965
- id: key,
38966
- name: key,
38967
- placeholder: prop.description,
38968
- value: params[key] === void 0 ? "" : String(params[key]),
38969
- onChange: (e) => {
38970
- const value2 = e.target.value;
38971
- if (value2 === "") {
38972
- setParams({
38973
- ...params,
38974
- [key]: void 0
38975
- });
38976
- } else {
38977
- setParams({
39074
+ ),
39075
+ prop.nullable ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
39076
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39077
+ Checkbox,
39078
+ {
39079
+ id: key,
39080
+ name: key,
39081
+ checked: params[key] === null,
39082
+ onCheckedChange: (checked) => setParams({
38978
39083
  ...params,
38979
- [key]: value2
38980
- });
39084
+ [key]: checked ? null : prop.default
39085
+ })
38981
39086
  }
38982
- },
38983
- className: "mt-1"
38984
- }
38985
- ) : prop.type === "object" || prop.type === "array" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
38986
- DynamicJsonForm,
38987
- {
38988
- ref: (ref2) => formRefs.current[key] = ref2,
38989
- schema: {
38990
- type: prop.type,
38991
- properties: prop.properties,
38992
- description: prop.description,
38993
- items: prop.items
38994
- },
38995
- value: params[key] ?? generateDefaultValue(prop),
38996
- onChange: (newValue) => {
38997
- setParams({
38998
- ...params,
38999
- [key]: newValue
39000
- });
39001
- setTimeout(checkValidationErrors, 100);
39002
- }
39003
- }
39004
- ) }) : prop.type === "number" || prop.type === "integer" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
39005
- Input,
39087
+ ),
39088
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39089
+ "label",
39090
+ {
39091
+ htmlFor: key,
39092
+ className: "text-sm font-medium text-gray-700 dark:text-gray-300",
39093
+ children: "null"
39094
+ }
39095
+ )
39096
+ ] }) : null
39097
+ ] }),
39098
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39099
+ "div",
39006
39100
  {
39007
- type: "number",
39008
- id: key,
39009
- name: key,
39010
- placeholder: prop.description,
39011
- value: params[key] === void 0 ? "" : String(params[key]),
39012
- onChange: (e) => {
39013
- const value2 = e.target.value;
39014
- if (value2 === "") {
39015
- setParams({
39016
- ...params,
39017
- [key]: void 0
39018
- });
39019
- } else {
39020
- const num = Number(value2);
39021
- if (!isNaN(num)) {
39101
+ role: "toolinputwrapper",
39102
+ className: `${prop.nullable && params[key] === null ? "pointer-events-none opacity-50" : ""}`,
39103
+ children: prop.type === "boolean" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2 mt-2", children: [
39104
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39105
+ Checkbox,
39106
+ {
39107
+ id: key,
39108
+ name: key,
39109
+ checked: !!params[key],
39110
+ onCheckedChange: (checked) => setParams({
39111
+ ...params,
39112
+ [key]: checked
39113
+ })
39114
+ }
39115
+ ),
39116
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39117
+ "label",
39118
+ {
39119
+ htmlFor: key,
39120
+ className: "text-sm font-medium text-gray-700 dark:text-gray-300",
39121
+ children: prop.description || "Toggle this option"
39122
+ }
39123
+ )
39124
+ ] }) : prop.type === "string" && prop.enum ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
39125
+ Select,
39126
+ {
39127
+ value: params[key] === void 0 ? "" : String(params[key]),
39128
+ onValueChange: (value2) => {
39129
+ if (value2 === "") {
39130
+ setParams({
39131
+ ...params,
39132
+ [key]: void 0
39133
+ });
39134
+ } else {
39135
+ setParams({
39136
+ ...params,
39137
+ [key]: value2
39138
+ });
39139
+ }
39140
+ },
39141
+ children: [
39142
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { id: key, className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
39143
+ SelectValue,
39144
+ {
39145
+ placeholder: prop.description || "Select an option"
39146
+ }
39147
+ ) }),
39148
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: prop.enum.map((option) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: option, children: option }, option)) })
39149
+ ]
39150
+ }
39151
+ ) : prop.type === "string" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
39152
+ Textarea,
39153
+ {
39154
+ id: key,
39155
+ name: key,
39156
+ placeholder: prop.description,
39157
+ value: params[key] === void 0 ? "" : String(params[key]),
39158
+ onChange: (e) => {
39159
+ const value2 = e.target.value;
39160
+ if (value2 === "") {
39161
+ setParams({
39162
+ ...params,
39163
+ [key]: void 0
39164
+ });
39165
+ } else {
39166
+ setParams({
39167
+ ...params,
39168
+ [key]: value2
39169
+ });
39170
+ }
39171
+ },
39172
+ className: "mt-1"
39173
+ }
39174
+ ) : prop.type === "object" || prop.type === "array" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
39175
+ DynamicJsonForm,
39176
+ {
39177
+ ref: (ref2) => formRefs.current[key] = ref2,
39178
+ schema: {
39179
+ type: prop.type,
39180
+ properties: prop.properties,
39181
+ description: prop.description,
39182
+ items: prop.items
39183
+ },
39184
+ value: params[key] ?? generateDefaultValue(prop),
39185
+ onChange: (newValue) => {
39022
39186
  setParams({
39023
39187
  ...params,
39024
- [key]: num
39188
+ [key]: newValue
39025
39189
  });
39026
- } else {
39190
+ setTimeout(checkValidationErrors, 100);
39191
+ }
39192
+ }
39193
+ ) }) : prop.type === "number" || prop.type === "integer" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
39194
+ Input,
39195
+ {
39196
+ type: "number",
39197
+ id: key,
39198
+ name: key,
39199
+ placeholder: prop.description,
39200
+ value: params[key] === void 0 ? "" : String(params[key]),
39201
+ onChange: (e) => {
39202
+ const value2 = e.target.value;
39203
+ if (value2 === "") {
39204
+ setParams({
39205
+ ...params,
39206
+ [key]: void 0
39207
+ });
39208
+ } else {
39209
+ const num = Number(value2);
39210
+ if (!isNaN(num)) {
39211
+ setParams({
39212
+ ...params,
39213
+ [key]: num
39214
+ });
39215
+ } else {
39216
+ setParams({
39217
+ ...params,
39218
+ [key]: value2
39219
+ });
39220
+ }
39221
+ }
39222
+ },
39223
+ className: "mt-1"
39224
+ }
39225
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
39226
+ DynamicJsonForm,
39227
+ {
39228
+ ref: (ref2) => formRefs.current[key] = ref2,
39229
+ schema: {
39230
+ type: prop.type,
39231
+ properties: prop.properties,
39232
+ description: prop.description,
39233
+ items: prop.items
39234
+ },
39235
+ value: params[key],
39236
+ onChange: (newValue) => {
39027
39237
  setParams({
39028
39238
  ...params,
39029
- [key]: value2
39239
+ [key]: newValue
39030
39240
  });
39241
+ setTimeout(checkValidationErrors, 100);
39031
39242
  }
39032
39243
  }
39033
- },
39034
- className: "mt-1"
39244
+ ) })
39035
39245
  }
39036
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
39037
- DynamicJsonForm,
39038
- {
39039
- ref: (ref2) => formRefs.current[key] = ref2,
39040
- schema: {
39041
- type: prop.type,
39042
- properties: prop.properties,
39043
- description: prop.description,
39044
- items: prop.items
39045
- },
39046
- value: params[key],
39047
- onChange: (newValue) => {
39048
- setParams({
39049
- ...params,
39050
- [key]: newValue
39051
- });
39052
- setTimeout(checkValidationErrors, 100);
39053
- }
39054
- }
39055
- ) })
39246
+ )
39056
39247
  ] }, key);
39057
39248
  }
39058
39249
  ),
@@ -39353,6 +39544,9 @@ const App = () => {
39353
39544
  const [oauthScope, setOauthScope] = reactExports.useState(() => {
39354
39545
  return localStorage.getItem("lastOauthScope") || "";
39355
39546
  });
39547
+ const [oauthClientSecret, setOauthClientSecret] = reactExports.useState(() => {
39548
+ return localStorage.getItem("lastOauthClientSecret") || "";
39549
+ });
39356
39550
  const [customHeaders, setCustomHeaders] = reactExports.useState(() => {
39357
39551
  const savedHeaders = localStorage.getItem("lastCustomHeaders");
39358
39552
  if (savedHeaders) {
@@ -39434,6 +39628,7 @@ const App = () => {
39434
39628
  env,
39435
39629
  customHeaders,
39436
39630
  oauthClientId,
39631
+ oauthClientSecret,
39437
39632
  oauthScope,
39438
39633
  config,
39439
39634
  connectionType,
@@ -39539,6 +39734,9 @@ const App = () => {
39539
39734
  reactExports.useEffect(() => {
39540
39735
  localStorage.setItem("lastOauthScope", oauthScope);
39541
39736
  }, [oauthScope]);
39737
+ reactExports.useEffect(() => {
39738
+ localStorage.setItem("lastOauthClientSecret", oauthClientSecret);
39739
+ }, [oauthClientSecret]);
39542
39740
  reactExports.useEffect(() => {
39543
39741
  saveInspectorConfig(CONFIG_LOCAL_STORAGE_KEY, config);
39544
39742
  }, [config]);
@@ -39919,13 +40117,13 @@ const App = () => {
39919
40117
  ) });
39920
40118
  if (window.location.pathname === "/oauth/callback") {
39921
40119
  const OAuthCallback = React.lazy(
39922
- () => __vitePreload(() => import("./OAuthCallback-C0JXhwud.js"), true ? [] : void 0)
40120
+ () => __vitePreload(() => import("./OAuthCallback-0GeGMxax.js"), true ? [] : void 0)
39923
40121
  );
39924
40122
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
39925
40123
  }
39926
40124
  if (window.location.pathname === "/oauth/callback/debug") {
39927
40125
  const OAuthDebugCallback = React.lazy(
39928
- () => __vitePreload(() => import("./OAuthDebugCallback-TZR9iqA_.js"), true ? [] : void 0)
40126
+ () => __vitePreload(() => import("./OAuthDebugCallback-DEQBSYMe.js"), true ? [] : void 0)
39929
40127
  );
39930
40128
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
39931
40129
  }
@@ -39961,6 +40159,8 @@ const App = () => {
39961
40159
  setCustomHeaders,
39962
40160
  oauthClientId,
39963
40161
  setOauthClientId,
40162
+ oauthClientSecret,
40163
+ setOauthClientSecret,
39964
40164
  oauthScope,
39965
40165
  setOauthScope,
39966
40166
  onConnect: connectMcpServer,
@@ -916,6 +916,12 @@ video {
916
916
  .mt-4 {
917
917
  margin-top: 1rem;
918
918
  }
919
+ .line-clamp-3 {
920
+ overflow: hidden;
921
+ display: -webkit-box;
922
+ -webkit-box-orient: vertical;
923
+ -webkit-line-clamp: 3;
924
+ }
919
925
  .block {
920
926
  display: block;
921
927
  }
@@ -989,6 +995,9 @@ video {
989
995
  .h-screen {
990
996
  height: 100vh;
991
997
  }
998
+ .max-h-48 {
999
+ max-height: 12rem;
1000
+ }
992
1001
  .max-h-96 {
993
1002
  max-height: 24rem;
994
1003
  }
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/mcp.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>MCP Inspector</title>
8
- <script type="module" crossorigin src="/assets/index-BB0Z_sAV.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-DJXA50Oy.css">
8
+ <script type="module" crossorigin src="/assets/index-9_nBaufL.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CV-uzqYs.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root" class="w-full"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelcontextprotocol/inspector",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Model Context Protocol inspector",
5
5
  "license": "MIT",
6
6
  "author": "Anthropic, PBC (https://anthropic.com)",
@@ -47,9 +47,9 @@
47
47
  "check-version": "node scripts/check-version-consistency.js"
48
48
  },
49
49
  "dependencies": {
50
- "@modelcontextprotocol/inspector-cli": "^0.17.0",
51
- "@modelcontextprotocol/inspector-client": "^0.17.0",
52
- "@modelcontextprotocol/inspector-server": "^0.17.0",
50
+ "@modelcontextprotocol/inspector-cli": "^0.17.1",
51
+ "@modelcontextprotocol/inspector-client": "^0.17.1",
52
+ "@modelcontextprotocol/inspector-server": "^0.17.1",
53
53
  "@modelcontextprotocol/sdk": "^1.18.0",
54
54
  "concurrently": "^9.2.0",
55
55
  "node-fetch": "^3.3.2",