"""View note tool for Basic Memory MCP server.""" from textwrap import dedent from typing import Optional from loguru import logger from fastmcp import Context from basic_memory.mcp.server import mcp from basic_memory.mcp.tools.read_note import read_note @mcp.tool( description="View a note as a formatted artifact for better readability.", ) async def view_note( identifier: str, project: Optional[str] = None, page: int = 1, page_size: int = 10, context: Context | None = None, ) -> str: """View a markdown note as a formatted artifact. This tool reads a note using the same logic as read_note but displays the content as a markdown artifact for better viewing experience in Claude Desktop. Project parameter optional with server resolution. After calling this tool, create an artifact using the returned content to display the note in a readable format. The tool returns the note content that should be used to create a markdown artifact. Args: identifier: The title or permalink of the note to view project: Project name to read from. Optional - server will resolve using hierarchy. If unknown, use list_memory_projects() to discover available projects. page: Page number for paginated results (default: 1) page_size: Number of items per page (default: 10) context: Optional FastMCP context for performance caching. Returns: The note content as a markdown artifact with a confirmation message. Examples: # View a note by title view_note("Meeting Notes") # View a note by permalink view_note("meetings/weekly-standup") # View with pagination view_note("large-document", page=2, page_size=5) # Explicit project specification view_note("Meeting Notes", project="my-project") Raises: HTTPError: If project doesn't exist or is inaccessible SecurityError: If identifier attempts path traversal """ logger.info(f"Viewing note: {identifier} in project: {project}") # Call the existing read_note logic content = await read_note.fn(identifier, project, page, page_size, context) # Check if this is an error message (note not found) if "# Note Not Found" in content: return content # Return error message directly instead of creating artifact # Extract title from content if possible title = identifier lines = content.split("\n") for line in lines: if line.startswith("title:"): # Extract title from frontmatter title = line.split("title:", 1)[1].strip().strip('"').strip("'") break elif line.startswith("# "): # Extract title from first heading title = line[2:].strip() break # Return the artifact XML as part of the response artifact = f'\n{content}\n' return dedent(f""" Create an artifact using the returned content to display the note in a readable format. {artifact}\n\n✅ Note displayed as artifact: **{title}**""")