zk_remove_link
Delete a link between two notes in a Zettelkasten system by specifying source and target note IDs, optionally removing bidirectional connections.
Instructions
Remove a link between two notes. Args: source_id: ID of the source note target_id: ID of the target note bidirectional: Whether to remove the link in both directions
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| bidirectional | No | ||
| source_id | Yes | ||
| target_id | Yes |
Implementation Reference
- MCP tool decorator and handler function implementing zk_remove_link. Handles input parameters, calls ZettelService.remove_link, and returns success/error messages.@self.mcp.tool( name="zk_remove_link", description="Remove an existing link between two notes.", annotations={ "readOnlyHint": False, "destructiveHint": True, "idempotentHint": True, }, ) def zk_remove_link( source_id: str, target_id: str, bidirectional: bool = False ) -> str: """Remove an existing link between two notes. Args: source_id: The unique ID of the source note target_id: The unique ID of the target note bidirectional: If true, removes links in both directions (source→target and target→source) """ try: # Remove the link source_note, target_note = self.zettel_service.remove_link( source_id=str(source_id), target_id=str(target_id), bidirectional=bidirectional, ) if bidirectional: return f"Bidirectional link removed between {source_id} and {target_id}" else: return f"Link removed from {source_id} to {target_id}" except Exception as e: return self.format_error_response(e) logger.debug("Tool zk_remove_link registered")
- ZettelService.remove_link method called by the tool handler. Retrieves notes, calls model remove_link on source (and target if bidirectional), and persists changes.def remove_link( self, source_id: str, target_id: str, link_type: Optional[LinkType] = None, bidirectional: bool = False ) -> Tuple[Note, Optional[Note]]: """Remove a link between notes.""" source_note = self.repository.get(source_id) if not source_note: raise ValueError(f"Source note with ID {source_id} not found") # Remove link from source to target source_note.remove_link(target_id, link_type) source_note = self.repository.update(source_note) # If bidirectional, remove link from target to source reverse_note = None if bidirectional: target_note = self.repository.get(target_id) if target_note: target_note.remove_link(source_id, link_type) reverse_note = self.repository.update(target_note) return source_note, reverse_note
- Note model method that implements the core link removal logic by filtering the links list and updating timestamp.def remove_link(self, target_id: str, link_type: Optional[LinkType] = None) -> None: """Remove a link to another note.""" if link_type: self.links = [ link for link in self.links if not (link.target_id == target_id and link.link_type == link_type) ] else: self.links = [link for link in self.links if link.target_id != target_id] self.updated_at = datetime.datetime.now()
- Enum defining possible link types used in remove_link operations.class LinkType(str, Enum): """Types of links between notes.""" REFERENCE = "reference" # Simple reference to another note EXTENDS = "extends" # Current note extends another note EXTENDED_BY = "extended_by" # Current note is extended by another note REFINES = "refines" # Current note refines another note REFINED_BY = "refined_by" # Current note is refined by another note CONTRADICTS = "contradicts" # Current note contradicts another note CONTRADICTED_BY = "contradicted_by" # Current note is contradicted by another note QUESTIONS = "questions" # Current note questions another note QUESTIONED_BY = "questioned_by" # Current note is questioned by another note SUPPORTS = "supports" # Current note supports another note SUPPORTED_BY = "supported_by" # Current note is supported by another note RELATED = "related" # Notes are related in some way