Skip to content

Commit 144755b

Browse files
authored
Merge branch 'main' into feature/elicitations
2 parents 6b204b5 + 1ea8e9a commit 144755b

26 files changed

+934
-160
lines changed

.github/workflows/claude.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Claude Code
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
issues:
9+
types: [opened, assigned]
10+
pull_request_review:
11+
types: [submitted]
12+
13+
jobs:
14+
claude:
15+
if: |
16+
(
17+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
18+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
19+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
20+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
21+
) &&
22+
(
23+
github.actor == 'ihrpr' ||
24+
github.actor == 'olaservo'
25+
)
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: read
29+
pull-requests: read
30+
issues: read
31+
id-token: write
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@v4
35+
with:
36+
fetch-depth: 1
37+
38+
- name: Run Claude Code
39+
id: claude
40+
uses: anthropics/claude-code-action@beta
41+
with:
42+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
43+
44+
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
45+
# model: "claude-opus-4-20250514"
46+
47+
# Optional: Customize the trigger phrase (default: @claude)
48+
# trigger_phrase: "/claude"
49+
50+
# Optional: Trigger when specific user is assigned to an issue
51+
# assignee_trigger: "claude-bot"
52+
53+
# Optional: Allow Claude to run specific commands
54+
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
55+
56+
# Optional: Add custom instructions for Claude to customize its behavior for your project
57+
# custom_instructions: |
58+
# Follow our coding standards
59+
# Ensure all new code has tests
60+
# Use TypeScript for new files
61+
62+
# Optional: Custom environment variables for Claude
63+
# claude_env: |
64+
# NODE_ENV: test

.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

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ client/tsconfig.app.tsbuildinfo
99
client/tsconfig.node.tsbuildinfo
1010
cli/build
1111
test-output
12+
# symlinked by `npm run link:sdk`:
13+
sdk
1214
client/playwright-report/
1315
client/results.json
1416
client/test-results/
15-

README.md

Lines changed: 13 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:
@@ -254,6 +260,12 @@ Development mode:
254260

255261
```bash
256262
npm run dev
263+
264+
# To co-develop with the typescript-sdk package (assuming it's cloned in ../typescript-sdk; set MCP_SDK otherwise):
265+
npm run dev:sdk "cd sdk && npm run examples:simple-server:w"
266+
# then open http://localhost:3000/mcp as SHTTP in the inspector.
267+
# To go back to the deployed SDK version:
268+
# npm run unlink:sdk && npm i
257269
```
258270

259271
> **Note for Windows users:**
@@ -303,7 +315,7 @@ npx @modelcontextprotocol/inspector --cli node build/index.js --method prompts/l
303315
npx @modelcontextprotocol/inspector --cli https://my-mcp-server.example.com
304316

305317
# Connect to a remote MCP server (with Streamable HTTP transport)
306-
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
307319

308320
# Call a tool on a remote server
309321
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-cli",
3-
"version": "0.15.0",
3+
"version": "0.16.1",
44
"description": "CLI for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",

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: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -50,71 +50,29 @@ function delay(ms: number): Promise<void> {
5050
}
5151

5252
async function runWebClient(args: Args): Promise<void> {
53-
const inspectorServerPath = resolve(
54-
__dirname,
55-
"../../",
56-
"server",
57-
"build",
58-
"index.js",
59-
);
60-
6153
// Path to the client entry point
6254
const inspectorClientPath = resolve(
6355
__dirname,
6456
"../../",
6557
"client",
6658
"bin",
67-
"client.js",
59+
"start.js",
6860
);
6961

70-
const CLIENT_PORT: string = process.env.CLIENT_PORT ?? "6274";
71-
const SERVER_PORT: string = process.env.SERVER_PORT ?? "6277";
72-
73-
console.log("Starting MCP inspector...");
74-
7562
const abort = new AbortController();
7663
let cancelled: boolean = false;
7764
process.on("SIGINT", () => {
7865
cancelled = true;
7966
abort.abort();
8067
});
8168

82-
let server: ReturnType<typeof spawnPromise>;
83-
let serverOk: unknown;
84-
8569
try {
86-
server = spawnPromise(
87-
"node",
88-
[
89-
inspectorServerPath,
90-
...(args.command ? [`--env`, args.command] : []),
91-
...(args.args ? [`--args=${args.args.join(" ")}`] : []),
92-
],
93-
{
94-
env: {
95-
...process.env,
96-
PORT: SERVER_PORT,
97-
MCP_ENV_VARS: JSON.stringify(args.envArgs),
98-
},
99-
signal: abort.signal,
100-
echoOutput: true,
101-
},
102-
);
103-
104-
// Make sure server started before starting client
105-
serverOk = await Promise.race([server, delay(2 * 1000)]);
106-
} catch (error) {}
107-
108-
if (serverOk) {
109-
try {
110-
await spawnPromise("node", [inspectorClientPath], {
111-
env: { ...process.env, PORT: CLIENT_PORT },
112-
signal: abort.signal,
113-
echoOutput: true,
114-
});
115-
} catch (e) {
116-
if (!cancelled || process.env.DEBUG) throw e;
117-
}
70+
await spawnPromise("node", [inspectorClientPath], {
71+
signal: abort.signal,
72+
echoOutput: true,
73+
});
74+
} catch (e) {
75+
if (!cancelled || process.env.DEBUG) throw e;
11876
}
11977
}
12078

@@ -275,7 +233,7 @@ async function main(): Promise<void> {
275233
const args = parseArgs();
276234

277235
if (args.cli) {
278-
runCli(args);
236+
await runCli(args);
279237
} else {
280238
await runWebClient(args);
281239
}

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: 5 additions & 4 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,
@@ -99,7 +99,7 @@ async function startProdServer(serverOptions) {
9999
...process.env,
100100
SERVER_PORT,
101101
CLIENT_PORT,
102-
MCP_PROXY_TOKEN: sessionToken,
102+
MCP_PROXY_AUTH_TOKEN: sessionToken,
103103
MCP_ENV_VARS: JSON.stringify(envVars),
104104
},
105105
signal: abort.signal,
@@ -247,8 +247,9 @@ async function main() {
247247
: "Starting MCP inspector...",
248248
);
249249

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

254255
const abort = new AbortController();

0 commit comments

Comments
 (0)