Skip to content

Commit 1e6063b

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 5c00b74 + e8d5e09 commit 1e6063b

19 files changed

+1029
-170
lines changed

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"dependencies": {
2626
"@modelcontextprotocol/sdk": "^1.11.5",
2727
"@radix-ui/react-checkbox": "^1.1.4",
28+
"ajv": "^6.12.6",
2829
"@radix-ui/react-dialog": "^1.1.3",
2930
"@radix-ui/react-icons": "^1.3.0",
3031
"@radix-ui/react-label": "^2.1.0",

client/src/App.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import { OAuthTokensSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
2121
import { SESSION_KEYS, getServerSpecificKey } from "./lib/constants";
2222
import { AuthDebuggerState } from "./lib/auth-types";
23+
import { cacheToolOutputSchemas } from "./utils/schemaUtils";
2324
import React, {
2425
Suspense,
2526
useCallback,
@@ -473,6 +474,8 @@ const App = () => {
473474
);
474475
setTools(response.tools);
475476
setNextToolCursor(response.nextCursor);
477+
// Cache output schemas for validation
478+
cacheToolOutputSchemas(response.tools);
476479
};
477480

478481
const callTool = async (name: string, params: Record<string, unknown>) => {
@@ -608,7 +611,7 @@ const App = () => {
608611
className="w-full p-4"
609612
onValueChange={(value) => (window.location.hash = value)}
610613
>
611-
<TabsList className="mb-4 p-0">
614+
<TabsList className="mb-4 py-0">
612615
<TabsTrigger
613616
value="resources"
614617
disabled={!serverCapabilities?.resources}
@@ -659,7 +662,7 @@ const App = () => {
659662
!serverCapabilities?.tools ? (
660663
<>
661664
<div className="flex items-center justify-center p-4">
662-
<p className="text-lg text-gray-500">
665+
<p className="text-lg text-gray-500 dark:text-gray-400">
663666
The connected server does not support any MCP
664667
capabilities
665668
</p>
@@ -759,6 +762,8 @@ const App = () => {
759762
clearTools={() => {
760763
setTools([]);
761764
setNextToolCursor(undefined);
765+
// Clear cached output schemas
766+
cacheToolOutputSchemas([]);
762767
}}
763768
callTool={async (name, params) => {
764769
clearError("tools");
@@ -811,7 +816,7 @@ const App = () => {
811816
</Tabs>
812817
) : (
813818
<div className="flex flex-col items-center justify-center h-full gap-4">
814-
<p className="text-lg text-gray-500">
819+
<p className="text-lg text-gray-500 dark:text-gray-400">
815820
Connect to an MCP server to start inspecting
816821
</p>
817822
<div className="flex items-center gap-2">
@@ -836,7 +841,7 @@ const App = () => {
836841
}}
837842
>
838843
<div
839-
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50"
844+
className="absolute w-full h-4 -top-2 cursor-row-resize flex items-center justify-center hover:bg-accent/50 dark:hover:bg-input/40"
840845
onMouseDown={handleDragStart}
841846
>
842847
<div className="w-8 h-1 rounded-full bg-border" />

client/src/components/AuthDebugger.tsx

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { useCallback, useMemo } from "react";
22
import { Button } from "@/components/ui/button";
33
import { DebugInspectorOAuthClientProvider } from "../lib/auth";
4-
import {
5-
auth,
6-
discoverOAuthMetadata,
7-
} from "@modelcontextprotocol/sdk/client/auth.js";
8-
import { OAuthMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
94
import { AlertCircle } from "lucide-react";
105
import { AuthDebuggerState } from "../lib/auth-types";
116
import { OAuthFlowProgress } from "./OAuthFlowProgress";
@@ -124,22 +119,43 @@ const AuthDebugger = ({
124119

125120
updateAuthState({ isInitiatingAuth: true, statusMessage: null });
126121
try {
127-
const serverAuthProvider = new DebugInspectorOAuthClientProvider(
128-
serverUrl,
129-
);
130-
// First discover OAuth metadata separately so we can save it
131-
const metadata = await discoverOAuthMetadata(serverUrl);
132-
if (!metadata) {
133-
throw new Error("Failed to discover OAuth metadata");
122+
// Step through the OAuth flow using the state machine instead of the auth() function
123+
let currentState: AuthDebuggerState = {
124+
...authState,
125+
oauthStep: "metadata_discovery",
126+
authorizationUrl: null,
127+
latestError: null,
128+
};
129+
130+
const oauthMachine = new OAuthStateMachine(serverUrl, (updates) => {
131+
// Update our temporary state during the process
132+
currentState = { ...currentState, ...updates };
133+
// But don't call updateAuthState yet
134+
});
135+
136+
// Manually step through each stage of the OAuth flow
137+
while (currentState.oauthStep !== "complete") {
138+
await oauthMachine.executeStep(currentState);
139+
// In quick mode, we'll just redirect to the authorization URL
140+
if (
141+
currentState.oauthStep === "authorization_code" &&
142+
currentState.authorizationUrl
143+
) {
144+
// Open the authorization URL automatically
145+
window.location.href = currentState.authorizationUrl;
146+
break;
147+
}
134148
}
135-
const parsedMetadata = await OAuthMetadataSchema.parseAsync(metadata);
136-
serverAuthProvider.saveServerMetadata(parsedMetadata);
137149

138-
await auth(serverAuthProvider, { serverUrl: serverUrl });
150+
// After the flow completes or reaches a user-input step, update the app state
139151
updateAuthState({
152+
...currentState,
140153
statusMessage: {
141154
type: "info",
142-
message: "Starting OAuth authentication process...",
155+
message:
156+
currentState.oauthStep === "complete"
157+
? "Authentication completed successfully"
158+
: "Please complete authentication in the opened window and enter the code",
143159
},
144160
});
145161
} catch (error) {
@@ -153,7 +169,7 @@ const AuthDebugger = ({
153169
} finally {
154170
updateAuthState({ isInitiatingAuth: false });
155171
}
156-
}, [serverUrl, updateAuthState]);
172+
}, [serverUrl, updateAuthState, authState]);
157173

158174
const handleClearOAuth = useCallback(() => {
159175
if (serverUrl) {

client/src/components/History.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ const HistoryAndNotifications = ({
2929
<div className="flex-1 overflow-y-auto p-4 border-r">
3030
<h2 className="text-lg font-semibold mb-4">History</h2>
3131
{requestHistory.length === 0 ? (
32-
<p className="text-sm text-gray-500 italic">No history yet</p>
32+
<p className="text-sm text-gray-500 dark:text-gray-400 italic">
33+
No history yet
34+
</p>
3335
) : (
3436
<ul className="space-y-3">
3537
{requestHistory
@@ -38,7 +40,7 @@ const HistoryAndNotifications = ({
3840
.map((request, index) => (
3941
<li
4042
key={index}
41-
className="text-sm text-foreground bg-secondary p-2 rounded"
43+
className="text-sm text-foreground bg-secondary py-2 px-3 rounded"
4244
>
4345
<div
4446
className="flex justify-between items-center cursor-pointer"
@@ -93,7 +95,9 @@ const HistoryAndNotifications = ({
9395
<div className="flex-1 overflow-y-auto p-4">
9496
<h2 className="text-lg font-semibold mb-4">Server Notifications</h2>
9597
{serverNotifications.length === 0 ? (
96-
<p className="text-sm text-gray-500 italic">No notifications yet</p>
98+
<p className="text-sm text-gray-500 dark:text-gray-400 italic">
99+
No notifications yet
100+
</p>
97101
) : (
98102
<ul className="space-y-3">
99103
{serverNotifications
@@ -102,7 +106,7 @@ const HistoryAndNotifications = ({
102106
.map((notification, index) => (
103107
<li
104108
key={index}
105-
className="text-sm text-foreground bg-secondary p-2 rounded"
109+
className="text-sm text-foreground bg-secondary py-2 px-3 rounded"
106110
>
107111
<div
108112
className="flex justify-between items-center cursor-pointer"

client/src/components/ListPane.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ const ListPane = <T extends object>({
2121
buttonText,
2222
isButtonDisabled,
2323
}: ListPaneProps<T>) => (
24-
<div className="bg-card rounded-lg shadow">
25-
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
24+
<div className="bg-card border border-border rounded-lg shadow">
25+
<div className="p-4 border-b border-gray-200 dark:border-border">
2626
<h3 className="font-semibold dark:text-white">{title}</h3>
2727
</div>
2828
<div className="p-4">
@@ -46,7 +46,7 @@ const ListPane = <T extends object>({
4646
{items.map((item, index) => (
4747
<div
4848
key={index}
49-
className="flex items-center p-2 rounded hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer"
49+
className="flex items-center py-2 px-4 rounded hover:bg-gray-50 dark:hover:bg-secondary cursor-pointer"
5050
onClick={() => setSelectedItem(item)}
5151
>
5252
{renderItem(item)}

client/src/components/OAuthFlowProgress.tsx

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { AuthDebuggerState, OAuthStep } from "@/lib/auth-types";
22
import { CheckCircle2, Circle, ExternalLink } from "lucide-react";
33
import { Button } from "./ui/button";
44
import { DebugInspectorOAuthClientProvider } from "@/lib/auth";
5+
import { useEffect, useMemo, useState } from "react";
6+
import { OAuthClientInformation } from "@modelcontextprotocol/sdk/shared/auth.js";
57

68
interface OAuthStepProps {
79
label: string;
@@ -54,24 +56,57 @@ interface OAuthFlowProgressProps {
5456
proceedToNextStep: () => Promise<void>;
5557
}
5658

59+
const steps: Array<OAuthStep> = [
60+
"metadata_discovery",
61+
"client_registration",
62+
"authorization_redirect",
63+
"authorization_code",
64+
"token_request",
65+
"complete",
66+
];
67+
5768
export const OAuthFlowProgress = ({
5869
serverUrl,
5970
authState,
6071
updateAuthState,
6172
proceedToNextStep,
6273
}: OAuthFlowProgressProps) => {
63-
const provider = new DebugInspectorOAuthClientProvider(serverUrl);
74+
const provider = useMemo(
75+
() => new DebugInspectorOAuthClientProvider(serverUrl),
76+
[serverUrl],
77+
);
78+
const [clientInfo, setClientInfo] = useState<OAuthClientInformation | null>(
79+
null,
80+
);
6481

65-
const steps: Array<OAuthStep> = [
66-
"metadata_discovery",
67-
"client_registration",
68-
"authorization_redirect",
69-
"authorization_code",
70-
"token_request",
71-
"complete",
72-
];
7382
const currentStepIdx = steps.findIndex((s) => s === authState.oauthStep);
7483

84+
useEffect(() => {
85+
const fetchClientInfo = async () => {
86+
if (authState.oauthClientInfo) {
87+
setClientInfo(authState.oauthClientInfo);
88+
} else {
89+
try {
90+
const info = await provider.clientInformation();
91+
if (info) {
92+
setClientInfo(info);
93+
}
94+
} catch (error) {
95+
console.error("Failed to fetch client information:", error);
96+
}
97+
}
98+
};
99+
100+
if (currentStepIdx > steps.indexOf("client_registration")) {
101+
fetchClientInfo();
102+
}
103+
}, [
104+
provider,
105+
authState.oauthStep,
106+
authState.oauthClientInfo,
107+
currentStepIdx,
108+
]);
109+
75110
// Helper to get step props
76111
const getStepProps = (stepName: OAuthStep) => ({
77112
isComplete:
@@ -110,13 +145,13 @@ export const OAuthFlowProgress = ({
110145
label="Client Registration"
111146
{...getStepProps("client_registration")}
112147
>
113-
{authState.oauthClientInfo && (
148+
{clientInfo && (
114149
<details className="text-xs mt-2">
115150
<summary className="cursor-pointer text-muted-foreground font-medium">
116151
Registered Client Information
117152
</summary>
118153
<pre className="mt-2 p-2 bg-muted rounded-md overflow-auto max-h-[300px]">
119-
{JSON.stringify(authState.oauthClientInfo, null, 2)}
154+
{JSON.stringify(clientInfo, null, 2)}
120155
</pre>
121156
</details>
122157
)}

client/src/components/PromptsTab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ const PromptsTab = ({
110110
isButtonDisabled={!nextCursor && prompts.length > 0}
111111
/>
112112

113-
<div className="bg-card rounded-lg shadow">
114-
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
113+
<div className="bg-card border border-border rounded-lg shadow">
114+
<div className="p-4 border-b border-gray-200 dark:border-border">
115115
<h3 className="font-semibold">
116116
{selectedPrompt ? selectedPrompt.name : "Select a prompt"}
117117
</h3>
@@ -126,7 +126,7 @@ const PromptsTab = ({
126126
) : selectedPrompt ? (
127127
<div className="space-y-4">
128128
{selectedPrompt.description && (
129-
<p className="text-sm text-gray-600">
129+
<p className="text-sm text-gray-600 dark:text-gray-400">
130130
{selectedPrompt.description}
131131
</p>
132132
)}

client/src/components/ResourcesTab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ const ResourcesTab = ({
173173
isButtonDisabled={!nextTemplateCursor && resourceTemplates.length > 0}
174174
/>
175175

176-
<div className="bg-card rounded-lg shadow">
177-
<div className="p-4 border-b border-gray-200 dark:border-gray-800 flex justify-between items-center">
176+
<div className="bg-card border border-border rounded-lg shadow">
177+
<div className="p-4 border-b border-gray-200 dark:border-border flex justify-between items-center">
178178
<h3
179179
className="font-semibold truncate"
180180
title={selectedResource?.name || selectedTemplate?.name}
@@ -234,7 +234,7 @@ const ResourcesTab = ({
234234
/>
235235
) : selectedTemplate ? (
236236
<div className="space-y-4">
237-
<p className="text-sm text-gray-600">
237+
<p className="text-sm text-gray-600 dark:text-gray-400">
238238
{selectedTemplate.description}
239239
</p>
240240
{selectedTemplate.uriTemplate

client/src/components/Sidebar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const Sidebar = ({
215215

216216
return (
217217
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
218-
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800">
218+
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-border">
219219
<div className="flex items-center">
220220
<h1 className="ml-2 text-lg font-semibold">
221221
MCP Inspector v{version}
@@ -646,7 +646,7 @@ const Sidebar = ({
646646
}
647647
})()}`}
648648
/>
649-
<span className="text-sm text-gray-600">
649+
<span className="text-sm text-gray-600 dark:text-gray-400">
650650
{(() => {
651651
switch (connectionStatus) {
652652
case "connected":

0 commit comments

Comments
 (0)