Skip to content

Commit 86eaabe

Browse files
authored
Merge branch 'main' into playwright-test
2 parents ebc249b + 5db6426 commit 86eaabe

File tree

10 files changed

+41
-28
lines changed

10 files changed

+41
-28
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ The project is organized as a monorepo with workspaces:
3030

3131
- `client/`: React frontend with Vite, TypeScript and Tailwind
3232
- `server/`: Express backend with TypeScript
33-
- `bin/`: CLI scripts
33+
- `cli/`: Command-line interface for testing and invoking MCP server methods directly

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
},
2222
"devDependencies": {},
2323
"dependencies": {
24-
"@modelcontextprotocol/sdk": "^1.12.1",
24+
"@modelcontextprotocol/sdk": "^1.13.0",
2525
"commander": "^13.1.0",
2626
"spawn-rx": "^5.1.2"
2727
}

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"cleanup:e2e": "node e2e/global-teardown.js"
2626
},
2727
"dependencies": {
28-
"@modelcontextprotocol/sdk": "^1.12.1",
28+
"@modelcontextprotocol/sdk": "^1.13.0",
2929
"@radix-ui/react-checkbox": "^1.1.4",
3030
"ajv": "^6.12.6",
3131
"@radix-ui/react-dialog": "^1.1.3",

client/src/components/OAuthFlowProgress.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ export const OAuthFlowProgress = ({
156156
{authState.resourceMetadataError && (
157157
<div className="mt-2 p-3 border border-blue-300 bg-blue-50 rounded-md">
158158
<p className="text-sm font-medium text-blue-700">
159-
ℹ️ No resource metadata available from{" "}
159+
ℹ️ Problem with resource metadata from{" "}
160160
<a
161161
href={
162162
new URL(

client/src/components/__tests__/AuthDebugger.test.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jest.mock("@modelcontextprotocol/sdk/client/auth.js", () => ({
4141
startAuthorization: jest.fn(),
4242
exchangeAuthorization: jest.fn(),
4343
discoverOAuthProtectedResourceMetadata: jest.fn(),
44+
selectResourceURL: jest.fn(),
4445
}));
4546

4647
// Import the functions to get their types
@@ -88,7 +89,7 @@ describe("AuthDebugger", () => {
8889
const defaultAuthState = EMPTY_DEBUGGER_STATE;
8990

9091
const defaultProps = {
91-
serverUrl: "https://example.com",
92+
serverUrl: "https://example.com/mcp",
9293
onBack: jest.fn(),
9394
authState: defaultAuthState,
9495
updateAuthState: jest.fn(),
@@ -203,7 +204,7 @@ describe("AuthDebugger", () => {
203204

204205
// Should first discover and save OAuth metadata
205206
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
206-
new URL("https://example.com"),
207+
new URL("https://example.com/"),
207208
);
208209

209210
// Check that updateAuthState was called with the right info message
@@ -320,6 +321,7 @@ describe("AuthDebugger", () => {
320321
isInitiatingAuth: false,
321322
resourceMetadata: null,
322323
resourceMetadataError: null,
324+
resource: null,
323325
oauthTokens: null,
324326
oauthStep: "metadata_discovery",
325327
latestError: null,
@@ -361,7 +363,7 @@ describe("AuthDebugger", () => {
361363
});
362364

363365
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
364-
new URL("https://example.com"),
366+
new URL("https://example.com/"),
365367
);
366368
});
367369

@@ -496,11 +498,11 @@ describe("AuthDebugger", () => {
496498
it("should successfully fetch and display protected resource metadata", async () => {
497499
const updateAuthState = jest.fn();
498500
const mockResourceMetadata = {
499-
resource: "https://example.com/api",
501+
resource: "https://example.com/mcp",
500502
authorization_servers: ["https://custom-auth.example.com"],
501503
bearer_methods_supported: ["header", "body"],
502-
resource_documentation: "https://example.com/api/docs",
503-
resource_policy_uri: "https://example.com/api/policy",
504+
resource_documentation: "https://example.com/mcp/docs",
505+
resource_policy_uri: "https://example.com/mcp/policy",
504506
};
505507

506508
// Mock successful metadata discovery
@@ -538,7 +540,7 @@ describe("AuthDebugger", () => {
538540
// Wait for the metadata to be fetched
539541
await waitFor(() => {
540542
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
541-
"https://example.com",
543+
"https://example.com/mcp",
542544
);
543545
});
544546

@@ -584,7 +586,7 @@ describe("AuthDebugger", () => {
584586
// Wait for the metadata fetch to fail
585587
await waitFor(() => {
586588
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
587-
"https://example.com",
589+
"https://example.com/mcp",
588590
);
589591
});
590592

@@ -594,15 +596,15 @@ describe("AuthDebugger", () => {
594596
expect.objectContaining({
595597
resourceMetadataError: mockError,
596598
// Should use the original server URL as fallback
597-
authServerUrl: new URL("https://example.com"),
599+
authServerUrl: new URL("https://example.com/"),
598600
oauthStep: "client_registration",
599601
}),
600602
);
601603
});
602604

603605
// Verify that regular OAuth metadata discovery was still called
604606
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
605-
new URL("https://example.com"),
607+
new URL("https://example.com/"),
606608
);
607609
});
608610
});

client/src/lib/auth-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface AuthDebuggerState {
3030
oauthStep: OAuthStep;
3131
resourceMetadata: OAuthProtectedResourceMetadata | null;
3232
resourceMetadataError: Error | null;
33+
resource: URL | null;
3334
authServerUrl: URL | null;
3435
oauthMetadata: OAuthMetadata | null;
3536
oauthClientInfo: OAuthClientInformationFull | OAuthClientInformation | null;
@@ -47,6 +48,7 @@ export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = {
4748
oauthMetadata: null,
4849
resourceMetadata: null,
4950
resourceMetadataError: null,
51+
resource: null,
5052
authServerUrl: null,
5153
oauthClientInfo: null,
5254
authorizationUrl: null,

client/src/lib/oauth-state-machine.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
startAuthorization,
77
exchangeAuthorization,
88
discoverOAuthProtectedResourceMetadata,
9+
selectResourceURL,
910
} from "@modelcontextprotocol/sdk/client/auth.js";
1011
import {
1112
OAuthMetadataSchema,
@@ -29,17 +30,15 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
2930
metadata_discovery: {
3031
canTransition: async () => true,
3132
execute: async (context) => {
32-
let authServerUrl = new URL(context.serverUrl);
33+
// Default to discovering from the server's URL
34+
let authServerUrl = new URL("/", context.serverUrl);
3335
let resourceMetadata: OAuthProtectedResourceMetadata | null = null;
3436
let resourceMetadataError: Error | null = null;
3537
try {
3638
resourceMetadata = await discoverOAuthProtectedResourceMetadata(
3739
context.serverUrl,
3840
);
39-
if (
40-
resourceMetadata &&
41-
resourceMetadata.authorization_servers?.length
42-
) {
41+
if (resourceMetadata?.authorization_servers?.length) {
4342
authServerUrl = new URL(resourceMetadata.authorization_servers[0]);
4443
}
4544
} catch (e) {
@@ -50,6 +49,13 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
5049
}
5150
}
5251

52+
const resource: URL | undefined = await selectResourceURL(
53+
context.serverUrl,
54+
context.provider,
55+
// we default to null, so swap it for undefined if not set
56+
resourceMetadata ?? undefined,
57+
);
58+
5359
const metadata = await discoverOAuthMetadata(authServerUrl);
5460
if (!metadata) {
5561
throw new Error("Failed to discover OAuth metadata");
@@ -58,6 +64,7 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
5864
context.provider.saveServerMetadata(parsedMetadata);
5965
context.updateState({
6066
resourceMetadata,
67+
resource,
6168
resourceMetadataError,
6269
authServerUrl,
6370
oauthMetadata: parsedMetadata,
@@ -113,6 +120,7 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
113120
clientInformation,
114121
redirectUrl: context.provider.redirectUrl,
115122
scope,
123+
resource: context.state.resource ?? undefined,
116124
},
117125
);
118126

@@ -163,6 +171,7 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
163171
authorizationCode: context.state.authorizationCode,
164172
codeVerifier,
165173
redirectUri: context.provider.redirectUrl,
174+
resource: context.state.resource ?? undefined,
166175
});
167176

168177
context.provider.saveTokens(tokens);

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"@modelcontextprotocol/inspector-cli": "^0.14.3",
4848
"@modelcontextprotocol/inspector-client": "^0.14.3",
4949
"@modelcontextprotocol/inspector-server": "^0.14.3",
50-
"@modelcontextprotocol/sdk": "^1.12.1",
50+
"@modelcontextprotocol/sdk": "^1.13.1",
5151
"concurrently": "^9.0.1",
5252
"open": "^10.1.0",
5353
"shell-quote": "^1.8.2",

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"typescript": "^5.6.2"
2828
},
2929
"dependencies": {
30-
"@modelcontextprotocol/sdk": "^1.12.1",
30+
"@modelcontextprotocol/sdk": "^1.13.0",
3131
"cors": "^2.8.5",
3232
"express": "^5.1.0",
3333
"ws": "^8.18.0",

0 commit comments

Comments
 (0)