diff --git a/.fern/metadata.json b/.fern/metadata.json
index b45297c75..78055311d 100644
--- a/.fern/metadata.json
+++ b/.fern/metadata.json
@@ -15,7 +15,7 @@
"standardwebhooks": ">=1.0.1,<2"
}
},
- "originGitCommit": "71b6752138f9f4abe9e8f58724f614eb717ea242",
+ "originGitCommit": "b84de18966f48aec68d6e24ca19cf22a5afe0a9f",
"originGitCommitIsDirty": false,
"invokedBy": "ci",
"requestedVersion": "2.2.0",
diff --git a/.fern/replay.lock b/.fern/replay.lock
index 6ea83476b..b130a4ab5 100644
--- a/.fern/replay.lock
+++ b/.fern/replay.lock
@@ -1758,5 +1758,11 @@ generations:
cli_version: unknown
generator_versions:
fernapi/fern-python-sdk: 5.28.0
-current_generation: 3ad3a4a750c24660afd6338e165498f1bce2766a
+ - commit_sha: f663cbd9b6a5771dbd01481d560ed4bb33355658
+ tree_hash: 4befc754f1915c2567d002523586e7b064c2089b
+ timestamp: 2026-10-05T05:43:20.575Z
+ cli_version: unknown
+ generator_versions:
+ fernapi/fern-python-sdk: 5.28.0
+current_generation: f663cbd9b6a5771dbd01481d560ed4bb33355658
patches: []
diff --git a/reference.md b/reference.md
index f8f85f88f..1fd8ea87d 100644
--- a/reference.md
+++ b/reference.md
@@ -49162,6 +49162,14 @@ client.users.oauth_grants.create(
-
+**mcp_client:** `typing.Optional[CreateOauthGrantsRequestMcpClient]` — The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+
+
+
+
+
+-
+
**nonce:** `typing.Optional[str]` — OIDC nonce, echoed into the resulting ID token. Required when `requested_scopes` includes `openid`.
diff --git a/src/whop_sdk/users/__init__.py b/src/whop_sdk/users/__init__.py
index 8ea466546..9d1cd1df2 100644
--- a/src/whop_sdk/users/__init__.py
+++ b/src/whop_sdk/users/__init__.py
@@ -22,6 +22,7 @@
from . import oauth_grants, passkeys, preferences
from .oauth_grants import (
CreateOauthGrantsRequestCodeChallengeMethod,
+ CreateOauthGrantsRequestMcpClient,
CreateOauthGrantsRequestResponseType,
ListOauthGrantsRequestDirection,
ListOauthGrantsRequestOrder,
@@ -43,6 +44,7 @@
"CheckAccessUsersResponse": ".types",
"CheckAccessUsersResponseAccessLevel": ".types",
"CreateOauthGrantsRequestCodeChallengeMethod": ".oauth_grants",
+ "CreateOauthGrantsRequestMcpClient": ".oauth_grants",
"CreateOauthGrantsRequestResponseType": ".oauth_grants",
"DeletePasskeysResponse": ".passkeys",
"ListOauthGrantsRequestDirection": ".oauth_grants",
@@ -95,6 +97,7 @@ def __dir__():
"CheckAccessUsersResponse",
"CheckAccessUsersResponseAccessLevel",
"CreateOauthGrantsRequestCodeChallengeMethod",
+ "CreateOauthGrantsRequestMcpClient",
"CreateOauthGrantsRequestResponseType",
"DeletePasskeysResponse",
"ListOauthGrantsRequestDirection",
diff --git a/src/whop_sdk/users/oauth_grants/__init__.py b/src/whop_sdk/users/oauth_grants/__init__.py
index b0cb2a0d2..86d2fd40f 100644
--- a/src/whop_sdk/users/oauth_grants/__init__.py
+++ b/src/whop_sdk/users/oauth_grants/__init__.py
@@ -8,6 +8,7 @@
if typing.TYPE_CHECKING:
from .types import (
CreateOauthGrantsRequestCodeChallengeMethod,
+ CreateOauthGrantsRequestMcpClient,
CreateOauthGrantsRequestResponseType,
ListOauthGrantsRequestDirection,
ListOauthGrantsRequestOrder,
@@ -16,6 +17,7 @@
)
_dynamic_imports: typing.Dict[str, str] = {
"CreateOauthGrantsRequestCodeChallengeMethod": ".types",
+ "CreateOauthGrantsRequestMcpClient": ".types",
"CreateOauthGrantsRequestResponseType": ".types",
"ListOauthGrantsRequestDirection": ".types",
"ListOauthGrantsRequestOrder": ".types",
@@ -47,6 +49,7 @@ def __dir__():
__all__ = [
"CreateOauthGrantsRequestCodeChallengeMethod",
+ "CreateOauthGrantsRequestMcpClient",
"CreateOauthGrantsRequestResponseType",
"ListOauthGrantsRequestDirection",
"ListOauthGrantsRequestOrder",
diff --git a/src/whop_sdk/users/oauth_grants/client.py b/src/whop_sdk/users/oauth_grants/client.py
index 769345926..ca580bcf6 100644
--- a/src/whop_sdk/users/oauth_grants/client.py
+++ b/src/whop_sdk/users/oauth_grants/client.py
@@ -8,6 +8,7 @@
from ...types.oauth_grant import OauthGrant
from .raw_client import AsyncRawOauthGrantsClient, RawOauthGrantsClient
from .types.create_oauth_grants_request_code_challenge_method import CreateOauthGrantsRequestCodeChallengeMethod
+from .types.create_oauth_grants_request_mcp_client import CreateOauthGrantsRequestMcpClient
from .types.create_oauth_grants_request_response_type import CreateOauthGrantsRequestResponseType
from .types.list_oauth_grants_request_direction import ListOauthGrantsRequestDirection
from .types.list_oauth_grants_request_order import ListOauthGrantsRequestOrder
@@ -115,6 +116,7 @@ def create(
code_challenge: typing.Optional[str] = OMIT,
code_challenge_method: typing.Optional[CreateOauthGrantsRequestCodeChallengeMethod] = OMIT,
consent_shown: typing.Optional[bool] = OMIT,
+ mcp_client: typing.Optional[CreateOauthGrantsRequestMcpClient] = OMIT,
nonce: typing.Optional[str] = OMIT,
response_type: typing.Optional[CreateOauthGrantsRequestResponseType] = OMIT,
state: typing.Optional[str] = OMIT,
@@ -146,6 +148,9 @@ def create(
consent_shown : typing.Optional[bool]
Whether the consent UI listed these scopes for the user. Sending `false` succeeds only when the user has already granted every scope requested, or when the app is one of Whop's own with the consent skip switched on and asks for `openid` alone.
+ mcp_client : typing.Optional[CreateOauthGrantsRequestMcpClient]
+ The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+
nonce : typing.Optional[str]
OIDC nonce, echoed into the resulting ID token. Required when `requested_scopes` includes `openid`.
@@ -186,6 +191,7 @@ def create(
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
consent_shown=consent_shown,
+ mcp_client=mcp_client,
nonce=nonce,
response_type=response_type,
state=state,
@@ -301,6 +307,7 @@ async def create(
code_challenge: typing.Optional[str] = OMIT,
code_challenge_method: typing.Optional[CreateOauthGrantsRequestCodeChallengeMethod] = OMIT,
consent_shown: typing.Optional[bool] = OMIT,
+ mcp_client: typing.Optional[CreateOauthGrantsRequestMcpClient] = OMIT,
nonce: typing.Optional[str] = OMIT,
response_type: typing.Optional[CreateOauthGrantsRequestResponseType] = OMIT,
state: typing.Optional[str] = OMIT,
@@ -332,6 +339,9 @@ async def create(
consent_shown : typing.Optional[bool]
Whether the consent UI listed these scopes for the user. Sending `false` succeeds only when the user has already granted every scope requested, or when the app is one of Whop's own with the consent skip switched on and asks for `openid` alone.
+ mcp_client : typing.Optional[CreateOauthGrantsRequestMcpClient]
+ The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+
nonce : typing.Optional[str]
OIDC nonce, echoed into the resulting ID token. Required when `requested_scopes` includes `openid`.
@@ -380,6 +390,7 @@ async def main() -> None:
code_challenge=code_challenge,
code_challenge_method=code_challenge_method,
consent_shown=consent_shown,
+ mcp_client=mcp_client,
nonce=nonce,
response_type=response_type,
state=state,
diff --git a/src/whop_sdk/users/oauth_grants/raw_client.py b/src/whop_sdk/users/oauth_grants/raw_client.py
index 28b046246..e3ca14cf4 100644
--- a/src/whop_sdk/users/oauth_grants/raw_client.py
+++ b/src/whop_sdk/users/oauth_grants/raw_client.py
@@ -10,6 +10,7 @@
from ...core.parse_error import ParsingError
from ...core.pydantic_utilities import parse_obj_as
from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
from ...errors.bad_request_error import BadRequestError
from ...errors.conflict_error import ConflictError
from ...errors.forbidden_error import ForbiddenError
@@ -18,6 +19,7 @@
from ...types.oauth_grant import OauthGrant
from ...types.v1error_response import V1ErrorResponse
from .types.create_oauth_grants_request_code_challenge_method import CreateOauthGrantsRequestCodeChallengeMethod
+from .types.create_oauth_grants_request_mcp_client import CreateOauthGrantsRequestMcpClient
from .types.create_oauth_grants_request_response_type import CreateOauthGrantsRequestResponseType
from .types.list_oauth_grants_request_direction import ListOauthGrantsRequestDirection
from .types.list_oauth_grants_request_order import ListOauthGrantsRequestOrder
@@ -171,6 +173,7 @@ def create(
code_challenge: typing.Optional[str] = OMIT,
code_challenge_method: typing.Optional[CreateOauthGrantsRequestCodeChallengeMethod] = OMIT,
consent_shown: typing.Optional[bool] = OMIT,
+ mcp_client: typing.Optional[CreateOauthGrantsRequestMcpClient] = OMIT,
nonce: typing.Optional[str] = OMIT,
response_type: typing.Optional[CreateOauthGrantsRequestResponseType] = OMIT,
state: typing.Optional[str] = OMIT,
@@ -202,6 +205,9 @@ def create(
consent_shown : typing.Optional[bool]
Whether the consent UI listed these scopes for the user. Sending `false` succeeds only when the user has already granted every scope requested, or when the app is one of Whop's own with the consent skip switched on and asks for `openid` alone.
+ mcp_client : typing.Optional[CreateOauthGrantsRequestMcpClient]
+ The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+
nonce : typing.Optional[str]
OIDC nonce, echoed into the resulting ID token. Required when `requested_scopes` includes `openid`.
@@ -229,6 +235,9 @@ def create(
"code_challenge": code_challenge,
"code_challenge_method": code_challenge_method,
"consent_shown": consent_shown,
+ "mcp_client": convert_and_respect_annotation_metadata(
+ object_=mcp_client, annotation=CreateOauthGrantsRequestMcpClient, direction="write"
+ ),
"nonce": nonce,
"redirect_uri": redirect_uri,
"requested_scopes": requested_scopes,
@@ -462,6 +471,7 @@ async def create(
code_challenge: typing.Optional[str] = OMIT,
code_challenge_method: typing.Optional[CreateOauthGrantsRequestCodeChallengeMethod] = OMIT,
consent_shown: typing.Optional[bool] = OMIT,
+ mcp_client: typing.Optional[CreateOauthGrantsRequestMcpClient] = OMIT,
nonce: typing.Optional[str] = OMIT,
response_type: typing.Optional[CreateOauthGrantsRequestResponseType] = OMIT,
state: typing.Optional[str] = OMIT,
@@ -493,6 +503,9 @@ async def create(
consent_shown : typing.Optional[bool]
Whether the consent UI listed these scopes for the user. Sending `false` succeeds only when the user has already granted every scope requested, or when the app is one of Whop's own with the consent skip switched on and asks for `openid` alone.
+ mcp_client : typing.Optional[CreateOauthGrantsRequestMcpClient]
+ The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+
nonce : typing.Optional[str]
OIDC nonce, echoed into the resulting ID token. Required when `requested_scopes` includes `openid`.
@@ -520,6 +533,9 @@ async def create(
"code_challenge": code_challenge,
"code_challenge_method": code_challenge_method,
"consent_shown": consent_shown,
+ "mcp_client": convert_and_respect_annotation_metadata(
+ object_=mcp_client, annotation=CreateOauthGrantsRequestMcpClient, direction="write"
+ ),
"nonce": nonce,
"redirect_uri": redirect_uri,
"requested_scopes": requested_scopes,
diff --git a/src/whop_sdk/users/oauth_grants/types/__init__.py b/src/whop_sdk/users/oauth_grants/types/__init__.py
index 88d897d8d..f9bc53bcd 100644
--- a/src/whop_sdk/users/oauth_grants/types/__init__.py
+++ b/src/whop_sdk/users/oauth_grants/types/__init__.py
@@ -7,6 +7,7 @@
if typing.TYPE_CHECKING:
from .create_oauth_grants_request_code_challenge_method import CreateOauthGrantsRequestCodeChallengeMethod
+ from .create_oauth_grants_request_mcp_client import CreateOauthGrantsRequestMcpClient
from .create_oauth_grants_request_response_type import CreateOauthGrantsRequestResponseType
from .list_oauth_grants_request_direction import ListOauthGrantsRequestDirection
from .list_oauth_grants_request_order import ListOauthGrantsRequestOrder
@@ -14,6 +15,7 @@
from .list_oauth_grants_response_page_info import ListOauthGrantsResponsePageInfo
_dynamic_imports: typing.Dict[str, str] = {
"CreateOauthGrantsRequestCodeChallengeMethod": ".create_oauth_grants_request_code_challenge_method",
+ "CreateOauthGrantsRequestMcpClient": ".create_oauth_grants_request_mcp_client",
"CreateOauthGrantsRequestResponseType": ".create_oauth_grants_request_response_type",
"ListOauthGrantsRequestDirection": ".list_oauth_grants_request_direction",
"ListOauthGrantsRequestOrder": ".list_oauth_grants_request_order",
@@ -45,6 +47,7 @@ def __dir__():
__all__ = [
"CreateOauthGrantsRequestCodeChallengeMethod",
+ "CreateOauthGrantsRequestMcpClient",
"CreateOauthGrantsRequestResponseType",
"ListOauthGrantsRequestDirection",
"ListOauthGrantsRequestOrder",
diff --git a/src/whop_sdk/users/oauth_grants/types/create_oauth_grants_request_mcp_client.py b/src/whop_sdk/users/oauth_grants/types/create_oauth_grants_request_mcp_client.py
new file mode 100644
index 000000000..5ca62715e
--- /dev/null
+++ b/src/whop_sdk/users/oauth_grants/types/create_oauth_grants_request_mcp_client.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CreateOauthGrantsRequestMcpClient(UniversalBaseModel):
+ """
+ The downstream MCP client displayed on the consent screen. Requires explicit consent even when the upstream app already has a grant. Bound to the authorization code and returned on token exchange so the MCP server can verify the approved client.
+ """
+
+ client_id: str = pydantic.Field()
+ """
+ The requesting MCP client's identifier.
+ """
+
+ client_name: str = pydantic.Field()
+ """
+ The requesting MCP client's display name.
+ """
+
+ redirect_uri: str = pydantic.Field()
+ """
+ The downstream redirect URI displayed to the user.
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow