fix(auth): address PR #757 review feedback

- Branch the ProvisioningRequiredError message on the elicit result so a
  user who acknowledged the prompt isn't told to call
  nc_auth_provision_access (which would loop an LLM that just confirmed
  via elicitation). Other paths keep the existing instruction.
- Convert present_login_url's f-string logger.warning to lazy %s, matching
  present_provisioning_required and the repo's lazy-logging preference.
- Add a test for NEXTCLOUD_PUBLIC_ISSUER_URL trailing-slash normalization.
- Strengthen the decorator-elicits test: split into the "accepted" and
  "message_only" branches so the error-message change is regression-tested.

Refs: cbcoutinho/nextcloud-mcp-server#757#issuecomment-4363552487

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-05-02 15:34:56 +02:00
co-authored by Claude Opus 4.7
parent da60322597
commit 822a8fe2ed
4 changed files with 82 additions and 16 deletions
+3 -2
View File
@@ -115,8 +115,9 @@ async def present_login_url(
return "message_only"
except Exception as e:
logger.warning(
f"Elicitation failed unexpectedly ({type(e).__name__}: {e}), "
"falling back to message"
"Elicitation failed unexpectedly (%s: %s), falling back to message",
type(e).__name__,
e,
)
return "message_only"
@@ -159,13 +159,27 @@ def require_scopes(*required_scopes: str):
present_provisioning_required,
)
await present_provisioning_required(ctx)
elicit_result = await present_provisioning_required(ctx)
error_msg = (
f"Access denied to {func_name}: "
f"Nextcloud access not provisioned. "
f"Please call 'nc_auth_provision_access' first."
)
# Always raise — the decorator can't safely re-check
# stored scopes mid-call (TTL cache, plus the LFv2
# poller may still be running). Only the message
# changes so an LLM that just acknowledged the
# elicitation isn't told to call the auth tool
# again (which would loop).
if elicit_result == "accepted":
error_msg = (
f"Access denied to {func_name}: Nextcloud "
f"access was not provisioned at the time of "
f"this call. If you just completed "
f"provisioning, please retry the request."
)
else:
error_msg = (
f"Access denied to {func_name}: "
f"Nextcloud access not provisioned. "
f"Please call 'nc_auth_provision_access' first."
)
logger.warning(error_msg)
raise ProvisioningRequiredError(error_msg)