Skip to content

Commit 5c15e50

Browse files
authored
Merge branch 'main' into patch-1
2 parents 80fcf1a + 3acc6d8 commit 5c15e50

File tree

14 files changed

+468
-112
lines changed

14 files changed

+468
-112
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

.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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ Development mode:
260260

261261
```bash
262262
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
263269
```
264270

265271
> **Note for Windows users:**

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/src/cli.ts

Lines changed: 7 additions & 49 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

client/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-client",
3-
"version": "0.15.0",
3+
"version": "0.16.1",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",

client/src/App.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ const App = () => {
8080
ResourceTemplate[]
8181
>([]);
8282
const [resourceContent, setResourceContent] = useState<string>("");
83+
const [resourceContentMap, setResourceContentMap] = useState<
84+
Record<string, string>
85+
>({});
8386
const [prompts, setPrompts] = useState<Prompt[]>([]);
8487
const [promptContent, setPromptContent] = useState<string>("");
8588
const [tools, setTools] = useState<Tool[]>([]);
@@ -461,7 +464,12 @@ const App = () => {
461464
ReadResourceResultSchema,
462465
"resources",
463466
);
464-
setResourceContent(JSON.stringify(response, null, 2));
467+
const content = JSON.stringify(response, null, 2);
468+
setResourceContent(content);
469+
setResourceContentMap((prev) => ({
470+
...prev,
471+
[uri]: content,
472+
}));
465473
};
466474

467475
const subscribeToResource = async (uri: string) => {
@@ -863,6 +871,11 @@ const App = () => {
863871
toolResult={toolResult}
864872
nextCursor={nextToolCursor}
865873
error={errors.tools}
874+
resourceContent={resourceContentMap}
875+
onReadResource={(uri: string) => {
876+
clearError("resources");
877+
readResource(uri);
878+
}}
866879
/>
867880
<ConsoleTab />
868881
<PingTab
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { useState, useCallback, useMemo, memo } from "react";
2+
import JsonView from "./JsonView";
3+
4+
interface ResourceLinkViewProps {
5+
uri: string;
6+
name?: string;
7+
description?: string;
8+
mimeType?: string;
9+
resourceContent: string;
10+
onReadResource?: (uri: string) => void;
11+
}
12+
13+
const ResourceLinkView = memo(
14+
({
15+
uri,
16+
name,
17+
description,
18+
mimeType,
19+
resourceContent,
20+
onReadResource,
21+
}: ResourceLinkViewProps) => {
22+
const [{ expanded, loading }, setState] = useState({
23+
expanded: false,
24+
loading: false,
25+
});
26+
27+
const expandedContent = useMemo(
28+
() =>
29+
expanded && resourceContent ? (
30+
<div className="mt-2">
31+
<div className="flex justify-between items-center mb-1">
32+
<span className="font-semibold text-green-600">Resource:</span>
33+
</div>
34+
<JsonView data={resourceContent} className="bg-background" />
35+
</div>
36+
) : null,
37+
[expanded, resourceContent],
38+
);
39+
40+
const handleClick = useCallback(() => {
41+
if (!onReadResource) return;
42+
if (!expanded) {
43+
setState((prev) => ({ ...prev, expanded: true, loading: true }));
44+
onReadResource(uri);
45+
setState((prev) => ({ ...prev, loading: false }));
46+
} else {
47+
setState((prev) => ({ ...prev, expanded: false }));
48+
}
49+
}, [expanded, onReadResource, uri]);
50+
51+
const handleKeyDown = useCallback(
52+
(e: React.KeyboardEvent) => {
53+
if ((e.key === "Enter" || e.key === " ") && onReadResource) {
54+
e.preventDefault();
55+
handleClick();
56+
}
57+
},
58+
[handleClick, onReadResource],
59+
);
60+
61+
return (
62+
<div className="text-sm text-foreground bg-secondary py-2 px-3 rounded">
63+
<div
64+
className="flex justify-between items-center cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 rounded"
65+
onClick={onReadResource ? handleClick : undefined}
66+
onKeyDown={onReadResource ? handleKeyDown : undefined}
67+
tabIndex={onReadResource ? 0 : -1}
68+
role="button"
69+
aria-expanded={expanded}
70+
aria-label={`${expanded ? "Collapse" : "Expand"} resource ${uri}`}
71+
>
72+
<div className="flex-1 min-w-0">
73+
<div className="flex items-start justify-between gap-2 mb-1">
74+
<span className="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline px-1 py-0.5 break-all font-mono flex-1 min-w-0">
75+
{uri}
76+
</span>
77+
<div className="flex items-center gap-2 flex-shrink-0">
78+
{mimeType && (
79+
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
80+
{mimeType}
81+
</span>
82+
)}
83+
{onReadResource && (
84+
<span className="ml-2 flex-shrink-0" aria-hidden="true">
85+
{loading ? (
86+
<div className="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
87+
) : (
88+
<span>{expanded ? "▼" : "▶"}</span>
89+
)}
90+
</span>
91+
)}
92+
</div>
93+
</div>
94+
{name && (
95+
<div className="font-semibold text-sm text-gray-900 dark:text-gray-100 mb-1">
96+
{name}
97+
</div>
98+
)}
99+
{description && (
100+
<p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
101+
{description}
102+
</p>
103+
)}
104+
</div>
105+
</div>
106+
{expandedContent}
107+
</div>
108+
);
109+
},
110+
);
111+
112+
export default ResourceLinkView;

0 commit comments

Comments
 (0)