Skip to content

Commit 38e0776

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents a58a259 + a2d2cf6 commit 38e0776

17 files changed

+966
-237
lines changed

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.13.0",
3+
"version": "0.14.0",
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.11.5",
24+
"@modelcontextprotocol/sdk": "^1.12.1",
2525
"commander": "^13.1.0",
2626
"spawn-rx": "^5.1.2"
2727
}

client/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-client",
3-
"version": "0.13.0",
3+
"version": "0.14.0",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -23,7 +23,7 @@
2323
"test:watch": "jest --config jest.config.cjs --watch"
2424
},
2525
"dependencies": {
26-
"@modelcontextprotocol/sdk": "^1.11.5",
26+
"@modelcontextprotocol/sdk": "^1.12.1",
2727
"@radix-ui/react-checkbox": "^1.1.4",
2828
"ajv": "^6.12.6",
2929
"@radix-ui/react-dialog": "^1.1.3",

client/src/App.tsx

Lines changed: 126 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
} from "@modelcontextprotocol/sdk/types.js";
2020
import { OAuthTokensSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
2121
import { SESSION_KEYS, getServerSpecificKey } from "./lib/constants";
22-
import { AuthDebuggerState } from "./lib/auth-types";
22+
import { AuthDebuggerState, EMPTY_DEBUGGER_STATE } from "./lib/auth-types";
23+
import { OAuthStateMachine } from "./lib/oauth-state-machine";
2324
import { cacheToolOutputSchemas } from "./utils/schemaUtils";
2425
import React, {
2526
Suspense,
@@ -29,7 +30,10 @@ import React, {
2930
useState,
3031
} from "react";
3132
import { useConnection } from "./lib/hooks/useConnection";
32-
import { useDraggablePane } from "./lib/hooks/useDraggablePane";
33+
import {
34+
useDraggablePane,
35+
useDraggableSidebar,
36+
} from "./lib/hooks/useDraggablePane";
3337
import { StdErrNotification } from "./lib/notificationTypes";
3438

3539
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
@@ -121,19 +125,8 @@ const App = () => {
121125
const [isAuthDebuggerVisible, setIsAuthDebuggerVisible] = useState(false);
122126

123127
// Auth debugger state
124-
const [authState, setAuthState] = useState<AuthDebuggerState>({
125-
isInitiatingAuth: false,
126-
oauthTokens: null,
127-
loading: true,
128-
oauthStep: "metadata_discovery",
129-
oauthMetadata: null,
130-
oauthClientInfo: null,
131-
authorizationUrl: null,
132-
authorizationCode: "",
133-
latestError: null,
134-
statusMessage: null,
135-
validationError: null,
136-
});
128+
const [authState, setAuthState] =
129+
useState<AuthDebuggerState>(EMPTY_DEBUGGER_STATE);
137130

138131
// Helper function to update specific auth state properties
139132
const updateAuthState = (updates: Partial<AuthDebuggerState>) => {
@@ -164,6 +157,11 @@ const App = () => {
164157
const progressTokenRef = useRef(0);
165158

166159
const { height: historyPaneHeight, handleDragStart } = useDraggablePane(300);
160+
const {
161+
width: sidebarWidth,
162+
isDragging: isSidebarDragging,
163+
handleDragStart: handleSidebarDragStart,
164+
} = useDraggableSidebar(320);
167165

168166
const {
169167
connectionStatus,
@@ -243,27 +241,81 @@ const App = () => {
243241

244242
// Update OAuth debug state during debug callback
245243
const onOAuthDebugConnect = useCallback(
246-
({
244+
async ({
247245
authorizationCode,
248246
errorMsg,
247+
restoredState,
249248
}: {
250249
authorizationCode?: string;
251250
errorMsg?: string;
251+
restoredState?: AuthDebuggerState;
252252
}) => {
253253
setIsAuthDebuggerVisible(true);
254-
if (authorizationCode) {
254+
255+
if (errorMsg) {
255256
updateAuthState({
256-
authorizationCode,
257-
oauthStep: "token_request",
257+
latestError: new Error(errorMsg),
258258
});
259+
return;
259260
}
260-
if (errorMsg) {
261+
262+
if (restoredState && authorizationCode) {
263+
// Restore the previous auth state and continue the OAuth flow
264+
let currentState: AuthDebuggerState = {
265+
...restoredState,
266+
authorizationCode,
267+
oauthStep: "token_request",
268+
isInitiatingAuth: true,
269+
statusMessage: null,
270+
latestError: null,
271+
};
272+
273+
try {
274+
// Create a new state machine instance to continue the flow
275+
const stateMachine = new OAuthStateMachine(sseUrl, (updates) => {
276+
currentState = { ...currentState, ...updates };
277+
});
278+
279+
// Continue stepping through the OAuth flow from where we left off
280+
while (
281+
currentState.oauthStep !== "complete" &&
282+
currentState.oauthStep !== "authorization_code"
283+
) {
284+
await stateMachine.executeStep(currentState);
285+
}
286+
287+
if (currentState.oauthStep === "complete") {
288+
// After the flow completes or reaches a user-input step, update the app state
289+
updateAuthState({
290+
...currentState,
291+
statusMessage: {
292+
type: "success",
293+
message: "Authentication completed successfully",
294+
},
295+
isInitiatingAuth: false,
296+
});
297+
}
298+
} catch (error) {
299+
console.error("OAuth continuation error:", error);
300+
updateAuthState({
301+
latestError:
302+
error instanceof Error ? error : new Error(String(error)),
303+
statusMessage: {
304+
type: "error",
305+
message: `Failed to complete OAuth flow: ${error instanceof Error ? error.message : String(error)}`,
306+
},
307+
isInitiatingAuth: false,
308+
});
309+
}
310+
} else if (authorizationCode) {
311+
// Fallback to the original behavior if no state was restored
261312
updateAuthState({
262-
latestError: new Error(errorMsg),
313+
authorizationCode,
314+
oauthStep: "token_request",
263315
});
264316
}
265317
},
266-
[],
318+
[sseUrl],
267319
);
268320

269321
// Load OAuth tokens when sseUrl changes
@@ -285,8 +337,6 @@ const App = () => {
285337
}
286338
} catch (error) {
287339
console.error("Error loading OAuth tokens:", error);
288-
} finally {
289-
updateAuthState({ loading: false });
290340
}
291341
};
292342

@@ -565,32 +615,58 @@ const App = () => {
565615

566616
return (
567617
<div className="flex h-screen bg-background">
568-
<Sidebar
569-
connectionStatus={connectionStatus}
570-
transportType={transportType}
571-
setTransportType={setTransportType}
572-
command={command}
573-
setCommand={setCommand}
574-
args={args}
575-
setArgs={setArgs}
576-
sseUrl={sseUrl}
577-
setSseUrl={setSseUrl}
578-
env={env}
579-
setEnv={setEnv}
580-
config={config}
581-
setConfig={setConfig}
582-
bearerToken={bearerToken}
583-
setBearerToken={setBearerToken}
584-
headerName={headerName}
585-
setHeaderName={setHeaderName}
586-
onConnect={connectMcpServer}
587-
onDisconnect={disconnectMcpServer}
588-
stdErrNotifications={stdErrNotifications}
589-
logLevel={logLevel}
590-
sendLogLevelRequest={sendLogLevelRequest}
591-
loggingSupported={!!serverCapabilities?.logging || false}
592-
clearStdErrNotifications={clearStdErrNotifications}
593-
/>
618+
<div
619+
style={{
620+
width: sidebarWidth,
621+
minWidth: 200,
622+
maxWidth: 600,
623+
transition: isSidebarDragging ? "none" : "width 0.15s",
624+
}}
625+
className="bg-card border-r border-border flex flex-col h-full relative"
626+
>
627+
<Sidebar
628+
connectionStatus={connectionStatus}
629+
transportType={transportType}
630+
setTransportType={setTransportType}
631+
command={command}
632+
setCommand={setCommand}
633+
args={args}
634+
setArgs={setArgs}
635+
sseUrl={sseUrl}
636+
setSseUrl={setSseUrl}
637+
env={env}
638+
setEnv={setEnv}
639+
config={config}
640+
setConfig={setConfig}
641+
bearerToken={bearerToken}
642+
setBearerToken={setBearerToken}
643+
headerName={headerName}
644+
setHeaderName={setHeaderName}
645+
onConnect={connectMcpServer}
646+
onDisconnect={disconnectMcpServer}
647+
stdErrNotifications={stdErrNotifications}
648+
logLevel={logLevel}
649+
sendLogLevelRequest={sendLogLevelRequest}
650+
loggingSupported={!!serverCapabilities?.logging || false}
651+
clearStdErrNotifications={clearStdErrNotifications}
652+
/>
653+
{/* Drag handle for resizing sidebar */}
654+
<div
655+
onMouseDown={handleSidebarDragStart}
656+
style={{
657+
cursor: "col-resize",
658+
position: "absolute",
659+
top: 0,
660+
right: 0,
661+
width: 6,
662+
height: "100%",
663+
zIndex: 10,
664+
background: isSidebarDragging ? "rgba(0,0,0,0.08)" : "transparent",
665+
}}
666+
aria-label="Resize sidebar"
667+
data-testid="sidebar-drag-handle"
668+
/>
669+
</div>
594670
<div className="flex-1 flex flex-col overflow-hidden">
595671
<div className="flex-1 overflow-auto">
596672
{mcpClient ? (

0 commit comments

Comments
 (0)