StoredCredentials was marked #[non_exhaustive] in #715 / #768, but unlike OAuthClientConfig (which got a new() in the same PR), StoredCredentials doesn't have a constructor or Default impl. External crates that implement CredentialStore and need to construct StoredCredentials in their save() path don't have a compile-safe way to do so.
The workaround we landed on is a serde JSON roundtrip:
let credentials:StoredCredentials = serde_json::from_value(serde_json::json!({"client_id": client_id,"token_response": token_response,"granted_scopes": granted_scopes,"token_received_at": timestamp,}))?;This bypasses #[non_exhaustive] via Deserialize but turns what should be a compile-time error (if a new required field is added) into a silent runtime failure during OAuth.
We ran into this in block/goose after bumping to rmcp 1.3.0 for Unix socket transport support (#749).
Suggested fix: A constructor matching the pattern used for OAuthClientConfig:
implStoredCredentials{pubfnnew(client_id:String,token_response:Option<OAuthTokenResponse>,granted_scopes:Vec<String>,token_received_at:Option<u64>,) -> Self{Self{
client_id,
token_response,
granted_scopes,
token_received_at,}}}
StoredCredentialswas marked#[non_exhaustive]in #715 / #768, but unlikeOAuthClientConfig(which got anew()in the same PR),StoredCredentialsdoesn't have a constructor orDefaultimpl. External crates that implementCredentialStoreand need to constructStoredCredentialsin theirsave()path don't have a compile-safe way to do so.The workaround we landed on is a serde JSON roundtrip:
This bypasses
#[non_exhaustive]viaDeserializebut turns what should be a compile-time error (if a new required field is added) into a silent runtime failure during OAuth.We ran into this in block/goose after bumping to rmcp 1.3.0 for Unix socket transport support (#749).
Suggested fix: A constructor matching the pattern used for
OAuthClientConfig: