Merge branch 'master' into feature/introduce_files_parsing_with_unstructured_service_for_webdav_files_retrieval
This commit is contained in:
@@ -4,6 +4,7 @@ from typing import Optional
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models.calendar import (
|
||||
Calendar,
|
||||
@@ -18,6 +19,7 @@ logger = logging.getLogger(__name__)
|
||||
def configure_calendar_tools(mcp: FastMCP):
|
||||
# Calendar tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_list_calendars(ctx: Context) -> ListCalendarsResponse:
|
||||
"""List all available calendars for the user"""
|
||||
client = get_client(ctx)
|
||||
@@ -27,6 +29,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return ListCalendarsResponse(calendars=calendars, total_count=len(calendars))
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_create_event(
|
||||
calendar_name: str,
|
||||
title: str,
|
||||
@@ -102,6 +105,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.create_event(calendar_name, event_data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_list_events(
|
||||
calendar_name: str,
|
||||
ctx: Context,
|
||||
@@ -203,6 +207,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return events
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_get_event(
|
||||
calendar_name: str,
|
||||
event_uid: str,
|
||||
@@ -214,6 +219,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return event_data
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_update_event(
|
||||
calendar_name: str,
|
||||
event_uid: str,
|
||||
@@ -286,6 +292,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_delete_event(
|
||||
calendar_name: str,
|
||||
event_uid: str,
|
||||
@@ -296,6 +303,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.delete_event(calendar_name, event_uid)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_create_meeting(
|
||||
title: str,
|
||||
date: str,
|
||||
@@ -361,6 +369,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.create_event(calendar_name, event_data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_get_upcoming_events(
|
||||
ctx: Context,
|
||||
calendar_name: str = "", # Empty = all calendars
|
||||
@@ -410,6 +419,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return all_events[:limit]
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_find_availability(
|
||||
duration_minutes: int,
|
||||
ctx: Context,
|
||||
@@ -489,6 +499,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_bulk_operations(
|
||||
operation: str, # "update", "delete", "move"
|
||||
ctx: Context,
|
||||
@@ -737,6 +748,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
}
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_manage_calendar(
|
||||
action: str, # "create", "delete", "update", "list"
|
||||
ctx: Context,
|
||||
@@ -805,6 +817,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
# ============= Todo/Task Tools =============
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_list_todos(
|
||||
calendar_name: str,
|
||||
ctx: Context,
|
||||
@@ -849,6 +862,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_create_todo(
|
||||
calendar_name: str,
|
||||
summary: str,
|
||||
@@ -891,6 +905,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.create_todo(calendar_name, todo_data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_update_todo(
|
||||
calendar_name: str,
|
||||
todo_uid: str,
|
||||
@@ -950,6 +965,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.update_todo(calendar_name, todo_uid, todo_data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_calendar_delete_todo(
|
||||
calendar_name: str,
|
||||
todo_uid: str,
|
||||
@@ -969,6 +985,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
||||
return await client.calendar.delete_todo(calendar_name, todo_uid)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_calendar_search_todos(
|
||||
ctx: Context,
|
||||
status: Optional[str] = None,
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -10,18 +11,21 @@ logger = logging.getLogger(__name__)
|
||||
def configure_contacts_tools(mcp: FastMCP):
|
||||
# Contacts tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_contacts_list_addressbooks(ctx: Context):
|
||||
"""List all addressbooks for the user."""
|
||||
client = get_client(ctx)
|
||||
return await client.contacts.list_addressbooks()
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_contacts_list_contacts(ctx: Context, *, addressbook: str):
|
||||
"""List all contacts in the specified addressbook."""
|
||||
client = get_client(ctx)
|
||||
return await client.contacts.list_contacts(addressbook=addressbook)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_contacts_create_addressbook(
|
||||
ctx: Context, *, name: str, display_name: str
|
||||
):
|
||||
@@ -37,12 +41,14 @@ def configure_contacts_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_contacts_delete_addressbook(ctx: Context, *, name: str):
|
||||
"""Delete an addressbook."""
|
||||
client = get_client(ctx)
|
||||
return await client.contacts.delete_addressbook(name=name)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_contacts_create_contact(
|
||||
ctx: Context, *, addressbook: str, uid: str, contact_data: dict
|
||||
):
|
||||
@@ -59,12 +65,14 @@ def configure_contacts_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_contacts_delete_contact(ctx: Context, *, addressbook: str, uid: str):
|
||||
"""Delete a contact."""
|
||||
client = get_client(ctx)
|
||||
return await client.contacts.delete_contact(addressbook=addressbook, uid=uid)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_contacts_update_contact(
|
||||
ctx: Context, *, addressbook: str, uid: str, contact_data: dict, etag: str = ""
|
||||
):
|
||||
|
||||
@@ -5,6 +5,7 @@ from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.types import ErrorData
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models.cookbook import (
|
||||
Category,
|
||||
@@ -70,6 +71,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_import_recipe(url: str, ctx: Context) -> ImportRecipeResponse:
|
||||
"""Import a recipe from a URL using schema.org metadata.
|
||||
|
||||
@@ -126,6 +128,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_list_recipes(ctx: Context) -> ListRecipesResponse:
|
||||
"""Get all recipes in the database"""
|
||||
client = get_client(ctx)
|
||||
@@ -150,6 +153,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_get_recipe(recipe_id: int, ctx: Context) -> Recipe:
|
||||
"""Get a specific recipe by its ID"""
|
||||
client = get_client(ctx)
|
||||
@@ -174,6 +178,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_create_recipe(
|
||||
name: str,
|
||||
description: str | None = None,
|
||||
@@ -252,6 +257,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_update_recipe(
|
||||
recipe_id: int,
|
||||
name: str | None = None,
|
||||
@@ -340,6 +346,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_delete_recipe(
|
||||
recipe_id: int, ctx: Context
|
||||
) -> DeleteRecipeResponse:
|
||||
@@ -374,6 +381,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_search_recipes(
|
||||
query: str, ctx: Context
|
||||
) -> SearchRecipesResponse:
|
||||
@@ -409,6 +417,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_list_categories(ctx: Context) -> ListCategoriesResponse:
|
||||
"""Get all known categories.
|
||||
|
||||
@@ -435,6 +444,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_get_recipes_in_category(
|
||||
category: str, ctx: Context
|
||||
) -> ListRecipesResponse:
|
||||
@@ -470,6 +480,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_list_keywords(ctx: Context) -> ListKeywordsResponse:
|
||||
"""Get all known keywords/tags"""
|
||||
client = get_client(ctx)
|
||||
@@ -494,6 +505,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_cookbook_get_recipes_with_keywords(
|
||||
keywords: list[str], ctx: Context
|
||||
) -> ListRecipesResponse:
|
||||
@@ -527,6 +539,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_set_config(
|
||||
folder: str | None = None,
|
||||
update_interval: int | None = None,
|
||||
@@ -569,6 +582,7 @@ def configure_cookbook_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_cookbook_reindex(ctx: Context) -> ReindexResponse:
|
||||
"""Trigger a rescan of all recipes into the caching database.
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import Optional
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models.deck import (
|
||||
CardOperationResponse,
|
||||
@@ -116,6 +117,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
# Read Tools (converted from resources)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_boards(ctx: Context) -> list[DeckBoard]:
|
||||
"""Get all Nextcloud Deck boards"""
|
||||
client = get_client(ctx)
|
||||
@@ -123,6 +125,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return boards
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_board(ctx: Context, board_id: int) -> DeckBoard:
|
||||
"""Get details of a specific Nextcloud Deck board"""
|
||||
client = get_client(ctx)
|
||||
@@ -130,6 +133,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return board
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_stacks(ctx: Context, board_id: int) -> list[DeckStack]:
|
||||
"""Get all stacks in a Nextcloud Deck board"""
|
||||
client = get_client(ctx)
|
||||
@@ -137,6 +141,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return stacks
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_stack(ctx: Context, board_id: int, stack_id: int) -> DeckStack:
|
||||
"""Get details of a specific Nextcloud Deck stack"""
|
||||
client = get_client(ctx)
|
||||
@@ -144,6 +149,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return stack
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_cards(
|
||||
ctx: Context, board_id: int, stack_id: int
|
||||
) -> list[DeckCard]:
|
||||
@@ -155,6 +161,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return []
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int
|
||||
) -> DeckCard:
|
||||
@@ -164,6 +171,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return card
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_labels(ctx: Context, board_id: int) -> list[DeckLabel]:
|
||||
"""Get all labels in a Nextcloud Deck board"""
|
||||
client = get_client(ctx)
|
||||
@@ -171,6 +179,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return board.labels
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def deck_get_label(ctx: Context, board_id: int, label_id: int) -> DeckLabel:
|
||||
"""Get details of a specific Nextcloud Deck label"""
|
||||
client = get_client(ctx)
|
||||
@@ -180,6 +189,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
# Create/Update/Delete Tools
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_create_board(
|
||||
ctx: Context, title: str, color: str
|
||||
) -> CreateBoardResponse:
|
||||
@@ -196,6 +206,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
# Stack Tools
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_create_stack(
|
||||
ctx: Context, board_id: int, title: str, order: int
|
||||
) -> CreateStackResponse:
|
||||
@@ -211,6 +222,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return CreateStackResponse(id=stack.id, title=stack.title, order=stack.order)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_update_stack(
|
||||
ctx: Context,
|
||||
board_id: int,
|
||||
@@ -236,6 +248,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_delete_stack(
|
||||
ctx: Context, board_id: int, stack_id: int
|
||||
) -> StackOperationResponse:
|
||||
@@ -256,6 +269,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
|
||||
# Card Tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_create_card(
|
||||
ctx: Context,
|
||||
board_id: int,
|
||||
@@ -289,6 +303,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_update_card(
|
||||
ctx: Context,
|
||||
board_id: int,
|
||||
@@ -341,6 +356,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_delete_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int
|
||||
) -> CardOperationResponse:
|
||||
@@ -362,6 +378,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_archive_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int
|
||||
) -> CardOperationResponse:
|
||||
@@ -383,6 +400,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_unarchive_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int
|
||||
) -> CardOperationResponse:
|
||||
@@ -404,6 +422,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_reorder_card(
|
||||
ctx: Context,
|
||||
board_id: int,
|
||||
@@ -435,6 +454,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
|
||||
# Label Tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_create_label(
|
||||
ctx: Context, board_id: int, title: str, color: str
|
||||
) -> CreateLabelResponse:
|
||||
@@ -450,6 +470,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
return CreateLabelResponse(id=label.id, title=label.title, color=label.color)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_update_label(
|
||||
ctx: Context,
|
||||
board_id: int,
|
||||
@@ -475,6 +496,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_delete_label(
|
||||
ctx: Context, board_id: int, label_id: int
|
||||
) -> LabelOperationResponse:
|
||||
@@ -495,6 +517,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
|
||||
# Card-Label Assignment Tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_assign_label_to_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int, label_id: int
|
||||
) -> CardOperationResponse:
|
||||
@@ -517,6 +540,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_remove_label_from_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int, label_id: int
|
||||
) -> CardOperationResponse:
|
||||
@@ -540,6 +564,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
|
||||
# Card-User Assignment Tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_assign_user_to_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int, user_id: str
|
||||
) -> CardOperationResponse:
|
||||
@@ -562,6 +587,7 @@ def configure_deck_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def deck_unassign_user_from_card(
|
||||
ctx: Context, board_id: int, stack_id: int, card_id: int, user_id: str
|
||||
) -> CardOperationResponse:
|
||||
|
||||
@@ -5,6 +5,7 @@ from mcp.server.fastmcp import Context, FastMCP
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.types import ErrorData
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models.notes import (
|
||||
AppendContentResponse,
|
||||
@@ -84,10 +85,11 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_notes_create_note(
|
||||
title: str, content: str, category: str, ctx: Context
|
||||
) -> CreateNoteResponse:
|
||||
"""Create a new note"""
|
||||
"""Create a new note (requires nc:write scope)"""
|
||||
client = get_client(ctx)
|
||||
try:
|
||||
note_data = await client.notes.create_note(
|
||||
@@ -129,6 +131,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_notes_update_note(
|
||||
note_id: int,
|
||||
etag: str,
|
||||
@@ -137,7 +140,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
category: str | None,
|
||||
ctx: Context,
|
||||
) -> UpdateNoteResponse:
|
||||
"""Update an existing note's title, content, or category.
|
||||
"""Update an existing note's title, content, or category (requires nc:write scope).
|
||||
|
||||
REQUIRED: etag parameter must be provided to prevent overwriting concurrent changes.
|
||||
Get the current ETag by first retrieving the note using nc_notes_get_note tool.
|
||||
@@ -193,6 +196,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_notes_append_content(
|
||||
note_id: int, content: str, ctx: Context
|
||||
) -> AppendContentResponse:
|
||||
@@ -242,8 +246,9 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_notes_search_notes(query: str, ctx: Context) -> SearchNotesResponse:
|
||||
"""Search notes by title or content, returning only id, title, and category."""
|
||||
"""Search notes by title or content, returning only id, title, and category (requires nc:read scope)."""
|
||||
client = get_client(ctx)
|
||||
try:
|
||||
search_results_raw = await client.notes_search_notes(query=query)
|
||||
@@ -287,8 +292,9 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_notes_get_note(note_id: int, ctx: Context) -> Note:
|
||||
"""Get a specific note by its ID"""
|
||||
"""Get a specific note by its ID (requires nc:read scope)"""
|
||||
client = get_client(ctx)
|
||||
try:
|
||||
note_data = await client.notes.get_note(note_id)
|
||||
@@ -315,6 +321,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_notes_get_attachment(
|
||||
note_id: int, attachment_filename: str, ctx: Context
|
||||
) -> dict[str, str]:
|
||||
@@ -360,6 +367,7 @@ def configure_notes_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_notes_delete_note(note_id: int, ctx: Context) -> DeleteNoteResponse:
|
||||
"""Delete a note permanently"""
|
||||
logger.info("Deleting note %s", note_id)
|
||||
|
||||
@@ -4,6 +4,7 @@ import json
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
|
||||
|
||||
@@ -15,6 +16,7 @@ def configure_sharing_tools(mcp: FastMCP):
|
||||
"""
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_share_create(
|
||||
path: str,
|
||||
share_with: str,
|
||||
@@ -53,6 +55,7 @@ def configure_sharing_tools(mcp: FastMCP):
|
||||
return json.dumps(share_data, indent=2)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_share_delete(share_id: int, ctx: Context) -> str:
|
||||
"""Delete a share by its ID.
|
||||
|
||||
@@ -71,6 +74,7 @@ def configure_sharing_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_share_get(share_id: int, ctx: Context) -> str:
|
||||
"""Get information about a specific share.
|
||||
|
||||
@@ -88,6 +92,7 @@ def configure_sharing_tools(mcp: FastMCP):
|
||||
return json.dumps(share_data, indent=2)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_share_list(
|
||||
ctx: Context, path: str | None = None, shared_with_me: bool = False
|
||||
) -> str:
|
||||
@@ -108,6 +113,7 @@ def configure_sharing_tools(mcp: FastMCP):
|
||||
return json.dumps(shares, indent=2)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_share_update(share_id: int, permissions: int, ctx: Context) -> str:
|
||||
"""Update the permissions of an existing share.
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from mcp.server.fastmcp import Context, FastMCP
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -10,18 +11,21 @@ logger = logging.getLogger(__name__)
|
||||
def configure_tables_tools(mcp: FastMCP):
|
||||
# Tables tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_tables_list_tables(ctx: Context):
|
||||
"""List all tables available to the user"""
|
||||
client = get_client(ctx)
|
||||
return await client.tables.list_tables()
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_tables_get_schema(table_id: int, ctx: Context):
|
||||
"""Get the schema/structure of a specific table including columns and views"""
|
||||
client = get_client(ctx)
|
||||
return await client.tables.get_table_schema(table_id)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_tables_read_table(
|
||||
table_id: int,
|
||||
ctx: Context,
|
||||
@@ -33,6 +37,7 @@ def configure_tables_tools(mcp: FastMCP):
|
||||
return await client.tables.get_table_rows(table_id, limit, offset)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_tables_insert_row(table_id: int, data: dict, ctx: Context):
|
||||
"""Insert a new row into a table.
|
||||
|
||||
@@ -42,6 +47,7 @@ def configure_tables_tools(mcp: FastMCP):
|
||||
return await client.tables.create_row(table_id, data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_tables_update_row(row_id: int, data: dict, ctx: Context):
|
||||
"""Update an existing row in a table.
|
||||
|
||||
@@ -51,6 +57,7 @@ def configure_tables_tools(mcp: FastMCP):
|
||||
return await client.tables.update_row(row_id, data)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_tables_delete_row(row_id: int, ctx: Context):
|
||||
"""Delete a row from a table"""
|
||||
client = get_client(ctx)
|
||||
|
||||
@@ -8,6 +8,7 @@ from nextcloud_mcp_server.utils.document_parser import (
|
||||
parse_document,
|
||||
)
|
||||
from nextcloud_mcp_server.config import is_unstructured_parsing_enabled
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
from nextcloud_mcp_server.context import get_client
|
||||
from nextcloud_mcp_server.models import FileInfo, SearchFilesResponse
|
||||
|
||||
@@ -17,6 +18,7 @@ logger = logging.getLogger(__name__)
|
||||
def configure_webdav_tools(mcp: FastMCP):
|
||||
# WebDAV file system tools
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_list_directory(ctx: Context, path: str = ""):
|
||||
"""List files and directories in the specified NextCloud path.
|
||||
|
||||
@@ -30,6 +32,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
return await client.webdav.list_directory(path)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_read_file(path: str, ctx: Context):
|
||||
"""Read the content of a file from NextCloud.
|
||||
|
||||
@@ -105,6 +108,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
}
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_webdav_write_file(
|
||||
path: str, content: str, ctx: Context, content_type: str | None = None
|
||||
):
|
||||
@@ -132,6 +136,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
return await client.webdav.write_file(path, content_bytes, content_type)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_webdav_create_directory(path: str, ctx: Context):
|
||||
"""Create a directory in NextCloud.
|
||||
|
||||
@@ -145,6 +150,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
return await client.webdav.create_directory(path)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_webdav_delete_resource(path: str, ctx: Context):
|
||||
"""Delete a file or directory in NextCloud.
|
||||
|
||||
@@ -158,6 +164,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
return await client.webdav.delete_resource(path)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_webdav_move_resource(
|
||||
source_path: str, destination_path: str, ctx: Context, overwrite: bool = False
|
||||
):
|
||||
@@ -177,6 +184,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:write")
|
||||
async def nc_webdav_copy_resource(
|
||||
source_path: str, destination_path: str, ctx: Context, overwrite: bool = False
|
||||
):
|
||||
@@ -196,6 +204,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_search_files(
|
||||
ctx: Context,
|
||||
scope: str = "",
|
||||
@@ -311,6 +320,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_find_by_name(
|
||||
pattern: str, ctx: Context, scope: str = "", limit: int | None = None
|
||||
) -> SearchFilesResponse:
|
||||
@@ -337,6 +347,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_find_by_type(
|
||||
mime_type: str, ctx: Context, scope: str = "", limit: int | None = None
|
||||
) -> SearchFilesResponse:
|
||||
@@ -363,6 +374,7 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@require_scopes("nc:read")
|
||||
async def nc_webdav_list_favorites(
|
||||
ctx: Context, scope: str = "", limit: int | None = None
|
||||
) -> SearchFilesResponse:
|
||||
|
||||
Reference in New Issue
Block a user