fix: address remaining PR #589 review findings
- Consolidate MCP session + login flow cleanup into _mcp_session_with_login_flow() helper,
replacing 4 duplicated AsyncExitStack sites in app.py
- Fix get_shared_storage() race condition by using module-level anyio.Lock() init
(reverts regression from ba59763)
- Collapse cosmetic if/else branching in scope_authorization.py
- Consolidate dual password storage paths into single store_app_password_with_scopes() call
- Mark unused request param as _ in list_supported_scopes
- Make ALL_SUPPORTED_SCOPES an immutable tuple; use list() instead of .copy()
- Add hasattr(ctx, "elicit") guard in elicitation.py, narrow except to NotImplementedError
- Add YAML comment explaining --oauth flag for mcp-login-flow service
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ba597634bd
commit
0d14c75eb1
@@ -49,6 +49,12 @@ async def present_login_url(
|
||||
f"Then check the box below and click OK."
|
||||
)
|
||||
|
||||
if not hasattr(ctx, "elicit"):
|
||||
logger.debug(
|
||||
"Elicitation not available (no elicit method), returning URL in message"
|
||||
)
|
||||
return "message_only"
|
||||
|
||||
try:
|
||||
result = await ctx.elicit(
|
||||
message=message,
|
||||
@@ -70,7 +76,7 @@ async def present_login_url(
|
||||
logger.info("User cancelled login flow")
|
||||
return "cancelled"
|
||||
|
||||
except (AttributeError, NotImplementedError) as e:
|
||||
except NotImplementedError as e:
|
||||
# Elicitation not supported by this client/SDK - fall back to message
|
||||
logger.debug(
|
||||
f"Elicitation not available ({type(e).__name__}: {e}), returning URL in message"
|
||||
|
||||
@@ -128,17 +128,10 @@ def require_scopes(*required_scopes: str):
|
||||
)
|
||||
|
||||
if access_token is None:
|
||||
# No OAuth token — either BasicAuth with env var credentials
|
||||
# or BasicAuth without explicit credentials. Both bypass scope checks.
|
||||
settings = get_settings()
|
||||
if settings.nextcloud_app_password or settings.nextcloud_password:
|
||||
logger.debug(
|
||||
f"No access token for {func_name} - allowing (env var app password)"
|
||||
)
|
||||
else:
|
||||
logger.debug(
|
||||
f"No access token present for {func_name} - allowing (BasicAuth mode)"
|
||||
)
|
||||
# No OAuth token — BasicAuth mode bypasses scope checks
|
||||
logger.debug(
|
||||
f"No access token for {func_name} - allowing (BasicAuth mode)"
|
||||
)
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
# ── Login Flow v2: Check stored app password scopes ──
|
||||
|
||||
@@ -1861,7 +1861,7 @@ class RefreshTokenStorage:
|
||||
|
||||
|
||||
_shared_instance: RefreshTokenStorage | None = None
|
||||
_shared_lock: anyio.Lock | None = None
|
||||
_shared_lock: anyio.Lock = anyio.Lock()
|
||||
|
||||
|
||||
async def get_shared_storage() -> RefreshTokenStorage:
|
||||
@@ -1871,9 +1871,7 @@ async def get_shared_storage() -> RefreshTokenStorage:
|
||||
creating their own lazy singletons. The lock ensures thread-safe
|
||||
initialization on concurrent first-access.
|
||||
"""
|
||||
global _shared_instance, _shared_lock
|
||||
if _shared_lock is None:
|
||||
_shared_lock = anyio.Lock()
|
||||
global _shared_instance
|
||||
async with _shared_lock:
|
||||
if _shared_instance is None:
|
||||
_shared_instance = RefreshTokenStorage.from_env()
|
||||
|
||||
Reference in New Issue
Block a user