Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
The server defines 13 tools with mostly adequate naming and schema coverage, but suffers from inconsistent parameter descriptions, missing output schemas, and generic descriptions that don't guide LLM selection. All tools have input schemas and descriptions, which is good. However, parameter descriptions are brief and sometimes unhelpful (e.g., 'Page to archive' for archive_page lacks context about what archiving means or how to recover). Output schemas are not documented, LLMs don't know what fields to expect from responses. Error handling is present in the retry decorator but recovery guidance is minimal. Tool naming follows verb_noun convention and is clear. The server declares destructive/write risks per tool, which is positive for security awareness, but tool annotations are not implemented in the MCP schema.
Output schemas not documented, LLMs don't know what response fields to expect, forcing them to guess field names for downstream operations and risking failed tool chains
Parameter descriptions are too brief and lack guidance. E.g., 'Page to archive' (archive_page) doesn't explain what archiving does, whether it's recoverable, or consequences. Expected 50-100 chars per param description; most are 10-30 chars.
Document output schemas for all 13 tools. For each, add a 'Returns' section specifying: field names, types, and whether fields are always present or conditional. Example: 'Returns: {page_id (string), title (string), created_time (ISO 8601), properties (object)}'. This enables LLMs to chain tools correctly.
Expand parameter descriptions to 50-100 chars and include validation rules. Example: 'Page to archive' → 'The page ID (UUID format, e.g., 173dd756-6405-8016-b7e0-dc9aee0a97d6) of the page to archive. Archived pages are hidden from views but can be restored via restore_page. You cannot archive pages that contain active databases.'
Expand tool descriptions to 50-150 chars and include context for LLM selection. Example: 'Archive a page' → 'Archive a page to hide it from views without permanent deletion. Use this instead of delete_block if you might need to recover the page later. Archived pages can be restored with restore_page. Tip: archive parent pages to archive all child pages atomically.'
Implement tool annotations in MCP schema registration. Add 'annotations' object to each tool: {readOnlyHint: true} for get_*, search_*; {destructiveHint: true} for delete_*, archive_*; {idempotentHint: true} for operations safe to retry. Reference: https://spec.modelcontextprotocol.io/2024-12-19/server/tools/#tool-annotations
Enhance error messages with recovery guidance. In the with_retry decorator, map Notion API error codes to actionable advice. Example: '401 Unauthorized → Check that NOTION_API_KEY env var is set and valid. Generate a new token at https://www.notion.com/my-integrations'.
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Tool descriptions under 100 characters lack context for LLM selection. E.g., archive_page: 'Archive a page' (11 chars) doesn't explain when to use it vs delete_block or why an agent would archive. Expected 50-200 chars per description.
Tool annotations (readOnlyHint, destructiveHint) declared in risk field but NOT exposed in MCP schema, toolAnnotations feature is false. LLMs cannot see which tools are destructive or read-only at request time.
Error handling in retry decorator returns McpError with custom error codes but provides no recovery guidance. E.g., 'Invalid authentication token' (ErrorCode.AUTHENTICATION_ERROR) gives no hint that the user should check NOTION_API_KEY env var.
Destructive tools (archive_page, delete_block) do not support dry-run or confirmation. Agents can accidentally archive/delete without a second check. Consider adding a 'dry_run' parameter or separate 'confirm_delete_block' pattern.
Tool composition: create_page requires 'parent_id' (string UUID). Users think 'parent page name', not UUID. Tool should accept parent_name with fallback to search or accept both parent_id and parent_name parameters, or resolve at tool invocation time.
No pagination documented for query_database results. If a database has 500+ items, response will bloat context window. Tool accepts 'page_size' parameter but description doesn't specify max limit (e.g., '1-100') or mention pagination strategy.
query_database
Add dry-run support to destructive tools. Example: add 'dry_run' boolean parameter (default false) to delete_block and archive_page. When true, return what would be deleted but don't execute. This prevents accidental data loss by agents.
Accept human-friendly identifiers alongside UUIDs. For create_page, add optional 'parent_name' parameter. Inside the tool, if parent_id is not provided, search for a page by parent_name first. Alternatively, document that users can use the parent_page_id from ServerConfig as a fallback.
Document pagination limits for query_database. Add to description: 'page_size: Number of results per request (1-100, default 20). Use start_cursor to fetch subsequent pages. Total available items returned in response meta.'
Add per-item error handling for batch operations. If add_content_blocks with 50 blocks fails on block #30, return {succeeded: 30, failed: 20, errors: [{index: 30, reason: 'invalid_type'}]}. Current implementation likely fails the entire batch.
Declare tool permissions. Add a 'scope' field to each tool definition: 'read:page' for get_page, 'write:page' for create_page, 'write:page' for delete_block. This enables least-privilege agent configuration and audit trails per pattern:scope-declaration.