vercel/ai · error · MCPClientOAuthError
OAuth authorization server metadata must be saveable before
Error message
OAuth authorization server metadata must be saveable before starting authorization
What it means
Before redirecting the user to the authorization server, the client saves the current authorization server metadata (issuer pin) via saveAuthorizationServerInformation. If the provider's storage callback reports the metadata was not actually saved, the callback phase later cannot verify the issuer, so authorization is refused before it starts.
Source
Thrown at packages/mcp/src/tool/oauth.ts:1480
authorizationServerUrl,
{
metadata,
clientInformation,
state,
redirectUrl: provider.redirectUrl,
scope: selectedScope,
resource,
},
);
const savedAuthorizationServerInformation =
await saveAuthorizationServerInformation({
provider,
clientInformation,
authorizationServerInformation: currentAuthorizationServerInformation,
});
if (!savedAuthorizationServerInformation) {
throw new MCPClientOAuthError({
message:
'OAuth authorization server metadata must be saveable before starting authorization',
});
}
await provider.saveCodeVerifier(codeVerifier);
await provider.redirectToAuthorization(authorizationUrl);
return 'REDIRECT';
}
View on GitHub (pinned to 69428b1f8b)
Solutions
- Make the provider's authorization-server metadata storage actually persist (file, database, signed cookie) and return the saved value.
- Verify the storage backend serializes the full object (don't strip nested authorizationServerInformation fields).
- In serverless environments, keep the flow within one request/lambda invocation or use external durable storage for OAuth state.
Example fix
// before
saveAuthorizationServerInformation: async () => { /* no-op */ }
// after
saveAuthorizationServerInformation: async (info) => {
await kv.set('as-metadata', info);
return info;
} Defensive patterns
Strategy: validation
Validate before calling
await provider.saveAuthorizationServerInformation?.(asInfo);
const readBack = await provider.getAuthorizationServerInformation?.();
if (readBack == null) {
throw new Error('OAuth storage backend is not persisting authorization server metadata');
} Prevention
- Verify your storage setter round-trips (write then read back) at startup
- Use durable storage (file, DB, signed cookie), not in-memory state, in serverless environments
- Serialize the full metadata object without field whitelisting
- Make storage callbacks throw on write failures instead of silently no-oping
When it happens
Trigger: Starting a new authorization (no authorizationCode): saveAuthorizationServerInformation({...}) was invoked, but the subsequent read (savedAuthorizationServerInformation) shows nothing was persisted — i.e. the provider's save/storage functions silently drop or fail to persist the authorization server metadata.
Common situations: Custom OAuth providers whose storage setter is a no-op or writes to a read-only location; storage implementations that serialize only whitelisted fields; ephemeral environments (serverless) where in-memory storage vanishes between the start and callback of the flow.
Related errors
- OAuth client information must be saveable for dynamic regist
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server ${JSON.stringify(name)} must be configured wi
- ACP-transport MCP servers require client-side mcp/connect ha
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/6d95b082e8283b71.
Report an issue: GitHub.