Skip to content

Commit 1ed9202

Browse files
authored
Merge branch 'main' into oleina/logging
2 parents 7ce0938 + cfc17e5 commit 1ed9202

28 files changed

+2048
-178
lines changed

.github/workflows/cli_tests.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CLI Tests
2+
3+
on:
4+
push:
5+
paths:
6+
- "cli/**"
7+
pull_request:
8+
paths:
9+
- "cli/**"
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
defaults:
15+
run:
16+
working-directory: ./cli
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version-file: package.json
24+
cache: npm
25+
26+
- name: Install dependencies
27+
run: |
28+
cd ..
29+
npm ci --ignore-scripts
30+
31+
- name: Build CLI
32+
run: npm run build
33+
34+
- name: Explicitly pre-install test dependencies
35+
run: npx -y @modelcontextprotocol/server-everything --help || true
36+
37+
- name: Run tests
38+
run: npm test
39+
env:
40+
NPM_CONFIG_YES: true
41+
CI: true

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ If you need to disable authentication (NOT RECOMMENDED), you can set the `DANGER
166166
DANGEROUSLY_OMIT_AUTH=true npm start
167167
```
168168

169+
You can also set the token via the `MCP_PROXY_AUTH_TOKEN` environment variable when starting the server:
170+
171+
```bash
172+
MCP_PROXY_AUTH_TOKEN=$(openssl rand -hex 32) npm start
173+
```
174+
169175
#### Local-only Binding
170176

171177
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:
@@ -309,7 +315,7 @@ npx @modelcontextprotocol/inspector --cli node build/index.js --method prompts/l
309315
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com
310316

311317
# Connect to a remote MCP server (with Streamable HTTP transport)
312-
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --transport http
318+
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --transport http --method tools/list
313319

314320
# Call a tool on a remote server
315321
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com --method tools/call --tool-name remotetool --tool-arg param=value

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.16.1",
3+
"version": "0.16.2",
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.1",
24+
"@modelcontextprotocol/sdk": "^1.17.0",
2525
"commander": "^13.1.0",
2626
"spawn-rx": "^5.1.2"
2727
}

