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:
co-authored by
Claude Sonnet 4.5
parent
b9c94dfab0
commit
e1412320a7
@@ -12,6 +12,7 @@ from mcp.types import (
|
||||
ModelPreferences,
|
||||
SamplingMessage,
|
||||
TextContent,
|
||||
ToolAnnotations,
|
||||
)
|
||||
|
||||
from nextcloud_mcp_server.auth import require_scopes
|
||||
@@ -34,7 +35,13 @@ logger = logging.getLogger(__name__)
|
||||
def configure_semantic_tools(mcp: FastMCP):
|
||||
"""Configure semantic search tools for MCP server."""
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool(
|
||||
title="Semantic Search",
|
||||
annotations=ToolAnnotations(
|
||||
readOnlyHint=True, # Search doesn't modify data
|
||||
openWorldHint=False, # Searches only indexed Nextcloud data
|
||||
),
|
||||
)
|
||||
@require_scopes("semantic:read")
|
||||
@instrument_tool
|
||||
async def nc_semantic_search(
|
||||
@@ -285,7 +292,13 @@ def configure_semantic_tools(mcp: FastMCP):
|
||||
logger.error(f"Search error: {e}", exc_info=True)
|
||||
raise McpError(ErrorData(code=-1, message=f"Search failed: {str(e)}"))
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool(
|
||||
title="Search with AI-Generated Answer",
|
||||
annotations=ToolAnnotations(
|
||||
readOnlyHint=True, # Search doesn't modify data
|
||||
openWorldHint=False, # Searches only indexed Nextcloud data
|
||||
),
|
||||
)
|
||||
@require_scopes("semantic:read")
|
||||
@instrument_tool
|
||||
async def nc_semantic_search_answer(
|
||||
@@ -623,7 +636,13 @@ def configure_semantic_tools(mcp: FastMCP):
|
||||
success=True,
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool(
|
||||
title="Check Indexing Status",
|
||||
annotations=ToolAnnotations(
|
||||
readOnlyHint=True, # Only checks status
|
||||
openWorldHint=True,
|
||||
),
|
||||
)
|
||||
@require_scopes("semantic:read")
|
||||
@instrument_tool
|
||||
async def nc_get_vector_sync_status(ctx: Context) -> VectorSyncStatusResponse:
|
||||
|
||||
Reference in New Issue
Block a user