@modelcontextprotocol/inspector 0.15.0 → 0.16.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.
- package/README.md +9 -3
- package/cli/build/cli.js +5 -32
- package/client/bin/client.js +11 -6
- package/client/bin/start.js +64 -28
- package/client/dist/assets/{OAuthCallback-CaW3Hcqw.js → OAuthCallback-CaDIOg8Q.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-DiBt_oxh.js → OAuthDebugCallback-Ccjj44Wa.js} +1 -1
- package/client/dist/assets/{index-C1MLjTGf.css → index-BwWj6LL9.css} +0 -4
- package/client/dist/assets/{index-BNqYF5Na.js → index-CPgI0-gs.js} +442 -169
- package/client/dist/index.html +3 -3
- package/package.json +10 -4
- package/server/build/index.js +8 -12
- package/server/build/mcpProxy.js +4 -3
package/README.md
CHANGED
|
@@ -168,20 +168,20 @@ DANGEROUSLY_OMIT_AUTH=true npm start
|
|
|
168
168
|
|
|
169
169
|
#### Local-only Binding
|
|
170
170
|
|
|
171
|
-
By default, the MCP Inspector proxy server
|
|
171
|
+
By default, both the MCP Inspector proxy server and client bind only to `localhost` to prevent network access. This ensures they are not accessible from other devices on the network. If you need to bind to all interfaces for development purposes, you can override this with the `HOST` environment variable:
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
174
|
HOST=0.0.0.0 npm start
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
**Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes.
|
|
177
|
+
**Warning:** Only bind to all interfaces in trusted network environments, as this exposes the proxy server's ability to execute local processes and both services to network access.
|
|
178
178
|
|
|
179
179
|
#### DNS Rebinding Protection
|
|
180
180
|
|
|
181
181
|
To prevent DNS rebinding attacks, the MCP Inspector validates the `Origin` header on incoming requests. By default, only requests from the client origin are allowed (respects `CLIENT_PORT` if set, defaulting to port 6274). You can configure additional allowed origins by setting the `ALLOWED_ORIGINS` environment variable (comma-separated list):
|
|
182
182
|
|
|
183
183
|
```bash
|
|
184
|
-
ALLOWED_ORIGINS=http://localhost:6274,http://
|
|
184
|
+
ALLOWED_ORIGINS=http://localhost:6274,http://localhost:8000 npm start
|
|
185
185
|
```
|
|
186
186
|
|
|
187
187
|
### Configuration
|
|
@@ -254,6 +254,12 @@ Development mode:
|
|
|
254
254
|
|
|
255
255
|
```bash
|
|
256
256
|
npm run dev
|
|
257
|
+
|
|
258
|
+
# To co-develop with the typescript-sdk package (assuming it's cloned in ../typescript-sdk; set MCP_SDK otherwise):
|
|
259
|
+
npm run dev:sdk "cd sdk && npm run examples:simple-server:w"
|
|
260
|
+
# then open http://localhost:3000/mcp as SHTTP in the inspector.
|
|
261
|
+
# To go back to the deployed SDK version:
|
|
262
|
+
# npm run unlink:sdk && npm i
|
|
257
263
|
```
|
|
258
264
|
|
|
259
265
|
> **Note for Windows users:**
|
package/cli/build/cli.js
CHANGED
|
@@ -24,50 +24,23 @@ function delay(ms) {
|
|
|
24
24
|
return new Promise((resolve) => setTimeout(resolve, ms, true));
|
|
25
25
|
}
|
|
26
26
|
async function runWebClient(args) {
|
|
27
|
-
const inspectorServerPath = resolve(__dirname, "../../", "server", "build", "index.js");
|
|
28
27
|
// Path to the client entry point
|
|
29
|
-
const inspectorClientPath = resolve(__dirname, "../../", "client", "bin", "
|
|
30
|
-
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
|
|
31
|
-
const SERVER_PORT = process.env.SERVER_PORT ?? "6277";
|
|
32
|
-
console.log("Starting MCP inspector...");
|
|
28
|
+
const inspectorClientPath = resolve(__dirname, "../../", "client", "bin", "start.js");
|
|
33
29
|
const abort = new AbortController();
|
|
34
30
|
let cancelled = false;
|
|
35
31
|
process.on("SIGINT", () => {
|
|
36
32
|
cancelled = true;
|
|
37
33
|
abort.abort();
|
|
38
34
|
});
|
|
39
|
-
let server;
|
|
40
|
-
let serverOk;
|
|
41
35
|
try {
|
|
42
|
-
|
|
43
|
-
inspectorServerPath,
|
|
44
|
-
...(args.command ? [`--env`, args.command] : []),
|
|
45
|
-
...(args.args ? [`--args=${args.args.join(" ")}`] : []),
|
|
46
|
-
], {
|
|
47
|
-
env: {
|
|
48
|
-
...process.env,
|
|
49
|
-
PORT: SERVER_PORT,
|
|
50
|
-
MCP_ENV_VARS: JSON.stringify(args.envArgs),
|
|
51
|
-
},
|
|
36
|
+
await spawnPromise("node", [inspectorClientPath], {
|
|
52
37
|
signal: abort.signal,
|
|
53
38
|
echoOutput: true,
|
|
54
39
|
});
|
|
55
|
-
// Make sure server started before starting client
|
|
56
|
-
serverOk = await Promise.race([server, delay(2 * 1000)]);
|
|
57
40
|
}
|
|
58
|
-
catch (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await spawnPromise("node", [inspectorClientPath], {
|
|
62
|
-
env: { ...process.env, PORT: CLIENT_PORT },
|
|
63
|
-
signal: abort.signal,
|
|
64
|
-
echoOutput: true,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
if (!cancelled || process.env.DEBUG)
|
|
69
|
-
throw e;
|
|
70
|
-
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
if (!cancelled || process.env.DEBUG)
|
|
43
|
+
throw e;
|
|
71
44
|
}
|
|
72
45
|
}
|
|
73
46
|
async function runCli(args) {
|
package/client/bin/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import open from "open";
|
|
3
4
|
import { join, dirname } from "path";
|
|
4
5
|
import { fileURLToPath } from "url";
|
|
5
6
|
import handler from "serve-handler";
|
|
@@ -39,19 +40,23 @@ const server = http.createServer((request, response) => {
|
|
|
39
40
|
return handler(request, response, handlerOptions);
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
const port = process.env.
|
|
43
|
+
const port = parseInt(process.env.CLIENT_PORT || "6274", 10);
|
|
44
|
+
const host = process.env.HOST || "localhost";
|
|
43
45
|
server.on("listening", () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
46
|
+
const url = process.env.INSPECTOR_URL || `http://${host}:${port}`;
|
|
47
|
+
console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
|
|
48
|
+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
|
|
49
|
+
console.log(`🌐 Opening browser...`);
|
|
50
|
+
open(url);
|
|
51
|
+
}
|
|
47
52
|
});
|
|
48
53
|
server.on("error", (err) => {
|
|
49
54
|
if (err.message.includes(`EADDRINUSE`)) {
|
|
50
55
|
console.error(
|
|
51
|
-
`❌ MCP Inspector PORT IS IN USE at http
|
|
56
|
+
`❌ MCP Inspector PORT IS IN USE at http://${host}:${port} ❌ `,
|
|
52
57
|
);
|
|
53
58
|
} else {
|
|
54
59
|
throw err;
|
|
55
60
|
}
|
|
56
61
|
});
|
|
57
|
-
server.listen(port);
|
|
62
|
+
server.listen(port, host);
|
package/client/bin/start.js
CHANGED
|
@@ -7,11 +7,26 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
import { randomBytes } from "crypto";
|
|
8
8
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
|
|
10
11
|
|
|
11
12
|
function delay(ms) {
|
|
12
13
|
return new Promise((resolve) => setTimeout(resolve, ms, true));
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
function getClientUrl(port, authDisabled, sessionToken, serverPort) {
|
|
17
|
+
const host = process.env.HOST || "localhost";
|
|
18
|
+
const baseUrl = `http://${host}:${port}`;
|
|
19
|
+
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
if (serverPort && serverPort !== DEFAULT_MCP_PROXY_LISTEN_PORT) {
|
|
22
|
+
params.set("MCP_PROXY_PORT", serverPort);
|
|
23
|
+
}
|
|
24
|
+
if (!authDisabled) {
|
|
25
|
+
params.set("MCP_PROXY_AUTH_TOKEN", sessionToken);
|
|
26
|
+
}
|
|
27
|
+
return params.size > 0 ? `${baseUrl}/?${params.toString()}` : baseUrl;
|
|
28
|
+
}
|
|
29
|
+
|
|
15
30
|
async function startDevServer(serverOptions) {
|
|
16
31
|
const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } =
|
|
17
32
|
serverOptions;
|
|
@@ -23,8 +38,8 @@ async function startDevServer(serverOptions) {
|
|
|
23
38
|
cwd: resolve(__dirname, "../..", "server"),
|
|
24
39
|
env: {
|
|
25
40
|
...process.env,
|
|
26
|
-
|
|
27
|
-
CLIENT_PORT
|
|
41
|
+
SERVER_PORT,
|
|
42
|
+
CLIENT_PORT,
|
|
28
43
|
MCP_PROXY_TOKEN: sessionToken,
|
|
29
44
|
MCP_ENV_VARS: JSON.stringify(envVars),
|
|
30
45
|
},
|
|
@@ -82,8 +97,8 @@ async function startProdServer(serverOptions) {
|
|
|
82
97
|
{
|
|
83
98
|
env: {
|
|
84
99
|
...process.env,
|
|
85
|
-
|
|
86
|
-
CLIENT_PORT
|
|
100
|
+
SERVER_PORT,
|
|
101
|
+
CLIENT_PORT,
|
|
87
102
|
MCP_PROXY_TOKEN: sessionToken,
|
|
88
103
|
MCP_ENV_VARS: JSON.stringify(envVars),
|
|
89
104
|
},
|
|
@@ -99,30 +114,40 @@ async function startProdServer(serverOptions) {
|
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
async function startDevClient(clientOptions) {
|
|
102
|
-
const {
|
|
103
|
-
|
|
117
|
+
const {
|
|
118
|
+
CLIENT_PORT,
|
|
119
|
+
SERVER_PORT,
|
|
120
|
+
authDisabled,
|
|
121
|
+
sessionToken,
|
|
122
|
+
abort,
|
|
123
|
+
cancelled,
|
|
124
|
+
} = clientOptions;
|
|
104
125
|
const clientCommand = "npx";
|
|
105
|
-
const
|
|
126
|
+
const host = process.env.HOST || "localhost";
|
|
127
|
+
const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
|
|
106
128
|
|
|
107
129
|
const client = spawn(clientCommand, clientArgs, {
|
|
108
130
|
cwd: resolve(__dirname, ".."),
|
|
109
|
-
env: { ...process.env,
|
|
131
|
+
env: { ...process.env, CLIENT_PORT },
|
|
110
132
|
signal: abort.signal,
|
|
111
133
|
echoOutput: true,
|
|
112
134
|
});
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
136
|
+
const url = getClientUrl(
|
|
137
|
+
CLIENT_PORT,
|
|
138
|
+
authDisabled,
|
|
139
|
+
sessionToken,
|
|
140
|
+
SERVER_PORT,
|
|
141
|
+
);
|
|
119
142
|
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
// Give vite time to start before opening or logging the URL
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
console.log(`\n🚀 MCP Inspector is up and running at:\n ${url}\n`);
|
|
146
|
+
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
|
|
147
|
+
console.log("🌐 Opening browser...");
|
|
122
148
|
open(url);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
149
|
+
}
|
|
150
|
+
}, 3000);
|
|
126
151
|
|
|
127
152
|
await new Promise((resolve) => {
|
|
128
153
|
client.subscribe({
|
|
@@ -139,7 +164,14 @@ async function startDevClient(clientOptions) {
|
|
|
139
164
|
}
|
|
140
165
|
|
|
141
166
|
async function startProdClient(clientOptions) {
|
|
142
|
-
const {
|
|
167
|
+
const {
|
|
168
|
+
CLIENT_PORT,
|
|
169
|
+
SERVER_PORT,
|
|
170
|
+
authDisabled,
|
|
171
|
+
sessionToken,
|
|
172
|
+
abort,
|
|
173
|
+
cancelled,
|
|
174
|
+
} = clientOptions;
|
|
143
175
|
const inspectorClientPath = resolve(
|
|
144
176
|
__dirname,
|
|
145
177
|
"../..",
|
|
@@ -148,16 +180,19 @@ async function startProdClient(clientOptions) {
|
|
|
148
180
|
"client.js",
|
|
149
181
|
);
|
|
150
182
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
183
|
+
const url = getClientUrl(
|
|
184
|
+
CLIENT_PORT,
|
|
185
|
+
authDisabled,
|
|
186
|
+
sessionToken,
|
|
187
|
+
SERVER_PORT,
|
|
188
|
+
);
|
|
158
189
|
|
|
159
190
|
await spawnPromise("node", [inspectorClientPath], {
|
|
160
|
-
env: {
|
|
191
|
+
env: {
|
|
192
|
+
...process.env,
|
|
193
|
+
CLIENT_PORT,
|
|
194
|
+
INSPECTOR_URL: url,
|
|
195
|
+
},
|
|
161
196
|
signal: abort.signal,
|
|
162
197
|
echoOutput: true,
|
|
163
198
|
});
|
|
@@ -204,7 +239,7 @@ async function main() {
|
|
|
204
239
|
}
|
|
205
240
|
|
|
206
241
|
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
|
|
207
|
-
const SERVER_PORT = process.env.SERVER_PORT ??
|
|
242
|
+
const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT;
|
|
208
243
|
|
|
209
244
|
console.log(
|
|
210
245
|
isDev
|
|
@@ -249,6 +284,7 @@ async function main() {
|
|
|
249
284
|
try {
|
|
250
285
|
const clientOptions = {
|
|
251
286
|
CLIENT_PORT,
|
|
287
|
+
SERVER_PORT,
|
|
252
288
|
authDisabled,
|
|
253
289
|
sessionToken,
|
|
254
290
|
abort,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as useToast, r as reactExports, j as jsxRuntimeExports, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-
|
|
1
|
+
import { u as useToast, r as reactExports, j as jsxRuntimeExports, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-CPgI0-gs.js";
|
|
2
2
|
import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
|
|
3
3
|
const OAuthCallback = ({ onConnect }) => {
|
|
4
4
|
const { toast } = useToast();
|
package/client/dist/assets/{OAuthDebugCallback-DiBt_oxh.js → OAuthDebugCallback-Ccjj44Wa.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as reactExports, S as SESSION_KEYS, j as jsxRuntimeExports } from "./index-
|
|
1
|
+
import { r as reactExports, S as SESSION_KEYS, j as jsxRuntimeExports } from "./index-CPgI0-gs.js";
|
|
2
2
|
import { p as parseOAuthCallbackParams, g as generateOAuthErrorDescription } from "./oauthUtils-DTcoXpSP.js";
|
|
3
3
|
const OAuthDebugCallback = ({ onConnect }) => {
|
|
4
4
|
reactExports.useEffect(() => {
|