refactor: change OAuth scope separator from colon to dot for IDP compatibility

Many identity providers (AWS Cognito, Okta, Azure AD) reject or mishandle
colons in OAuth scope names. This migrates all custom scopes from
`resource:action` to `resource.action` format (e.g., `notes:read` →
`notes.read`), which is universally accepted and aligns with industry
conventions (Microsoft, Google).

Includes Alembic migration 004 for stored scope strings and ADR-024
documenting the rationale and RFC references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-07 10:07:02 +02:00
co-authored by Claude Opus 4.6
parent 899b9c7191
commit 29fd0486c9
44 changed files with 724 additions and 520 deletions
+11 -11
View File
@@ -25,7 +25,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_list_directory(
ctx: Context, path: str = ""
@@ -65,7 +65,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_read_file(path: str, ctx: Context):
"""Read the content of a file from NextCloud.
@@ -137,7 +137,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:write")
@require_scopes("files.write")
@instrument_tool
async def nc_webdav_write_file(
path: str, content: str, ctx: Context, content_type: str | None = None
@@ -170,7 +170,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:write")
@require_scopes("files.write")
@instrument_tool
async def nc_webdav_create_directory(path: str, ctx: Context):
"""Create a directory in NextCloud.
@@ -192,7 +192,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:write")
@require_scopes("files.write")
@instrument_tool
async def nc_webdav_delete_resource(path: str, ctx: Context):
"""Delete a file or directory in NextCloud.
@@ -213,7 +213,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:write")
@require_scopes("files.write")
@instrument_tool
async def nc_webdav_move_resource(
source_path: str, destination_path: str, ctx: Context, overwrite: bool = False
@@ -240,7 +240,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:write")
@require_scopes("files.write")
@instrument_tool
async def nc_webdav_copy_resource(
source_path: str, destination_path: str, ctx: Context, overwrite: bool = False
@@ -267,7 +267,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_search_files(
ctx: Context,
@@ -390,7 +390,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_find_by_name(
pattern: str, ctx: Context, scope: str = "", limit: int | None = None
@@ -424,7 +424,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_find_by_type(
mime_type: str, ctx: Context, scope: str = "", limit: int | None = None
@@ -458,7 +458,7 @@ def configure_webdav_tools(mcp: FastMCP):
openWorldHint=True,
),
)
@require_scopes("files:read")
@require_scopes("files.read")
@instrument_tool
async def nc_webdav_list_favorites(
ctx: Context, scope: str = "", limit: int | None = None