Skip to content

Commit 0130cf8

Browse files
authored
Merge branch 'main' into notification-expansion-state
2 parents 4e68b93 + fbe6c11 commit 0130cf8

19 files changed

+783
-279
lines changed

.github/workflows/e2e_tests.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ on:
88

99
jobs:
1010
test:
11-
timeout-minutes: 5
11+
# Installing Playright dependencies can take quite awhile, and also depends on GitHub CI load.
12+
timeout-minutes: 15
1213
runs-on: ubuntu-latest
1314

1415
steps:
@@ -44,11 +45,12 @@ jobs:
4445
if: steps.cache-playwright.outputs.cache-hit != 'true'
4546

4647
- name: Run Playwright tests
48+
id: playwright-tests
4749
run: npm run test:e2e
4850

4951
- name: Upload Playwright Report and Screenshots
5052
uses: actions/upload-artifact@v4
51-
if: always()
53+
if: steps.playwright-tests.conclusion != 'skipped'
5254
with:
5355
name: playwright-report
5456
path: |
@@ -59,7 +61,7 @@ jobs:
5961

6062
- name: Publish Playwright Test Summary
6163
uses: daun/playwright-report-summary@v3
62-
if: always()
64+
if: steps.playwright-tests.conclusion != 'skipped'
6365
with:
6466
create-comment: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
6567
report-file: client/results.json

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Thanks for your interest in contributing! This guide explains how to get involve
77
1. Fork the repository and clone it locally
88
2. Install dependencies with `npm install`
99
3. Run `npm run dev` to start both client and server in development mode
10-
4. Use the web UI at http://127.0.0.1:6274 to interact with the inspector
10+
4. Use the web UI at http://localhost:6274 to interact with the inspector
1111

1212
## Development Process & Pull Requests
1313

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,20 +168,20 @@ DANGEROUSLY_OMIT_AUTH=true npm start
168168

169169
#### Local-only Binding
170170

171-
By default, the MCP Inspector proxy server binds only to `127.0.0.1` (localhost) to prevent network access. This ensures the server is 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:
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:
172172

173173
```bash
174174
HOST=0.0.0.0 npm start
175175
```
176176

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.
178178

179179
#### DNS Rebinding Protection
180180

181181
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):
182182

183183
```bash
184-
ALLOWED_ORIGINS=http://localhost:6274,http://127.0.0.1:6274,http://localhost:8000 npm start
184+
ALLOWED_ORIGINS=http://localhost:6274,http://localhost:8000 npm start
185185
```
186186

187187
### Configuration

cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-cli",
3-
"version": "0.14.3",
3+
"version": "0.15.0",
44
"description": "CLI for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -21,7 +21,7 @@
2121
},
2222
"devDependencies": {},
2323
"dependencies": {
24-
"@modelcontextprotocol/sdk": "^1.13.0",
24+
"@modelcontextprotocol/sdk": "^1.13.1",
2525
"commander": "^13.1.0",
2626
"spawn-rx": "^5.1.2"
2727
}

client/bin/client.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env node
22

3+
import open from "open";
34
import { join, dirname } from "path";
45
import { fileURLToPath } from "url";
56
import handler from "serve-handler";
@@ -39,19 +40,23 @@ const server = http.createServer((request, response) => {
3940
return handler(request, response, handlerOptions);
4041
});
4142

42-
const port = process.env.PORT || 6274;
43+
const port = parseInt(process.env.CLIENT_PORT || "6274", 10);
44+
const host = process.env.HOST || "localhost";
4345
server.on("listening", () => {
44-
console.log(
45-
`🔍 MCP Inspector is up and running at http://127.0.0.1:${port} 🚀`,
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+
}
4752
});
4853
server.on("error", (err) => {
4954
if (err.message.includes(`EADDRINUSE`)) {
5055
console.error(
51-
`❌ MCP Inspector PORT IS IN USE at http://127.0.0.1:${port} ❌ `,
56+
`❌ MCP Inspector PORT IS IN USE at http://${host}:${port} ❌ `,
5257
);
5358
} else {
5459
throw err;
5560
}
5661
});
57-
server.listen(port);
62+
server.listen(port, host);

client/bin/start.js

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,26 @@ import { fileURLToPath } from "url";
77
import { randomBytes } from "crypto";
88

99
const __dirname = dirname(fileURLToPath(import.meta.url));
10+
const DEFAULT_MCP_PROXY_LISTEN_PORT = "6277";
1011

