@modelcontextprotocol/inspector 0.16.7 → 0.16.8

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.
@@ -779,6 +779,9 @@ video {
779
779
  white-space: nowrap;
780
780
  border-width: 0;
781
781
  }
782
+ .pointer-events-none {
783
+ pointer-events: none;
784
+ }
782
785
  .pointer-events-auto {
783
786
  pointer-events: auto;
784
787
  }
@@ -830,6 +833,9 @@ video {
830
833
  .top-1 {
831
834
  top: 0.25rem;
832
835
  }
836
+ .top-1\/2 {
837
+ top: 50%;
838
+ }
833
839
  .top-2 {
834
840
  top: 0.5rem;
835
841
  }
@@ -989,6 +995,9 @@ video {
989
995
  .max-h-screen {
990
996
  max-height: 100vh;
991
997
  }
998
+ .min-h-\[100px\] {
999
+ min-height: 100px;
1000
+ }
992
1001
  .min-h-\[60px\] {
993
1002
  min-height: 60px;
994
1003
  }
@@ -1010,6 +1019,9 @@ video {
1010
1019
  .w-5 {
1011
1020
  width: 1.25rem;
1012
1021
  }
1022
+ .w-6 {
1023
+ width: 1.5rem;
1024
+ }
1013
1025
  .w-72 {
1014
1026
  width: 18rem;
1015
1027
  }
@@ -1055,6 +1067,10 @@ video {
1055
1067
  .origin-\[--radix-tooltip-content-transform-origin\] {
1056
1068
  transform-origin: var(--radix-tooltip-content-transform-origin);
1057
1069
  }
1070
+ .-translate-y-1\/2 {
1071
+ --tw-translate-y: -50%;
1072
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1073
+ }
1058
1074
  .translate-x-\[-50\%\] {
1059
1075
  --tw-translate-x: -50%;
1060
1076
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -1086,6 +1102,9 @@ video {
1086
1102
  -moz-user-select: none;
1087
1103
  user-select: none;
1088
1104
  }
1105
+ .resize-none {
1106
+ resize: none;
1107
+ }
1089
1108
  .grid-cols-2 {
1090
1109
  grid-template-columns: repeat(2, minmax(0, 1fr));
1091
1110
  }
@@ -1271,6 +1290,9 @@ video {
1271
1290
  --tw-border-opacity: 1;
1272
1291
  border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
1273
1292
  }
1293
+ .border-transparent {
1294
+ border-color: transparent;
1295
+ }
1274
1296
  .border-t-transparent {
1275
1297
  border-top-color: transparent;
1276
1298
  }
@@ -1421,6 +1443,10 @@ video {
1421
1443
  padding-top: 0.75rem;
1422
1444
  padding-bottom: 0.75rem;
1423
1445
  }
1446
+ .py-4 {
1447
+ padding-top: 1rem;
1448
+ padding-bottom: 1rem;
1449
+ }
1424
1450
  .py-6 {
1425
1451
  padding-top: 1.5rem;
1426
1452
  padding-bottom: 1.5rem;
@@ -1649,6 +1675,11 @@ video {
1649
1675
  .outline {
1650
1676
  outline-style: solid;
1651
1677
  }
1678
+ .ring-0 {
1679
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
1680
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
1681
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
1682
+ }
1652
1683
  .ring-offset-background {
1653
1684
  --tw-ring-offset-color: hsl(var(--background));
1654
1685
  }
@@ -1679,6 +1710,11 @@ video {
1679
1710
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1680
1711
  transition-duration: 150ms;
1681
1712
  }
1713
+ .transition-transform {
1714
+ transition-property: transform;
1715
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1716
+ transition-duration: 150ms;
1717
+ }
1682
1718
  .duration-200 {
1683
1719
  transition-duration: 200ms;
1684
1720
  }
@@ -1833,6 +1869,11 @@ h1 {
1833
1869
  background-color: hsl(var(--primary) / 0.9);
1834
1870
  }
1835
1871
 
1872
+ .hover\:bg-red-50:hover {
1873
+ --tw-bg-opacity: 1;
1874
+ background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));
1875
+ }
1876
+
1836
1877
  .hover\:bg-secondary:hover {
1837
1878
  background-color: hsl(var(--secondary));
1838
1879
  }
@@ -1859,6 +1900,11 @@ h1 {
1859
1900
  color: hsl(var(--foreground));
1860
1901
  }
1861
1902
 
1903
+ .hover\:text-red-700:hover {
1904
+ --tw-text-opacity: 1;
1905
+ color: rgb(185 28 28 / var(--tw-text-opacity, 1));
1906
+ }
1907
+
1862
1908
  .hover\:underline:hover {
1863
1909
  text-decoration-line: underline;
1864
1910
  }
@@ -1943,6 +1989,10 @@ h1 {
1943
1989
  --tw-ring-offset-width: 2px;
1944
1990
  }
1945
1991
 
1992
+ .focus-visible\:ring-offset-background:focus-visible {
1993
+ --tw-ring-offset-color: hsl(var(--background));
1994
+ }
1995
+
1946
1996
  .disabled\:pointer-events-none:disabled {
1947
1997
  pointer-events: none;
1948
1998
  }
@@ -2049,6 +2099,16 @@ h1 {
2049
2099
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2050
2100
  }
2051
2101
 
2102
+ .data-\[state\=checked\]\:translate-x-4[data-state="checked"] {
2103
+ --tw-translate-x: 1rem;
2104
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2105
+ }
2106
+
2107
+ .data-\[state\=unchecked\]\:translate-x-0[data-state="unchecked"] {
2108
+ --tw-translate-x: 0px;
2109
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2110
+ }
2111
+
2052
2112
  .data-\[swipe\=cancel\]\:translate-x-0[data-swipe="cancel"] {
2053
2113
  --tw-translate-x: 0px;
2054
2114
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -2080,6 +2140,10 @@ h1 {
2080
2140
  background-color: hsl(var(--accent));
2081
2141
  }
2082
2142
 
2143
+ .data-\[state\=unchecked\]\:bg-input[data-state="unchecked"] {
2144
+ background-color: hsl(var(--input));
2145
+ }
2146
+
2083
2147
  .data-\[selected\=true\]\:text-accent-foreground[data-selected="true"] {
2084
2148
  color: hsl(var(--accent-foreground));
2085
2149
  }
@@ -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-Dg7mXHRE.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-DZ1A0VH0.css">
8
+ <script type="module" crossorigin src="/assets/index-3LzLs-Yz.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CFrqgd8F.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.16.7",
3
+ "version": "0.16.8",
4
4
  "description": "Model Context Protocol inspector",
5
5
  "license": "MIT",
6
6
  "author": "Anthropic, PBC (https://anthropic.com)",
@@ -47,11 +47,12 @@
47
47
  "check-version": "node scripts/check-version-consistency.js"
48
48
  },
49
49
  "dependencies": {
50
- "@modelcontextprotocol/inspector-cli": "^0.16.7",
51
- "@modelcontextprotocol/inspector-client": "^0.16.7",
52
- "@modelcontextprotocol/inspector-server": "^0.16.7",
50
+ "@modelcontextprotocol/inspector-cli": "^0.16.8",
51
+ "@modelcontextprotocol/inspector-client": "^0.16.8",
52
+ "@modelcontextprotocol/inspector-server": "^0.16.8",
53
53
  "@modelcontextprotocol/sdk": "^1.18.0",
54
54
  "concurrently": "^9.2.0",
55
+ "node-fetch": "^3.3.2",
55
56
  "open": "^10.2.0",
56
57
  "shell-quote": "^1.8.3",
57
58
  "spawn-rx": "^5.1.2",
@@ -2,6 +2,10 @@
2
2
  import cors from "cors";
3
3
  import { parseArgs } from "node:util";
4
4
  import { parse as shellParseArgs } from "shell-quote";
5
+ import nodeFetch, { Headers as NodeHeaders } from "node-fetch";
6
+ // Type-compatible wrappers for node-fetch to work with browser-style types
7
+ const fetch = nodeFetch;
8
+ const Headers = NodeHeaders;
5
9
  import { SSEClientTransport, SseError, } from "@modelcontextprotocol/sdk/client/sse.js";
6
10
  import { StdioClientTransport, getDefaultEnvironment, } from "@modelcontextprotocol/sdk/client/stdio.js";
7
11
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
@@ -36,8 +40,8 @@ const getHttpHeaders = (req) => {
36
40
  if (lowerKey.startsWith("mcp-") ||
37
41
  lowerKey === "authorization" ||
38
42
  lowerKey === "last-event-id") {
39
- // Exclude the proxy's own authentication header
40
- if (lowerKey !== "x-mcp-proxy-auth") {
43
+ // Exclude the proxy's own authentication header and the Client <-> Proxy session ID header
44
+ if (lowerKey !== "x-mcp-proxy-auth" && lowerKey !== "mcp-session-id") {
41
45
  const value = req.headers[key];
42
46
  if (typeof value === "string") {
43
47
  // If the value is a string, use it directly
@@ -71,6 +75,26 @@ const getHttpHeaders = (req) => {
71
75
  }
72
76
  }
73
77
  }
78
+ // Handle multiple custom headers (new approach)
79
+ if (req.headers["x-custom-auth-headers"] !== undefined) {
80
+ try {
81
+ const customHeaderNames = JSON.parse(req.headers["x-custom-auth-headers"]);
82
+ if (Array.isArray(customHeaderNames)) {
83
+ customHeaderNames.forEach((headerName) => {
84
+ const lowerCaseHeaderName = headerName.toLowerCase();
85
+ if (req.headers[lowerCaseHeaderName] !== undefined) {
86
+ const value = req.headers[lowerCaseHeaderName];
87
+ headers[headerName] = Array.isArray(value)
88
+ ? value[value.length - 1]
89
+ : value;
90
+ }
91
+ });
92
+ }
93
+ }
94
+ catch (error) {
95
+ console.warn("Failed to parse x-custom-auth-headers:", error);
96
+ }
97
+ }
74
98
  return headers;
75
99
  };
76
100
  /**
@@ -158,13 +182,33 @@ const authMiddleware = (req, res, next) => {
158
182
  }
159
183
  next();
160
184
  };
185
+ /**
186
+ * Converts a Node.js ReadableStream to a web-compatible ReadableStream
187
+ * This is necessary for the EventSource polyfill which expects web streams
188
+ */
189
+ const createWebReadableStream = (nodeStream) => {
190
+ return new ReadableStream({
191
+ start(controller) {
192
+ nodeStream.on("data", (chunk) => {
193
+ controller.enqueue(chunk);
194
+ });
195
+ nodeStream.on("end", () => {
196
+ controller.close();
197
+ });
198
+ nodeStream.on("error", (err) => {
199
+ controller.error(err);
200
+ });
201
+ },
202
+ });
203
+ };
161
204
  /**
162
205
  * Creates a `fetch` function that merges dynamic session headers with the
163
206
  * headers from the actual request, ensuring that request-specific headers like
164
- * `Content-Type` are preserved.
207
+ * `Content-Type` are preserved. For SSE requests, it also converts Node.js
208
+ * streams to web-compatible streams.
165
209
  */
166
210
  const createCustomFetch = (headerHolder) => {
167
- return (input, init) => {
211
+ return async (input, init) => {
168
212
  // Determine the headers from the original request/init.
169
213
  // The SDK may pass a Request object or a URL and an init object.
170
214
  const originalHeaders = input instanceof Request ? input.headers : init?.headers;
@@ -175,8 +219,34 @@ const createCustomFetch = (headerHolder) => {
175
219
  new Headers(originalHeaders).forEach((value, key) => {
176
220
  finalHeaders.set(key, value);
177
221
  });
178
- // This works for both `fetch(url, init)` and `fetch(request)` style calls.
179
- return fetch(input, { ...init, headers: finalHeaders });
222
+ // Convert Headers to a plain object for node-fetch compatibility
223
+ const headersObject = {};
224
+ finalHeaders.forEach((value, key) => {
225
+ headersObject[key] = value;
226
+ });
227
+ // Get the response from node-fetch (cast input and init to handle type differences)
228
+ const response = await fetch(input, { ...init, headers: headersObject });
229
+ // Check if this is an SSE request by looking at the Accept header
230
+ const acceptHeader = finalHeaders.get("Accept");
231
+ const isSSE = acceptHeader?.includes("text/event-stream");
232
+ if (isSSE && response.body) {
233
+ // For SSE requests, we need to convert the Node.js stream to a web ReadableStream
234
+ // because the EventSource polyfill expects web-compatible streams
235
+ const webStream = createWebReadableStream(response.body);
236
+ // Create a new response with the web-compatible stream
237
+ // Convert node-fetch headers to plain object for web Response compatibility
238
+ const responseHeaders = {};
239
+ response.headers.forEach((value, key) => {
240
+ responseHeaders[key] = value;
241
+ });
242
+ return new Response(webStream, {
243
+ status: response.status,
244
+ statusText: response.statusText,
245
+ headers: responseHeaders,
246
+ });
247
+ }
248
+ // For non-SSE requests, return the response as-is (cast to handle type differences)
249
+ return response;
180
250
  };
181
251
  };
182
252
  const createTransport = async (req) => {