@ai-sdk/mcp
Advanced tools
+6
-0
| # @ai-sdk/mcp | ||
| ## 2.0.32 | ||
| ### Patch Changes | ||
| - 1011e33: Select MCP OAuth authorization scopes from `WWW-Authenticate` challenges or Protected Resource Metadata. | ||
| ## 2.0.31 | ||
@@ -4,0 +10,0 @@ |
+3
-3
| { | ||
| "name": "@ai-sdk/mcp", | ||
| "version": "2.0.31", | ||
| "version": "2.0.32", | ||
| "type": "module", | ||
@@ -35,4 +35,4 @@ "license": "Apache-2.0", | ||
| "pkce-challenge": "^5.0.1", | ||
| "@ai-sdk/provider": "4.0.7", | ||
| "@ai-sdk/provider-utils": "5.0.27" | ||
| "@ai-sdk/provider-utils": "5.0.27", | ||
| "@ai-sdk/provider": "4.0.7" | ||
| }, | ||
@@ -39,0 +39,0 @@ "devDependencies": { |
@@ -16,3 +16,3 @@ import { | ||
| import { | ||
| extractResourceMetadataUrl, | ||
| extractWWWAuthenticateParams, | ||
| UnauthorizedError, | ||
@@ -163,3 +163,6 @@ auth, | ||
| */ | ||
| private authorizeOnce(resourceMetadataUrl?: URL): Promise<AuthResult> { | ||
| private authorizeOnce( | ||
| resourceMetadataUrl?: URL, | ||
| scope?: string, | ||
| ): Promise<AuthResult> { | ||
| if (!this.authProvider) { | ||
@@ -173,2 +176,3 @@ return Promise.resolve('REDIRECT'); | ||
| resourceMetadataUrl, | ||
| scope, | ||
| fetchFn: this.fetchFn, | ||
@@ -262,5 +266,10 @@ }).finally(() => { | ||
| if (response.status === 401 && this.authProvider && !triedAuth) { | ||
| this.resourceMetadataUrl = extractResourceMetadataUrl(response); | ||
| const { resourceMetadataUrl, scope } = | ||
| extractWWWAuthenticateParams(response); | ||
| this.resourceMetadataUrl = resourceMetadataUrl; | ||
| try { | ||
| const result = await this.authorizeOnce(this.resourceMetadataUrl); | ||
| const result = await this.authorizeOnce( | ||
| this.resourceMetadataUrl, | ||
| scope, | ||
| ); | ||
| if (result !== 'AUTHORIZED') { | ||
@@ -480,5 +489,10 @@ const error = new UnauthorizedError(); | ||
| if (response.status === 401 && this.authProvider && !triedAuth) { | ||
| this.resourceMetadataUrl = extractResourceMetadataUrl(response); | ||
| const { resourceMetadataUrl, scope } = | ||
| extractWWWAuthenticateParams(response); | ||
| this.resourceMetadataUrl = resourceMetadataUrl; | ||
| try { | ||
| const result = await this.authorizeOnce(this.resourceMetadataUrl); | ||
| const result = await this.authorizeOnce( | ||
| this.resourceMetadataUrl, | ||
| scope, | ||
| ); | ||
| if (result !== 'AUTHORIZED') { | ||
@@ -485,0 +499,0 @@ const error = new UnauthorizedError(); |
@@ -12,3 +12,3 @@ import { | ||
| import { | ||
| extractResourceMetadataUrl, | ||
| extractWWWAuthenticateParams, | ||
| UnauthorizedError, | ||
@@ -110,3 +110,5 @@ auth, | ||
| if (response.status === 401 && this.authProvider && !triedAuth) { | ||
| this.resourceMetadataUrl = extractResourceMetadataUrl(response); | ||
| const { resourceMetadataUrl, scope } = | ||
| extractWWWAuthenticateParams(response); | ||
| this.resourceMetadataUrl = resourceMetadataUrl; | ||
| try { | ||
@@ -116,2 +118,3 @@ const result = await auth(this.authProvider, { | ||
| resourceMetadataUrl: this.resourceMetadataUrl, | ||
| scope, | ||
| fetchFn: this.fetchFn, | ||
@@ -279,3 +282,5 @@ }); | ||
| if (response.status === 401 && this.authProvider && !triedAuth) { | ||
| this.resourceMetadataUrl = extractResourceMetadataUrl(response); | ||
| const { resourceMetadataUrl, scope } = | ||
| extractWWWAuthenticateParams(response); | ||
| this.resourceMetadataUrl = resourceMetadataUrl; | ||
| try { | ||
@@ -285,2 +290,3 @@ const result = await auth(this.authProvider, { | ||
| resourceMetadataUrl: this.resourceMetadataUrl, | ||
| scope, | ||
| fetchFn: this.fetchFn, | ||
@@ -287,0 +293,0 @@ }); |
+51
-19
@@ -273,9 +273,6 @@ import pkceChallenge from 'pkce-challenge'; | ||
| /** | ||
| * Extracts the OAuth 2.0 Protected Resource Metadata URL from a WWW-Authenticate header (RFC9728). | ||
| * Looks for a resource="..." parameter. | ||
| */ | ||
| export function extractResourceMetadataUrl( | ||
| response: Response, | ||
| ): URL | undefined { | ||
| export function extractWWWAuthenticateParams(response: Response): { | ||
| resourceMetadataUrl?: URL; | ||
| scope?: string; | ||
| } { | ||
| const header = | ||
@@ -285,3 +282,3 @@ response.headers.get('www-authenticate') ?? | ||
| if (!header) { | ||
| return undefined; | ||
| return {}; | ||
| } | ||
@@ -291,17 +288,48 @@ | ||
| if (type.toLowerCase() !== 'bearer' || !scheme) { | ||
| return undefined; | ||
| return {}; | ||
| } | ||
| // regex taken from MCP spec | ||
| const regex = /resource_metadata="([^"]*)"/; | ||
| const match = header.match(regex); | ||
| if (!match) { | ||
| return undefined; | ||
| } | ||
| const resourceMetadataMatch = header.match( | ||
| /(?:^|[,\s])resource_metadata="([^"]*)"/i, | ||
| ); | ||
| const scope = header.match(/(?:^|[,\s])scope="([^"]*)"/i)?.[1]; | ||
| let resourceMetadataUrl: URL | undefined; | ||
| try { | ||
| return new URL(match[1]); | ||
| } catch { | ||
| return undefined; | ||
| resourceMetadataUrl = resourceMetadataMatch | ||
| ? new URL(resourceMetadataMatch[1]) | ||
| : undefined; | ||
| } catch {} | ||
| return { resourceMetadataUrl, scope }; | ||
| } | ||
| /** | ||
| * Extracts the OAuth 2.0 Protected Resource Metadata URL from a WWW-Authenticate header (RFC9728). | ||
| */ | ||
| export function extractResourceMetadataUrl( | ||
| response: Response, | ||
| ): URL | undefined { | ||
| return extractWWWAuthenticateParams(response).resourceMetadataUrl; | ||
| } | ||
| function selectScope({ | ||
| scope, | ||
| resourceMetadata, | ||
| clientMetadata, | ||
| }: { | ||
| scope?: string; | ||
| resourceMetadata?: OAuthProtectedResourceMetadata; | ||
| clientMetadata: OAuthClientMetadata; | ||
| }): string | undefined { | ||
| if (scope) { | ||
| return scope; | ||
| } | ||
| const resourceScopes = resourceMetadata?.scopes_supported?.join(' '); | ||
| if (resourceScopes) { | ||
| return resourceScopes; | ||
| } | ||
| return clientMetadata.scope; | ||
| } | ||
@@ -1314,3 +1342,7 @@ | ||
| redirectUrl: provider.redirectUrl, | ||
| scope: scope || provider.clientMetadata.scope, | ||
| scope: selectScope({ | ||
| scope, | ||
| resourceMetadata, | ||
| clientMetadata: provider.clientMetadata, | ||
| }), | ||
| resource, | ||
@@ -1317,0 +1349,0 @@ }, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
588929
0.75%9474
0.84%