Skip to content

Commit fbf9ad9

Browse files
committed
docs(auth): document TokenStorage dual contract, add OAuthTokenStorageAdapter and unit tests
1 parent 5d38e4b commit fbf9ad9

1 file changed

Lines changed: 49 additions & 3 deletions

File tree

src/mcp/client/auth/multi_protocol.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
- **转换约定**:MultiProtocolAuthProvider 在调用方做转换,不扩展协议方法:
1313
- 取回时:_get_credentials() 调用 storage.get_tokens(),若得到 OAuthToken 则经
1414
_oauth_token_to_credentials 转为 OAuthCredentials。
15-
- 写入时:401 流程得到 AuthCredentials 后经 _credentials_to_storage 转为
16-
OAuthToken(仅 OAuthCredentials 转 OAuthToken,其他凭证原样),再调用 storage.set_tokens(to_store)。
15+
- 写入时:_discover_and_authenticate 得到 AuthCredentials 后经 _credentials_to_storage
16+
转为 OAuthToken(仅 OAuthCredentials 转 OAuthToken,其他凭证原样),再调用
17+
storage.set_tokens(to_store)。
1718
- 因此仅实现 get_tokens/set_tokens(OAuthToken) 的旧存储可直接用于 MultiProtocolAuthProvider,
1819
无需改存储实现。可选使用 OAuthTokenStorageAdapter 将此类存储包装为满足 multi_protocol 契约。
1920
"""
@@ -60,7 +61,14 @@
6061

6162

6263
class TokenStorage(Protocol):
63-
"""凭证存储协议(兼容 OAuthToken 与 AuthCredentials)。"""
64+
"""
65+
凭证存储协议(multi_protocol 契约)。
66+
67+
本协议接受 get_tokens() -> AuthCredentials | OAuthToken | None 与
68+
set_tokens(AuthCredentials | OAuthToken)。仅支持 OAuthToken 的旧存储亦可使用:
69+
MultiProtocolAuthProvider 在 _get_credentials/_discover_and_authenticate 内做
70+
OAuthToken <-> OAuthCredentials 转换;或使用 OAuthTokenStorageAdapter 包装。
71+
"""
6472

6573
async def get_tokens(self) -> AuthCredentials | OAuthToken | None:
6674
"""获取已存储的凭证。"""
@@ -109,6 +117,44 @@ def _credentials_to_storage(credentials: AuthCredentials) -> AuthCredentials | O
109117
return credentials
110118

111119

120+
class _OAuthTokenOnlyStorage(Protocol):
121+
"""仅支持 OAuthToken 的存储契约(供 OAuthTokenStorageAdapter 包装)。"""
122+
123+
async def get_tokens(self) -> OAuthToken | None:
124+
...
125+
126+
async def set_tokens(self, tokens: OAuthToken) -> None:
127+
...
128+
129+
130+
class OAuthTokenStorageAdapter:
131+
"""
132+
将仅支持 OAuthToken 的 storage 包装为满足 multi_protocol TokenStorage。
133+
134+
取回时把 OAuthToken 转为 OAuthCredentials;写入时把 OAuthCredentials 转为 OAuthToken
135+
再调用底层 set_tokens。仅 OAuth 凭证会写入底层存储,非 OAuth 凭证(如 APIKeyCredentials)
136+
不写入。
137+
"""
138+
139+
def __init__(self, wrapped: _OAuthTokenOnlyStorage) -> None:
140+
self._wrapped = wrapped
141+
142+
async def get_tokens(self) -> AuthCredentials | OAuthToken | None:
143+
raw = await self._wrapped.get_tokens()
144+
if raw is None:
145+
return None
146+
return _oauth_token_to_credentials(raw)
147+
148+
async def set_tokens(self, tokens: AuthCredentials | OAuthToken) -> None:
149+
to_store = (
150+
_credentials_to_storage(tokens)
151+
if isinstance(tokens, AuthCredentials)
152+
else tokens
153+
)
154+
if isinstance(to_store, OAuthToken):
155+
await self._wrapped.set_tokens(to_store)
156+
157+
112158
class MultiProtocolAuthProvider(httpx.Auth):
113159
"""
114160
多协议认证提供者。

0 commit comments

Comments
 (0)