1112
function delay(ms) {
1213
return new Promise((resolve) => setTimeout(resolve, ms, true));
1314
}
1415

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+
1530
async function startDevServer(serverOptions) {
1631
const { SERVER_PORT, CLIENT_PORT, sessionToken, envVars, abort } =
1732
serverOptions;
@@ -23,8 +38,8 @@ async function startDevServer(serverOptions) {
2338
cwd: resolve(__dirname, "../..", "server"),
2439
env: {
2540
...process.env,
26-
PORT: SERVER_PORT,
27-
CLIENT_PORT: CLIENT_PORT,
41+
SERVER_PORT,
42+
CLIENT_PORT,
2843
MCP_PROXY_TOKEN: sessionToken,
2944
MCP_ENV_VARS: JSON.stringify(envVars),
3045
},
@@ -82,8 +97,8 @@ async function startProdServer(serverOptions) {
8297
{
8398
env: {
8499
...process.env,
85-
PORT: SERVER_PORT,
86-
CLIENT_PORT: CLIENT_PORT,
100+
SERVER_PORT,
101+
CLIENT_PORT,
87102
MCP_PROXY_TOKEN: sessionToken,
88103
MCP_ENV_VARS: JSON.stringify(envVars),
89104
},
@@ -99,30 +114,40 @@ async function startProdServer(serverOptions) {
99114
}
100115

101116
async function startDevClient(clientOptions) {
102-
const { CLIENT_PORT, authDisabled, sessionToken, abort, cancelled } =
103-
clientOptions;
117+
const {
118+
CLIENT_PORT,
119+
SERVER_PORT,
120+
authDisabled,
121+
sessionToken,
122+
abort,
123+
cancelled,
124+
} = clientOptions;
104125
const clientCommand = "npx";
105-
const clientArgs = ["vite", "--port", CLIENT_PORT];
126+
const host = process.env.HOST || "localhost";
127+
const clientArgs = ["vite", "--port", CLIENT_PORT, "--host", host];
106128

107129
const client = spawn(clientCommand, clientArgs, {
108130
cwd: resolve(__dirname, ".."),
109-
env: { ...process.env, PORT: CLIENT_PORT },
131+
env: { ...process.env, CLIENT_PORT },
110132
signal: abort.signal,
111133
echoOutput: true,
112134
});
113135

114-
// Auto-open browser after vite starts
115-
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
116-
const url = authDisabled
117-
? `http://127.0.0.1:${CLIENT_PORT}`
118-
: `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
136+
const url = getClientUrl(
137+
CLIENT_PORT,
138+
authDisabled,
139+
sessionToken,
140+
SERVER_PORT,
141+
);
119142

120-
// Give vite time to start before opening browser
121-
setTimeout(() => {
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...");
122148
open(url);
123-
console.log(`\n🔗 Opening browser at: ${url}\n`);
124-
}, 3000);
125-
}
149+
}
150+
}, 3000);
126151

127152
await new Promise((resolve) => {
128153
client.subscribe({
@@ -139,7 +164,14 @@ async function startDevClient(clientOptions) {
139164
}
140165

141166
async function startProdClient(clientOptions) {
142-
const { CLIENT_PORT, authDisabled, sessionToken, abort } = clientOptions;
167+
const {
168+
CLIENT_PORT,
169+
SERVER_PORT,
170+
authDisabled,
171+
sessionToken,
172+
abort,
173+
cancelled,
174+
} = clientOptions;
143175
const inspectorClientPath = resolve(
144176
__dirname,
145177
"../..",
@@ -148,16 +180,19 @@ async function startProdClient(clientOptions) {
148180
"client.js",
149181
);
150182

151-
// Auto-open browser with token
152-
if (process.env.MCP_AUTO_OPEN_ENABLED !== "false") {
153-
const url = authDisabled
154-
? `http://127.0.0.1:${CLIENT_PORT}`
155-
: `http://127.0.0.1:${CLIENT_PORT}/?MCP_PROXY_AUTH_TOKEN=${sessionToken}`;
156-
open(url);
157-
}
183+
const url = getClientUrl(
184+
CLIENT_PORT,
185+
authDisabled,
186+
sessionToken,
187+
SERVER_PORT,
188+
);
158189

159190
await spawnPromise("node", [inspectorClientPath], {
160-
env: { ...process.env, PORT: CLIENT_PORT },
191+
env: {
192+
...process.env,
193+
CLIENT_PORT,
194+
INSPECTOR_URL: url,
195+
},
161196
signal: abort.signal,
162197
echoOutput: true,
163198
});
@@ -204,7 +239,7 @@ async function main() {
204239
}
205240

206241
const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
207-
const SERVER_PORT = process.env.SERVER_PORT ?? "6277";
242+
const SERVER_PORT = process.env.SERVER_PORT ?? DEFAULT_MCP_PROXY_LISTEN_PORT;
208243

209244
console.log(
210245
isDev
@@ -249,6 +284,7 @@ async function main() {
249284
try {
250285
const clientOptions = {
251286
CLIENT_PORT,
287+
SERVER_PORT,
252288
authDisabled,
253289
sessionToken,
254290
abort,

client/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-client",
3-
"version": "0.14.3",
3+
"version": "0.15.0",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -25,7 +25,7 @@
2525
"cleanup:e2e": "node e2e/global-teardown.js"
2626
},
2727
"dependencies": {
28-
"@modelcontextprotocol/sdk": "^1.13.0",
28+
"@modelcontextprotocol/sdk": "^1.13.1",
2929
"@radix-ui/react-checkbox": "^1.1.4",
3030
"ajv": "^6.12.6",
3131
"@radix-ui/react-dialog": "^1.1.3",
@@ -40,7 +40,7 @@
4040
"class-variance-authority": "^0.7.0",
4141
"clsx": "^2.1.1",
4242
"cmdk": "^1.0.4",
43-
"lucide-react": "^0.447.0",
43+
"lucide-react": "^0.523.0",
4444
"pkce-challenge": "^4.1.0",
4545
"prismjs": "^1.30.0",
4646
"react": "^18.3.1",

0 commit comments

Comments
 (0)