cli/scripts/cli-tests.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const colors = {
1212

1313
import fs from "fs";
1414
import path from "path";
15-
import { execSync, spawn } from "child_process";
15+
import { spawn } from "child_process";
1616
import os from "os";
1717
import { fileURLToPath } from "url";
1818

@@ -680,7 +680,7 @@ async function runTests() {
680680
// Test 26: HTTP transport with explicit --transport http flag
681681
await runBasicTest(
682682
"http_transport_with_explicit_flag",
683-
"http://127.0.0.1:3001",
683+
"http://127.0.0.1:3001/mcp",
684684
"--transport",
685685
"http",
686686
"--cli",
@@ -710,6 +710,26 @@ async function runTests() {
710710
"tools/list",
711711
);
712712

713+
// Test 29: HTTP transport without URL (should fail)
714+
await runErrorTest(
715+
"http_transport_without_url",
716+
"--transport",
717+
"http",
718+
"--cli",
719+
"--method",
720+
"tools/list",
721+
);
722+
723+
// Test 30: SSE transport without URL (should fail)
724+
await runErrorTest(
725+
"sse_transport_without_url",
726+
"--transport",
727+
"sse",
728+
"--cli",
729+
"--method",
730+
"tools/list",
731+
);
732+
713733
// Kill HTTP server
714734
try {
715735
process.kill(-httpServer.pid);

cli/src/cli.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,21 @@ async function runWebClient(args: Args): Promise<void> {
6666
abort.abort();
6767
});
6868

69+
// Build arguments to pass to start.js
70+
const startArgs: string[] = [];
71+
72+
// Pass environment variables
73+
for (const [key, value] of Object.entries(args.envArgs)) {
74+
startArgs.push("-e", `${key}=${value}`);
75+
}
76+
77+
// Pass command and args (using -- to separate them)
78+
if (args.command) {
79+
startArgs.push("--", args.command, ...args.args);
80+
}
81+
6982
try {
70-
await spawnPromise("node", [inspectorClientPath], {
83+
await spawnPromise("node", [inspectorClientPath, ...startArgs], {
7184
signal: abort.signal,
7285
echoOutput: true,
7386
});
@@ -233,7 +246,7 @@ async function main(): Promise<void> {
233246
const args = parseArgs();
234247

235248
if (args.cli) {
236-
runCli(args);
249+
await runCli(args);
237250
} else {
238251
await runWebClient(args);
239252
}

cli/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ async function main(): Promise<void> {
287287
try {
288288
const args = parseArgs();
289289
await callMethod(args);
290+
// Explicitly exit to ensure process terminates in CI
291+
process.exit(0);
290292
} catch (error) {
291293
handleError(error);
292294
}

cli/src/transport.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,6 @@ export type TransportOptions = {
1414
url?: string;
1515
};
1616

17-
function createSSETransport(options: TransportOptions): Transport {
18-
const baseUrl = new URL(options.url ?? "");
19-
const sseUrl = baseUrl.pathname.endsWith("/sse")
20-
? baseUrl
21-
: new URL("/sse", baseUrl);
22-
23-
return new SSEClientTransport(sseUrl);
24-
}
25-
26-
function createHTTPTransport(options: TransportOptions): Transport {
27-
const baseUrl = new URL(options.url ?? "");
28-
const mcpUrl = baseUrl.pathname.endsWith("/mcp")
29-
? baseUrl
30-
: new URL("/mcp", baseUrl);
31-
32-
return new StreamableHTTPClientTransport(mcpUrl);
33-
}
34-
3517
function createStdioTransport(options: TransportOptions): Transport {
3618
let args: string[] = [];
3719

@@ -75,12 +57,18 @@ export function createTransport(options: TransportOptions): Transport {
7557
return createStdioTransport(options);
7658
}
7759

60+
// If not STDIO, then it must be either SSE or HTTP.
61+
if (!options.url) {
62+
throw new Error("URL must be provided for SSE or HTTP transport types.");
63+
}
64+
const url = new URL(options.url);
65+
7866
if (transportType === "sse") {
79-
return createSSETransport(options);
67+
return new SSEClientTransport(url);
8068
}
8169

8270
if (transportType === "http") {
83-
return createHTTPTransport(options);
71+
return new StreamableHTTPClientTransport(url);
8472
}
8573

8674
throw new Error(`Unsupported transport type: ${transportType}`);

client/bin/start.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async function startDevServer(serverOptions) {
4040
...process.env,
4141
SERVER_PORT,
4242
CLIENT_PORT,
43-
MCP_PROXY_TOKEN: sessionToken,
43+
MCP_PROXY_AUTH_TOKEN: sessionToken,
4444
MCP_ENV_VARS: JSON.stringify(envVars),
4545
},
4646
signal: abort.signal,
@@ -91,15 +91,17 @@ async function startProdServer(serverOptions) {
9191
"node",
9292
[
9393
inspectorServerPath,
94-
...(command ? [`--env`, command] : []),
95-
...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []),
94+
...(command ? [`--command`, command] : []),
95+
...(mcpServerArgs && mcpServerArgs.length > 0
96+
? [`--args`, mcpServerArgs.join(" ")]
97+
: []),
9698
],
9799
{
98100
env: {
99101
...process.env,
100102
SERVER_PORT,
101103
CLIENT_PORT,
102-
MCP_PROXY_TOKEN: sessionToken,
104+
MCP_PROXY_AUTH_TOKEN: sessionToken,
103105
MCP_ENV_VARS: JSON.stringify(envVars),
104106
},
105107
signal: abort.signal,
@@ -247,8 +249,9 @@ async function main() {
247249
: "Starting MCP inspector...",
248250
);
249251

250-
// Generate session token for authentication
251-
const sessionToken = randomBytes(32).toString("hex");
252+
// Use provided token from environment or generate a new one
253+
const sessionToken =
254+
process.env.MCP_PROXY_AUTH_TOKEN || randomBytes(32).toString("hex");
252255
const authDisabled = !!process.env.DANGEROUSLY_OMIT_AUTH;
253256

254257
const abort = new AbortController();

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.16.1",
3+
"version": "0.16.2",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -25,9 +25,8 @@
2525
"cleanup:e2e": "node e2e/global-teardown.js"
2626
},
2727
"dependencies": {
28-
"@modelcontextprotocol/sdk": "^1.13.1",
28+
"@modelcontextprotocol/sdk": "^1.17.0",
2929
"@radix-ui/react-checkbox": "^1.1.4",
30-
"ajv": "^6.12.6",
3130
"@radix-ui/react-dialog": "^1.1.3",
3231
"@radix-ui/react-icons": "^1.3.0",
3332
"@radix-ui/react-label": "^2.1.0",
@@ -37,6 +36,7 @@
3736
"@radix-ui/react-tabs": "^1.1.1",
3837
"@radix-ui/react-toast": "^1.2.6",
3938
"@radix-ui/react-tooltip": "^1.1.8",
39+
"ajv": "^6.12.6",
4040
"class-variance-authority": "^0.7.0",
4141
"clsx": "^2.1.1",
4242
"cmdk": "^1.0.4",

0 commit comments

Comments
 (0)