Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/core/test/mcp-oauth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,40 @@ describe("MCP OAuth", () => {
expect(tokenRequests[0]?.get("resource")).toBe(url)
})

test("preserves a pathless resource from metadata", async () => {
const tokenRequests: URLSearchParams[] = []
const server = Bun.serve({
port: 0,
async fetch(request) {
const url = new URL(request.url)
if (url.pathname === "/.well-known/oauth-authorization-server")
return Response.json({
issuer: url.origin,
authorization_endpoint: `${url.origin}/authorize`,
token_endpoint: `${url.origin}/token`,
response_types_supported: ["code"],
})
if (url.pathname === "/.well-known/oauth-protected-resource/mcp")
return Response.json({ resource: url.origin, authorization_servers: [url.origin] })
if (request.method === "POST" && url.pathname === "/token") {
tokenRequests.push(new URLSearchParams(await request.text()))
return Response.json({ access_token: "next", token_type: "Bearer" })
}
return new Response(null, { status: 404 })
},
})
const url = `${server.url.origin}/mcp`
const oauthProvider = await connectProvider(
remote(url),
memoryCredentials([credential({ access: "expired", refresh: "refresh", url })]),
)

await auth(oauthProvider, { serverUrl: url }).finally(() => server.stop(true))

expect(tokenRequests[0]?.get("grant_type")).toBe("refresh_token")
expect(tokenRequests[0]?.get("resource")).toBe(server.url.origin)
})

test("finds resource metadata through the 401 header when the well-known path is not served", async () => {
const server = Bun.serve({
port: 0,
Expand Down
22 changes: 20 additions & 2 deletions patches/@modelcontextprotocol%2Fclient@2.3.1.patch
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
diff --git a/dist/index.cjs b/dist/index.cjs
index 71cf63076b073284aa14f63cd41efa653e8def0f..d4679fc706c76b87949fd674857cea54793e82ce 100644
index 71cf63076b073284aa14f63cd41efa653e8def0f..789b1636fc6f0adf8137addb648b2af0ac8d9e25 100644
--- a/dist/index.cjs
+++ b/dist/index.cjs
@@ -725,7 +725,7 @@
}
if (freshDiscoveryState) await provider.saveDiscoveryState?.(freshDiscoveryState);
const selectedResource = await selectResourceURL(serverUrl, provider, resourceMetadata);
- const resource = selectedResource && resourceMetadata && !provider.validateResourceURL ? resourceMetadata.resource : selectedResource;
+ const resource = selectedResource && resourceMetadata && selectedResource.href === new URL(resourceMetadata.resource).href ? resourceMetadata.resource : selectedResource;
if (resource) await provider.saveResourceUrl?.(resourceIndicatorToString(resource));
const resolvedScope = determineScope({
requestedScope: scope,
@@ -1038,7 +1038,6 @@ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, o
else {
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
Expand All @@ -28,9 +37,18 @@ index 71cf63076b073284aa14f63cd41efa653e8def0f..d4679fc706c76b87949fd674857cea54
console.warn(`[mcp-sdk] excluding tool '${tool.name}' from tools/list: invalid x-mcp-header declaration — ${scan.reason}`);
return false;
diff --git a/dist/index.mjs b/dist/index.mjs
index c1a09a82b8121d6a1b038ccc6d02bae46d55dbcf..bf457bdfdef05ad8d09f3fbb94c6ac1aecc59487 100644
index c1a09a82b8121d6a1b038ccc6d02bae46d55dbcf..3356a2e3df5122dc993b3a0cc39a73a8581b0cbe 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -722,7 +722,7 @@
}
if (freshDiscoveryState) await provider.saveDiscoveryState?.(freshDiscoveryState);
const selectedResource = await selectResourceURL(serverUrl, provider, resourceMetadata);
- const resource = selectedResource && resourceMetadata && !provider.validateResourceURL ? resourceMetadata.resource : selectedResource;
+ const resource = selectedResource && resourceMetadata && selectedResource.href === new URL(resourceMetadata.resource).href ? resourceMetadata.resource : selectedResource;
if (resource) await provider.saveResourceUrl?.(resourceIndicatorToString(resource));
const resolvedScope = determineScope({
requestedScope: scope,
@@ -1035,7 +1035,6 @@ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, o
else {
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
Expand Down
Loading