Skip to content

Commit 7c9cfa2

Browse files
committed
Merge branch 'feat/add-resource-link-support' of https://github.com/nandsha/mcp-inspector into feat/add-resource-link-support
2 parents c4587ba + c9ab61b commit 7c9cfa2

26 files changed

+1047
-181
lines changed

.github/workflows/e2e_tests.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ jobs:
2121
- uses: actions/checkout@v4
2222

2323
- uses: actions/setup-node@v4
24+
id: setup_node
2425
with:
25-
node-version: 18
26+
node-version-file: package.json
27+
cache: npm
2628

2729
# Cache Playwright browsers
2830
- name: Cache Playwright browsers
@@ -69,7 +71,7 @@ jobs:
6971
job-summary: true
7072
icon-style: "emojis"
7173
custom-info: |
72-
**Test Environment:** Ubuntu Latest, Node.js 18
74+
**Test Environment:** Ubuntu Latest, Node.js ${{ steps.setup_node.outputs.node-version }}
7375
**Browsers:** Chromium, Firefox
7476
7577
📊 [View Detailed HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) (download artifacts)

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919

2020
- uses: actions/setup-node@v4
2121
with:
22-
node-version: 18
22+
node-version-file: package.json
2323
cache: npm
2424

2525
# Working around https://github.com/npm/cli/issues/4828
@@ -53,7 +53,7 @@ jobs:
5353
- uses: actions/checkout@v4
5454
- uses: actions/setup-node@v4
5555
with:
56-
node-version: 18
56+
node-version-file: package.json
5757
cache: npm
5858
registry-url: "https://registry.npmjs.org"
5959

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22.x.x

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

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/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<title>MCP Inspector</title>
88
</head>
99
<body>
10-
<div id="root"></div>
10+
<div id="root" class="w-full"></div>
1111
<script type="module" src="/src/main.tsx"></script>
1212
</body>
1313
</html>

client/src/App.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
#root {
2-
margin: 0 auto;
3-
}
4-
51
.logo {
62
height: 6em;
73
padding: 1.5em;

client/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { z } from "zod";
5252
import "./App.css";
5353
import AuthDebugger from "./components/AuthDebugger";
5454
import ConsoleTab from "./components/ConsoleTab";
55-
import HistoryAndNotifications from "./components/History";
55+
import HistoryAndNotifications from "./components/HistoryAndNotifications";
5656
import PingTab from "./components/PingTab";
5757
import PromptsTab, { Prompt } from "./components/PromptsTab";
5858
import ResourcesTab from "./components/ResourcesTab";

0 commit comments

Comments
 (0)