Add read-only support for the Nextcloud Mail app, plus semantic indexing of mail messages. The MCP server never speaks IMAP/POP3 itself: it calls the Mail app's CSRF-free OCS API (/ocs/v2.php/apps/mail/api/...) with the existing Basic-Auth app-password flow and an OCS-APIRequest header, and the Mail app handles IMAP server-side. - client/mail.py: MailClient (accounts, mailboxes, messages, message, attachment), OCS-envelope aware. - models/mail.py: Pydantic models with the API's camelCase aliases. - server/mail.py: 5 read-only MCP tools (mail.read scope), registered in AVAILABLE_APPS. - Vector pipeline: new "mail_message" doc_type wired into scanner (scan_mail_messages, newest-N per mailbox), processor (body -> markdown embedding), per-id verifier, and context expansion. - Tests: client API, model round-trips, verifier behavior; consent-backstop test now derives its allowed set from INDEXED_DOC_TYPES. - README + semantic-search docstrings updated. Requires Mail 5.x / Nextcloud 32+ and a mail account configured in the Mail app. Follow-up: astrolabe must advertise "mail_message" in its enabled_doc_types capability for search under admin doc_type restriction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
"""Pydantic response models for Login Flow v2 auth tools."""
|
|
|
|
from pydantic import Field
|
|
|
|
from nextcloud_mcp_server.models.base import BaseResponse
|
|
|
|
|
|
class ProvisionAccessResponse(BaseResponse):
|
|
"""Response from nc_auth_provision_access tool."""
|
|
|
|
status: str = Field(
|
|
description="Provisioning status: 'login_required', 'already_provisioned', 'declined', 'cancelled', 'error'"
|
|
)
|
|
login_url: str | None = Field(
|
|
None, description="URL to open in browser for Nextcloud login"
|
|
)
|
|
message: str = Field(description="Human-readable status message")
|
|
user_id: str | None = Field(None, description="MCP user ID")
|
|
requested_scopes: list[str] | None = Field(
|
|
None, description="Scopes requested in this provisioning flow"
|
|
)
|
|
|
|
|
|
class ProvisionStatusResponse(BaseResponse):
|
|
"""Response from nc_auth_check_status tool."""
|
|
|
|
status: str = Field(
|
|
description="Status: 'provisioned', 'pending', 'not_initiated', 'error'"
|
|
)
|
|
message: str = Field(description="Human-readable status message")
|
|
user_id: str | None = Field(None, description="MCP user ID")
|
|
scopes: list[str] | None = Field(
|
|
None, description="Granted scopes (None = all scopes)"
|
|
)
|
|
username: str | None = Field(None, description="Nextcloud username (loginName)")
|
|
|
|
|
|
class UpdateScopesResponse(BaseResponse):
|
|
"""Response from nc_auth_update_scopes tool."""
|
|
|
|
status: str = Field(
|
|
description="Status: 'login_required', 'unchanged', 'declined', 'cancelled', 'error'"
|
|
)
|
|
login_url: str | None = Field(
|
|
None, description="URL for re-provisioning with new scopes"
|
|
)
|
|
message: str = Field(description="Human-readable status message")
|
|
previous_scopes: list[str] | None = Field(
|
|
None, description="Previously granted scopes"
|
|
)
|
|
new_scopes: list[str] | None = Field(None, description="Updated scope set")
|
|
|
|
|
|
# All supported application-level scopes (frozenset for O(1) membership tests)
|
|
ALL_SUPPORTED_SCOPES: frozenset[str] = frozenset(
|
|
{
|
|
"notes.read",
|
|
"notes.write",
|
|
"calendar.read",
|
|
"calendar.write",
|
|
"todo.read",
|
|
"todo.write",
|
|
"contacts.read",
|
|
"contacts.write",
|
|
"files.read",
|
|
"files.write",
|
|
"tables.read",
|
|
"tables.write",
|
|
"deck.read",
|
|
"deck.write",
|
|
"cookbook.read",
|
|
"cookbook.write",
|
|
"sharing.read",
|
|
"sharing.write",
|
|
"news.read",
|
|
"news.write",
|
|
"mail.read",
|
|
"collectives.read",
|
|
"collectives.write",
|
|
}
|
|
)
|