Files
mcp-nextcloud/nextcloud_mcp_server/auth/context_helper.py
T
Chris CoutinhoandClaude Opus 4.7 665cb9b1eb refactor: convert f-string logging to lazy %-style format (G004)
Sweep all 1676 G004 violations across 112 files, converting
`logger.<level>(f"…{x}…")` to `logger.<level>("…%s…", x)`.

Why: ruff rule G004 was added to pyproject.toml to enforce lazy
%-style logging — defers formatting until the log level is enabled
and lets structured log tooling match the unformatted template.

Conversion preserves rendered output byte-for-byte:
- `{x}` → `%s` + `x`
- `{x!r}` / `{x!s}` / `{x!a}` → `%r` / `%s` / `%a`
- Format specs (`{x:.2f}`, `{x:>10}`) → `%s` + `format(x, 'spec')`
  (printf-style specs aren't 1:1 with Python format specs, so we
  delegate to `format()` to keep identical output)
- Literal `%` → `%%`
- Concatenated f-strings (`f"a {x} " "b"`) flattened
- Trailing kwargs (`exc_info=True`) preserved

Verified:
- `uv run ruff check --select G004` → 0 violations
- `uv run ty check -- nextcloud_mcp_server` → passes
- `uv run pytest tests/unit/` → 1010 passed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 01:12:17 +02:00

71 lines
2.5 KiB
Python

"""Helper functions for extracting OAuth context from MCP requests.
ADR-005 compliant implementation for multi-audience token mode.
"""
import logging
from mcp.server.auth.provider import AccessToken
from mcp.server.fastmcp import Context
from ..client import NextcloudClient
logger = logging.getLogger(__name__)
def get_client_from_context(ctx: Context, base_url: str) -> NextcloudClient:
"""
Create NextcloudClient for multi-audience mode (no exchange needed).
ADR-005 Mode 1: Use multi-audience tokens directly.
The UnifiedTokenVerifier validated MCP audience per RFC 7519.
Nextcloud will independently validate its own audience.
Args:
ctx: MCP request context containing session info
base_url: Nextcloud base URL
Returns:
NextcloudClient configured with multi-audience token
Raises:
AttributeError: If context doesn't contain expected OAuth session data
ValueError: If username cannot be extracted from token
"""
try:
# Extract validated access token from MCP context
if hasattr(ctx.request_context.request, "user") and hasattr(
ctx.request_context.request.user, "access_token"
):
access_token: AccessToken = ctx.request_context.request.user.access_token
logger.debug("Retrieved multi-audience token from request.user")
else:
logger.error(
"OAuth authentication failed: No access token found in request"
)
raise AttributeError("No access token found in OAuth request context")
# Extract username from resource field (RFC 8707)
# UnifiedTokenVerifier stored the username here during validation
username = access_token.resource
if not username:
logger.error("No username found in access token resource field")
raise ValueError("Username not available in OAuth token context")
logger.debug(
"Creating NextcloudClient for user %s with multi-audience token (no exchange needed)",
username,
)
# Token was validated to have MCP audience
# Nextcloud will validate its own audience independently
return NextcloudClient.from_token(
base_url=base_url, token=access_token.token, username=username
)
except AttributeError as e:
logger.error("Failed to extract OAuth context: %s", e)
logger.error("This may indicate the server is not running in OAuth mode")
raise