@modelcontextprotocol/inspector 0.16.7 → 0.17.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.
@@ -281,7 +281,7 @@ pre[class*="language-"] {
281
281
  --tw-contain-paint: ;
282
282
  --tw-contain-style: ;
283
283
  }/*
284
- ! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
284
+ ! tailwindcss v3.4.18 | MIT License | https://tailwindcss.com
285
285
  *//*
286
286
  1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
287
287
  2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
@@ -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
  }
@@ -812,6 +815,9 @@ video {
812
815
  .-top-2 {
813
816
  top: -0.5rem;
814
817
  }
818
+ .left-3 {
819
+ left: 0.75rem;
820
+ }
815
821
  .left-\[50\%\] {
816
822
  left: 50%;
817
823
  }
@@ -830,6 +836,9 @@ video {
830
836
  .top-1 {
831
837
  top: 0.25rem;
832
838
  }
839
+ .top-1\/2 {
840
+ top: 50%;
841
+ }
833
842
  .top-2 {
834
843
  top: 0.5rem;
835
844
  }
@@ -839,6 +848,9 @@ video {
839
848
  .top-\[50\%\] {
840
849
  top: 50%;
841
850
  }
851
+ .z-10 {
852
+ z-index: 10;
853
+ }
842
854
  .z-50 {
843
855
  z-index: 50;
844
856
  }
@@ -989,6 +1001,9 @@ video {
989
1001
  .max-h-screen {
990
1002
  max-height: 100vh;
991
1003
  }
1004
+ .min-h-\[100px\] {
1005
+ min-height: 100px;
1006
+ }
992
1007
  .min-h-\[60px\] {
993
1008
  min-height: 60px;
994
1009
  }
@@ -1010,6 +1025,9 @@ video {
1010
1025
  .w-5 {
1011
1026
  width: 1.25rem;
1012
1027
  }
1028
+ .w-6 {
1029
+ width: 1.5rem;
1030
+ }
1013
1031
  .w-72 {
1014
1032
  width: 18rem;
1015
1033
  }
@@ -1043,6 +1061,9 @@ video {
1043
1061
  .max-w-md {
1044
1062
  max-width: 28rem;
1045
1063
  }
1064
+ .max-w-xs {
1065
+ max-width: 20rem;
1066
+ }
1046
1067
  .flex-1 {
1047
1068
  flex: 1 1 0%;
1048
1069
  }
@@ -1055,6 +1076,10 @@ video {
1055
1076
  .origin-\[--radix-tooltip-content-transform-origin\] {
1056
1077
  transform-origin: var(--radix-tooltip-content-transform-origin);
1057
1078
  }
1079
+ .-translate-y-1\/2 {
1080
+ --tw-translate-y: -50%;
1081
+ 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));
1082
+ }
1058
1083
  .translate-x-\[-50\%\] {
1059
1084
  --tw-translate-x: -50%;
1060
1085
  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));
@@ -1063,6 +1088,9 @@ video {
1063
1088
  --tw-translate-y: -50%;
1064
1089
  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));
1065
1090
  }
1091
+ .transform {
1092
+ 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));
1093
+ }
1066
1094
  @keyframes spin {
1067
1095
 
1068
1096
  to {
@@ -1086,6 +1114,9 @@ video {
1086
1114
  -moz-user-select: none;
1087
1115
  user-select: none;
1088
1116
  }
1117
+ .resize-none {
1118
+ resize: none;
1119
+ }
1089
1120
  .grid-cols-2 {
1090
1121
  grid-template-columns: repeat(2, minmax(0, 1fr));
1091
1122
  }
@@ -1271,6 +1302,9 @@ video {
1271
1302
  --tw-border-opacity: 1;
1272
1303
  border-color: rgb(239 68 68 / var(--tw-border-opacity, 1));
1273
1304
  }
1305
+ .border-transparent {
1306
+ border-color: transparent;
1307
+ }
1274
1308
  .border-t-transparent {
1275
1309
  border-top-color: transparent;
1276
1310
  }
@@ -1421,6 +1455,10 @@ video {
1421
1455
  padding-top: 0.75rem;
1422
1456
  padding-bottom: 0.75rem;
1423
1457
  }
1458
+ .py-4 {
1459
+ padding-top: 1rem;
1460
+ padding-bottom: 1rem;
1461
+ }
1424
1462
  .py-6 {
1425
1463
  padding-top: 1.5rem;
1426
1464
  padding-bottom: 1.5rem;
@@ -1428,6 +1466,9 @@ video {
1428
1466
  .pb-4 {
1429
1467
  padding-bottom: 1rem;
1430
1468
  }
1469
+ .pl-10 {
1470
+ padding-left: 2.5rem;
1471
+ }
1431
1472
  .pl-2 {
1432
1473
  padding-left: 0.5rem;
1433
1474
  }
@@ -1649,6 +1690,11 @@ video {
1649
1690
  .outline {
1650
1691
  outline-style: solid;
1651
1692
  }
1693
+ .ring-0 {
1694
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
1695
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
1696
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
1697
+ }
1652
1698
  .ring-offset-background {
1653
1699
  --tw-ring-offset-color: hsl(var(--background));
1654
1700
  }
@@ -1679,12 +1725,20 @@ video {
1679
1725
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1680
1726
  transition-duration: 150ms;
1681
1727
  }
1728
+ .transition-transform {
1729
+ transition-property: transform;
1730
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1731
+ transition-duration: 150ms;
1732
+ }
1682
1733
  .duration-200 {
1683
1734
  transition-duration: 200ms;
1684
1735
  }
1685
1736
  .duration-300 {
1686
1737
  transition-duration: 300ms;
1687
1738
  }
1739
+ .ease-in-out {
1740
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1741
+ }
1688
1742
  @keyframes enter {
1689
1743
 
1690
1744
  from {
@@ -1720,6 +1774,9 @@ video {
1720
1774
  .duration-300 {
1721
1775
  animation-duration: 300ms;
1722
1776
  }
1777
+ .ease-in-out {
1778
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1779
+ }
1723
1780
  .running {
1724
1781
  animation-play-state: running;
1725
1782
  }
@@ -1816,6 +1873,11 @@ h1 {
1816
1873
  background-color: hsl(var(--destructive) / 0.9);
1817
1874
  }
1818
1875
 
1876
+ .hover\:bg-gray-100:hover {
1877
+ --tw-bg-opacity: 1;
1878
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
1879
+ }
1880
+
1819
1881
  .hover\:bg-gray-50:hover {
1820
1882
  --tw-bg-opacity: 1;
1821
1883
  background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
@@ -1833,6 +1895,11 @@ h1 {
1833
1895
  background-color: hsl(var(--primary) / 0.9);
1834
1896
  }
1835
1897
 
1898
+ .hover\:bg-red-50:hover {
1899
+ --tw-bg-opacity: 1;
1900
+ background-color: rgb(254 242 242 / var(--tw-bg-opacity, 1));
1901
+ }
1902
+
1836
1903
  .hover\:bg-secondary:hover {
1837
1904
  background-color: hsl(var(--secondary));
1838
1905
  }
@@ -1859,6 +1926,11 @@ h1 {
1859
1926
  color: hsl(var(--foreground));
1860
1927
  }
1861
1928
 
1929
+ .hover\:text-red-700:hover {
1930
+ --tw-text-opacity: 1;
1931
+ color: rgb(185 28 28 / var(--tw-text-opacity, 1));
1932
+ }
1933
+
1862
1934
  .hover\:underline:hover {
1863
1935
  text-decoration-line: underline;
1864
1936
  }
@@ -1943,6 +2015,10 @@ h1 {
1943
2015
  --tw-ring-offset-width: 2px;
1944
2016
  }
1945
2017
 
2018
+ .focus-visible\:ring-offset-background:focus-visible {
2019
+ --tw-ring-offset-color: hsl(var(--background));
2020
+ }
2021
+
1946
2022
  .disabled\:pointer-events-none:disabled {
1947
2023
  pointer-events: none;
1948
2024
  }
@@ -2049,6 +2125,16 @@ h1 {
2049
2125
  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
2126
  }
2051
2127
 
2128
+ .data-\[state\=checked\]\:translate-x-4[data-state="checked"] {
2129
+ --tw-translate-x: 1rem;
2130
+ 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));
2131
+ }
2132
+
2133
+ .data-\[state\=unchecked\]\:translate-x-0[data-state="unchecked"] {
2134
+ --tw-translate-x: 0px;
2135
+ 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));
2136
+ }
2137
+
2052
2138
  .data-\[swipe\=cancel\]\:translate-x-0[data-swipe="cancel"] {
2053
2139
  --tw-translate-x: 0px;
2054
2140
  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 +2166,10 @@ h1 {
2080
2166
  background-color: hsl(var(--accent));
2081
2167
  }
2082
2168
 
2169
+ .data-\[state\=unchecked\]\:bg-input[data-state="unchecked"] {
2170
+ background-color: hsl(var(--input));
2171
+ }
2172
+
2083
2173
  .data-\[selected\=true\]\:text-accent-foreground[data-selected="true"] {
2084
2174
  color: hsl(var(--accent-foreground));
2085
2175
  }
@@ -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-BB0Z_sAV.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-DJXA50Oy.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.17.0",
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.17.0",
51
+ "@modelcontextprotocol/inspector-client": "^0.17.0",
52
+ "@modelcontextprotocol/inspector-server": "^0.17.0",
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) => {