1+ from textwrap import dedent
12from typing import Optional
23
4+ from loguru import logger
5+
36from basic_memory .mcp .tools .utils import call_delete
47from basic_memory .mcp .server import mcp
58from basic_memory .mcp .async_client import client
69from basic_memory .mcp .project_session import get_active_project
710from basic_memory .schemas import DeleteEntitiesResponse
811
912
13+ def _format_delete_error_response (error_message : str , identifier : str ) -> str :
14+ """Format helpful error responses for delete failures that guide users to successful deletions."""
15+
16+ # Note not found errors
17+ if "entity not found" in error_message .lower () or "not found" in error_message .lower ():
18+ search_term = identifier .split ("/" )[- 1 ] if "/" in identifier else identifier
19+ title_format = (
20+ identifier .split ("/" )[- 1 ].replace ("-" , " " ).title () if "/" in identifier else identifier
21+ )
22+ permalink_format = identifier .lower ().replace (" " , "-" )
23+
24+ return dedent (f"""
25+ # Delete Failed - Note Not Found
26+
27+ The note '{ identifier } ' could not be found for deletion.
28+
29+ ## This might mean:
30+ 1. **Already deleted**: The note may have been deleted previously
31+ 2. **Wrong identifier**: The identifier format might be incorrect
32+ 3. **Different project**: The note might be in a different project
33+
34+ ## How to verify:
35+ 1. **Search for the note**: Use `search_notes("{ search_term } ")` to find it
36+ 2. **Try different formats**:
37+ - If you used a permalink like "folder/note-title", try just the title: "{ title_format } "
38+ - If you used a title, try the permalink format: "{ permalink_format } "
39+
40+ 3. **Check if already deleted**: Use `list_directory("/")` to see what notes exist
41+ 4. **Check current project**: Use `get_current_project()` to verify you're in the right project
42+
43+ ## If the note actually exists:
44+ ```
45+ # First, find the correct identifier:
46+ search_notes("{ identifier } ")
47+
48+ # Then delete using the correct identifier:
49+ delete_note("correct-identifier-from-search")
50+ ```
51+
52+ ## If you want to delete multiple similar notes:
53+ Use search to find all related notes and delete them one by one.
54+ """ ).strip ()
55+
56+ # Permission/access errors
57+ if (
58+ "permission" in error_message .lower ()
59+ or "access" in error_message .lower ()
60+ or "forbidden" in error_message .lower ()
61+ ):
62+ return f"""# Delete Failed - Permission Error
63+
64+ You don't have permission to delete '{ identifier } ': { error_message }
65+
66+ ## How to resolve:
67+ 1. **Check permissions**: Verify you have delete/write access to this project
68+ 2. **File locks**: The note might be open in another application
69+ 3. **Project access**: Ensure you're in the correct project with proper permissions
70+
71+ ## Alternative actions:
72+ - Check current project: `get_current_project()`
73+ - Switch to correct project: `switch_project("project-name")`
74+ - Verify note exists first: `read_note("{ identifier } ")`
75+
76+ ## If you have read-only access:
77+ Send a message to support@basicmachines.co to request deletion, or ask someone with write access to delete the note."""
78+
79+ # Server/filesystem errors
80+ if (
81+ "server error" in error_message .lower ()
82+ or "filesystem" in error_message .lower ()
83+ or "disk" in error_message .lower ()
84+ ):
85+ return f"""# Delete Failed - System Error
86+
87+ A system error occurred while deleting '{ identifier } ': { error_message }
88+
89+ ## Immediate steps:
90+ 1. **Try again**: The error might be temporary
91+ 2. **Check file status**: Verify the file isn't locked or in use
92+ 3. **Check disk space**: Ensure the system has adequate storage
93+
94+ ## Troubleshooting:
95+ - Verify note exists: `read_note("{ identifier } ")`
96+ - Check project status: `get_current_project()`
97+ - Try again in a few moments
98+
99+ ## If problem persists:
100+ Send a message to support@basicmachines.co - there may be a filesystem or database issue."""
101+
102+ # Database/sync errors
103+ if "database" in error_message .lower () or "sync" in error_message .lower ():
104+ return f"""# Delete Failed - Database Error
105+
106+ A database error occurred while deleting '{ identifier } ': { error_message }
107+
108+ ## This usually means:
109+ 1. **Sync conflict**: The file system and database are out of sync
110+ 2. **Database lock**: Another operation is accessing the database
111+ 3. **Corrupted entry**: The database entry might be corrupted
112+
113+ ## Steps to resolve:
114+ 1. **Try again**: Wait a moment and retry the deletion
115+ 2. **Check note status**: `read_note("{ identifier } ")` to see current state
116+ 3. **Manual verification**: Use `list_directory()` to see if file still exists
117+
118+ ## If the note appears gone but database shows it exists:
119+ Send a message to support@basicmachines.co - a manual database cleanup may be needed."""
120+
121+ # Generic fallback
122+ return f"""# Delete Failed
123+
124+ Error deleting note '{ identifier } ': { error_message }
125+
126+ ## General troubleshooting:
127+ 1. **Verify the note exists**: `read_note("{ identifier } ")` or `search_notes("{ identifier } ")`
128+ 2. **Check permissions**: Ensure you can edit/delete files in this project
129+ 3. **Try again**: The error might be temporary
130+ 4. **Check project**: Make sure you're in the correct project
131+
132+ ## Step-by-step approach:
133+ ```
134+ # 1. Confirm note exists and get correct identifier
135+ search_notes("{ identifier } ")
136+
137+ # 2. Read the note to verify access
138+ read_note("correct-identifier-from-search")
139+
140+ # 3. Try deletion with correct identifier
141+ delete_note("correct-identifier-from-search")
142+ ```
143+
144+ ## Alternative approaches:
145+ - Check what notes exist: `list_directory("/")`
146+ - Verify current project: `get_current_project()`
147+ - Switch projects if needed: `switch_project("correct-project")`
148+
149+ ## Need help?
150+ If the note should be deleted but the operation keeps failing, send a message to support@basicmachines.co."""
151+
152+
10153@mcp .tool (description = "Delete a note by title or permalink" )
11- async def delete_note (identifier : str , project : Optional [str ] = None ) -> bool :
154+ async def delete_note (identifier : str , project : Optional [str ] = None ) -> bool | str :
12155 """Delete a note from the knowledge base.
13156
14157 Args:
@@ -31,6 +174,18 @@ async def delete_note(identifier: str, project: Optional[str] = None) -> bool:
31174 active_project = get_active_project (project )
32175 project_url = active_project .project_url
33176
34- response = await call_delete (client , f"{ project_url } /knowledge/entities/{ identifier } " )
35- result = DeleteEntitiesResponse .model_validate (response .json ())
36- return result .deleted
177+ try :
178+ response = await call_delete (client , f"{ project_url } /knowledge/entities/{ identifier } " )
179+ result = DeleteEntitiesResponse .model_validate (response .json ())
180+
181+ if result .deleted :
182+ logger .info (f"Successfully deleted note: { identifier } " )
183+ return True
184+ else :
185+ logger .warning (f"Delete operation completed but note was not deleted: { identifier } " )
186+ return False
187+
188+ except Exception as e :
189+ logger .error (f"Delete failed for '{ identifier } ': { e } " )
190+ # Return formatted error message for better user experience
191+ return _format_delete_error_response (str (e ), identifier )
0 commit comments