Skip to content

Commit ee8c29b

Browse files
authored
Merge branch 'main' into fix/header
2 parents 10e3202 + e364273 commit ee8c29b

18 files changed

+986
-166
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.12.0",
3+
"version": "0.13.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.0",
24+
"@modelcontextprotocol/sdk": "^1.11.5",
2525
"commander": "^13.1.0",
2626
"spawn-rx": "^5.1.2"
2727
}

client/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@modelcontextprotocol/inspector-client",
3-
"version": "0.12.0",
3+
"version": "0.13.0",
44
"description": "Client-side application for the Model Context Protocol inspector",
55
"license": "MIT",
66
"author": "Anthropic, PBC (https://anthropic.com)",
@@ -23,8 +23,9 @@
2323
"test:watch": "jest --config jest.config.cjs --watch"
2424
},
2525
"dependencies": {
26-
"@modelcontextprotocol/sdk": "^1.11.0",
26+
"@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: 5 additions & 1 deletion
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,
@@ -234,7 +235,6 @@ const App = () => {
234235
const onOAuthConnect = useCallback(
235236
(serverUrl: string) => {
236237
setSseUrl(serverUrl);
237-
setTransportType("sse");
238238
setIsAuthDebuggerVisible(false);
239239
void connectMcpServer();
240240
},
@@ -474,6 +474,8 @@ const App = () => {
474474
);
475475
setTools(response.tools);
476476
setNextToolCursor(response.nextCursor);
477+
// Cache output schemas for validation
478+
cacheToolOutputSchemas(response.tools);
477479
};
478480

479481
const callTool = async (name: string, params: Record<string, unknown>) => {
@@ -760,6 +762,8 @@ const App = () => {
760762
clearTools={() => {
761763
setTools([]);
762764
setNextToolCursor(undefined);
765+
// Clear cached output schemas
766+
cacheToolOutputSchemas([]);
763767
}}
764768
callTool={async (name, params) => {
765769
clearError("tools");

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/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/Sidebar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,14 @@ const Sidebar = ({
127127
return {
128128
type: "sse",
129129
url: sseUrl,
130-
note: "For SSE connections, add this URL directly in Client",
130+
note: "For SSE connections, add this URL directly in your MCP Client",
131131
};
132132
}
133133
if (transportType === "streamable-http") {
134134
return {
135135
type: "streamable-http",
136136
url: sseUrl,
137-
note: "For Streamable HTTP connections, add this URL directly in Client",
137+
note: "For Streamable HTTP connections, add this URL directly in your MCP Client",
138138
};
139139
}
140140
return {};
@@ -172,7 +172,7 @@ const Sidebar = ({
172172
description:
173173
transportType === "stdio"
174174
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
175-
: "SSE URL has been copied. Use this URL in Cursor directly.",
175+
: "SSE URL has been copied. Use this URL directly in your MCP Client.",
176176
});
177177

178178
setTimeout(() => {

0 commit comments

Comments
 (0)