@ai-sdk/mcp
Advanced tools
+8
-0
| # @ai-sdk/mcp | ||
| ## 1.0.71 | ||
| ### Patch Changes | ||
| - b0e77c0: Select MCP OAuth authorization scopes from `WWW-Authenticate` challenges or Protected Resource Metadata. | ||
| - Updated dependencies [31205a4] | ||
| - @ai-sdk/provider-utils@4.0.46 | ||
| ## 1.0.70 | ||
@@ -4,0 +12,0 @@ |
+2
-2
| { | ||
| "name": "@ai-sdk/mcp", | ||
| "version": "1.0.70", | ||
| "version": "1.0.71", | ||
| "license": "Apache-2.0", | ||
@@ -37,3 +37,3 @@ "sideEffects": false, | ||
| "@ai-sdk/provider": "3.0.15", | ||
| "@ai-sdk/provider-utils": "4.0.45" | ||
| "@ai-sdk/provider-utils": "4.0.46" | ||
| }, | ||
@@ -40,0 +40,0 @@ "devDependencies": { |
@@ -16,3 +16,3 @@ import { | ||
| import { | ||
| extractResourceMetadataUrl, | ||
| extractWWWAuthenticateParams, | ||
| UnauthorizedError, | ||
@@ -117,3 +117,6 @@ auth, | ||
| */ | ||
| private authorizeOnce(resourceMetadataUrl?: URL): Promise<AuthResult> { | ||
| private authorizeOnce( | ||
| resourceMetadataUrl?: URL, | ||
| scope?: string, | ||
| ): Promise<AuthResult> { | ||
| if (!this.authProvider) { | ||
@@ -127,2 +130,3 @@ return Promise.resolve('REDIRECT'); | ||
| resourceMetadataUrl, | ||
| scope, | ||
| fetchFn: this.fetchFn, | ||
@@ -207,5 +211,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') { | ||
@@ -419,5 +428,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') { | ||
@@ -424,0 +438,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 @@ }); |
+52
-20
@@ -274,9 +274,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 = | ||
@@ -286,22 +283,53 @@ response.headers.get('www-authenticate') ?? | ||
| if (!header) { | ||
| return undefined; | ||
| return {}; | ||
| } | ||
| const [type, scheme] = header.split(' '); | ||
| if (type.toLowerCase() !== 'bearer' || !scheme) { | ||
| return undefined; | ||
| if (type.replace(/,$/, '').toLowerCase() !== 'bearer' || !scheme) { | ||
| 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
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.
891925
0.85%11892
0.94%+ Added
+ Added
- Removed
- Removed
- Removed