@@ -28,9 +28,29 @@ async def write_note(
2828) -> EntityResponse | str :
2929 """Write a markdown note to the knowledge base.
3030
31+ The content can include semantic observations and relations using markdown syntax.
32+ Relations can be specified either explicitly or through inline wiki-style links:
33+
34+ Observations format:
35+ `- [category] Observation text #tag1 #tag2 (optional context)`
36+
37+ Examples:
38+ `- [design] Files are the source of truth #architecture (All state comes from files)`
39+ `- [tech] Using SQLite for storage #implementation`
40+ `- [note] Need to add error handling #todo`
41+
42+ Relations format:
43+ - Explicit: `- relation_type [[Entity]] (optional context)`
44+ - Inline: Any `[[Entity]]` reference creates a relation
45+
46+ Examples:
47+ `- depends_on [[Content Parser]] (Need for semantic extraction)`
48+ `- implements [[Search Spec]] (Initial implementation)`
49+ `- This feature extends [[Base Design]] and uses [[Core Utils]]`
50+
3151 Args:
3252 title: The title of the note
33- content: Markdown content for the note
53+ content: Markdown content for the note, can include observations and relations
3454 folder: the folder where the file should be saved
3555 tags: Optional list of tags to categorize the note
3656 verbose: If True, returns full EntityResponse with semantic info
@@ -40,19 +60,32 @@ async def write_note(
4060 If verbose=True: EntityResponse with full semantic details
4161
4262 Examples:
43- # Create a simple note
63+ # Note with both explicit and inline relations
4464 write_note(
45- tile="Meeting Notes: Project Planning.md",
46- content="# Key Points\\ n\\ n- Discussed timeline\\ n- Set priorities"
47- folder="notes"
65+ title="Search Implementation",
66+ content="# Search Component\\ n\\ n"
67+ "Implementation of the search feature, building on [[Core Search]].\\ n\\ n"
68+ "## Observations\\ n"
69+ "- [tech] Using FTS5 for full-text search #implementation\\ n"
70+ "- [design] Need pagination support #todo\\ n\\ n"
71+ "## Relations\\ n"
72+ "- implements [[Search Spec]]\\ n"
73+ "- depends_on [[Database Schema]]",
74+ folder="docs/components"
4875 )
4976
50- # Create note with tags
77+ # Note with tags
5178 write_note(
52- title="Security Review",
53- content="# Findings\\ n\\ n1. Updated auth flow\\ n2. Added rate limiting",
54- folder="security",
55- tags=["security", "development"]
79+ title="Error Handling Design",
80+ content="# Error Handling\\ n\\ n"
81+ "This design builds on [[Reliability Design]].\\ n\\ n"
82+ "## Approach\\ n"
83+ "- [design] Use error codes #architecture\\ n"
84+ "- [tech] Implement retry logic #implementation\\ n\\ n"
85+ "## Relations\\ n"
86+ "- extends [[Base Error Handling]]",
87+ folder="docs/design",
88+ tags=["architecture", "reliability"]
5689 )
5790 """
5891 logger .info (f"Writing note folder:'{ folder } ' title: '{ title } '" )
@@ -76,26 +109,58 @@ async def write_note(
76109 return result if verbose else result .permalink
77110
78111
79- @mcp .tool (description = "Read a note's content by its title or permalink " )
112+ @mcp .tool (description = "Read note content by title, permalink, relation, or pattern " )
80113async def read_note (identifier : str ) -> str :
81- """Get the markdown content of a note.
82- Uses the resource router to return the actual file content.
114+ """Get note content in unified diff format.
115+
116+ The content is returned in a unified diff inspired format:
117+ ```
118+ --- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
119+ <document content>
120+ ```
121+
122+ Multiple documents (from relations or pattern matches) are separated by
123+ additional headers.
83124
84125 Args:
85- identifier: Note title or permalink
126+ identifier: Can be one of:
127+ - Note title ("Project Planning")
128+ - Note permalink ("docs/example")
129+ - Relation path ("docs/example/depends-on/other-doc")
130+ - Pattern match ("docs/*-architecture")
86131
87132 Returns:
88- The note's markdown content
133+ Document content in unified diff format. For single documents, returns
134+ just that document's content. For relations or pattern matches, returns
135+ multiple documents separated by unified diff headers.
89136
90137 Examples:
91- # Read by title
92- read_note("Meeting Notes: Project Planning")
138+ # Single document
139+ content = await read_note("Project Planning")
93140
94141 # Read by permalink
95- read_note("notes/project-planning")
142+ content = await read_note("docs/architecture/file-first")
143+
144+ # Follow relation
145+ content = await read_note("docs/architecture/depends-on/docs/content-parser")
146+
147+ # Pattern matching
148+ content = await read_note("docs/*-architecture") # All architecture docs
149+ content = await read_note("docs/*/implements/*") # Find implementations
150+
151+ Output format:
152+ ```
153+ --- memory://docs/example 2025-01-31T19:32:49 7d9f1c8b
154+ <first document content>
155+
156+ --- memory://docs/other 2025-01-30T15:45:22 a1b2c3d4
157+ <second document content>
158+ ```
96159
97- Raises:
98- ValueError: If the note cannot be found
160+ The headers include:
161+ - Full memory:// URI for the document
162+ - Last modified timestamp
163+ - Content checksum
99164 """
100165 logger .info (f"Reading note { identifier } " )
101166 url = memory_url_path (identifier )
0 commit comments