feat: Implement ADR-004 Progressive Consent foundation (partial)
Implements Progressive Consent architecture with dual OAuth flows: - Flow 1: Direct client authentication (aud: "mcp-server") - Flow 2: Resource provisioning with refresh tokens Components added: - Client registry with validation (client_registry.py) - Progressive token verifier (progressive_token_verifier.py) - Token broker service integration - Provisioning decorator for MCP tools - OAuth provisioning tools (provision_nextcloud_access, etc.) Configuration: - Progressive Consent enabled by default (ENABLE_PROGRESSIVE_CONSENT=true) - Client validation with pre-registered clients - Audience separation framework KNOWN ISSUE - Token Exchange Pattern Incorrect: The current implementation does NOT properly implement token exchange. MCP session tokens should be EXCHANGED for delegated Nextcloud tokens during tool calls, not stored/reused. Critical corrections needed: 1. Session tokens: Flow 1 token → exchange → ephemeral Nextcloud token - Generated on-demand per tool call - Short-lived, not stored - Scopes limited to tool requirements 2. Background tokens: Flow 2 refresh token → background Nextcloud token - Only for offline/background jobs - Potentially different scopes than session tokens - Must NOT be used for MCP session tool calls The token exchange mechanism needs to be implemented to properly separate session-time delegation from background job authorization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
Chris Coutinho
parent
3b4606b798
commit
d768909fd4
@@ -6,6 +6,7 @@ from mcp.shared.exceptions import McpError
|
||||
from mcp.types import ErrorData
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.auth.provisioning_decorator import require_provisioning
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models.notes import (
|
||||
AppendContentResponse,
|
||||
@@ -86,6 +87,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("notes:write")
|
||||
@require_provisioning
|
||||
async def nc_notes_create_note(
|
||||
title: str, content: str, category: str, ctx: Context
|
||||
) -> CreateNoteResponse:
|
||||
@@ -247,6 +249,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("notes:read")
|
||||
@require_provisioning
|
||||
async def nc_notes_search_notes(query: str, ctx: Context) -> SearchNotesResponse:
|
||||
"""Search notes by title or content, returning only id, title, and category (requires notes:read scope)."""
|
||||
client = get_client(ctx)
|
||||
|
||||
Reference in New Issue
Block a user