feat: add MCP tool annotations for enhanced UX
Add ToolAnnotations to all 105+ MCP tools across 13 modules to enable better client-side UX with human-readable titles and behavioral hints. Changes: - Add title and ToolAnnotations to all @mcp.tool() decorators - Apply correct idempotency classification per ADR-017 - Add destructiveHint for delete operations - Set openWorldHint=False for semantic search (internal data only) Modules updated: - OAuth (4 tools): Authentication and provisioning - Notes (7 tools): Note management - WebDAV (11 tools): File operations - Semantic (3 tools): Semantic search and RAG - Calendar (16 tools): Events and todos - Contacts (7 tools): Address book management - Sharing (5 tools): File/folder sharing - Tables (6 tools): Structured data - Deck (25 tools): Kanban board management - Cookbook (13 tools): Recipe management - News (8 tools): RSS feed reader Annotation patterns: - Read operations: readOnlyHint=True, openWorldHint=True - Create operations: idempotentHint=False, openWorldHint=True - Update operations: idempotentHint=False, openWorldHint=True - Delete operations: destructiveHint=True, idempotentHint=True, openWorldHint=True See docs/ADR-017-mcp-tool-annotations.md for rationale and implementation details. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import httpx
|
||||
from mcp.server.auth.middleware.auth_context import get_access_token
|
||||
from mcp.server.auth.provider import AccessToken
|
||||
from mcp.server.fastmcp import Context
|
||||
from mcp.types import ToolAnnotations
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
@@ -684,11 +685,16 @@ def register_oauth_tools(mcp):
|
||||
|
||||
@mcp.tool(
|
||||
name="provision_nextcloud_access",
|
||||
title="Grant Server Access to Nextcloud",
|
||||
description=(
|
||||
"Provision offline access to Nextcloud resources. "
|
||||
"This is required before using Nextcloud tools. "
|
||||
"You'll need to complete an OAuth authorization in your browser."
|
||||
),
|
||||
annotations=ToolAnnotations(
|
||||
idempotentHint=False, # Creates new OAuth session each time
|
||||
openWorldHint=True,
|
||||
),
|
||||
)
|
||||
@require_scopes("openid")
|
||||
async def tool_provision_access(
|
||||
@@ -699,7 +705,13 @@ def register_oauth_tools(mcp):
|
||||
|
||||
@mcp.tool(
|
||||
name="revoke_nextcloud_access",
|
||||
title="Revoke Server Access to Nextcloud",
|
||||
description="Revoke offline access to Nextcloud resources.",
|
||||
annotations=ToolAnnotations(
|
||||
destructiveHint=True, # Removes stored access tokens
|
||||
idempotentHint=True, # Revoking revoked access = same end state
|
||||
openWorldHint=True,
|
||||
),
|
||||
)
|
||||
@require_scopes("openid")
|
||||
async def tool_revoke_access(
|
||||
@@ -709,7 +721,12 @@ def register_oauth_tools(mcp):
|
||||
|
||||
@mcp.tool(
|
||||
name="check_provisioning_status",
|
||||
title="Check Provisioning Status",
|
||||
description="Check whether Nextcloud access is provisioned.",
|
||||
annotations=ToolAnnotations(
|
||||
readOnlyHint=True, # Only checks status, doesn't modify
|
||||
openWorldHint=True,
|
||||
),
|
||||
)
|
||||
@require_scopes("openid")
|
||||
async def tool_check_status(
|
||||
@@ -719,10 +736,15 @@ def register_oauth_tools(mcp):
|
||||
|
||||
@mcp.tool(
|
||||
name="check_logged_in",
|
||||
title="Check Server Login Status",
|
||||
description=(
|
||||
"Check if you are logged in to Nextcloud. "
|
||||
"If not logged in, this tool will prompt you to complete the login flow."
|
||||
),
|
||||
annotations=ToolAnnotations(
|
||||
readOnlyHint=True, # Checking status doesn't modify state
|
||||
openWorldHint=True,
|
||||
),
|
||||
)
|
||||
@require_scopes("openid")
|
||||
async def tool_check_logged_in(ctx: Context, user_id: Optional[str] = None) -> str:
|
||||
|
||||
Reference in New Issue
Block a user