Implement visual feedback for MCP tool calls with configurable notifications. Features: - Real-time notifications when tools are called (request only, no completion) - Tool-specific emoji icons for visual clarity - Rate limiting (max 10 notifications/second) - Notification history tracking (last 100 entries) - Configurable settings: enable/disable, show parameters, duration, console logging - History modal with filtering and export to clipboard Implementation: - Created NotificationManager with queue-based rate limiting - Created NotificationHistoryModal for viewing past tool calls - Integrated into tool call interceptor in ToolRegistry - Added notification settings UI section - Added 'View MCP Notification History' command Benefits: - Visual feedback for debugging and monitoring - Transparency into AI agent actions - Simple on/off toggle, no complex verbosity settings - Zero performance impact when disabled - History tracks success/failure/duration for all calls All 10 phases of the roadmap are now complete\!
55 KiB
Changelog
All notable changes to the Obsidian MCP Server plugin will be documented in this file.
[9.0.0] - 2025-10-17
🎨 Phase 10: UI Notifications
This release adds visual feedback for MCP tool calls with configurable notifications in the Obsidian UI. Provides transparency into API activity, easier debugging, and optional notification history tracking.
Added
Notification System
- Real-time notifications for MCP tool calls displayed in Obsidian UI
- Shows notification when tool is called (request only, no completion notifications)
- Configurable notification duration (default: 3 seconds)
- Rate limiting (max 10 notifications/second) to prevent UI spam
- Simple on/off toggle - no verbosity levels needed
- Tool-specific icons for visual clarity:
- 📖 Read operations (
read_note,read_excalidraw) - ✏️ Write operations (
create_note,update_note,update_frontmatter,update_sections) - 🗑️ Delete operations (
delete_note) - 📝 Rename operations (
rename_file) - 🔍 Search operations (
search,search_waypoints) - 📋 List operations (
list) - 📊 Stat operations (
stat,exists) - ℹ️ Info operations (
get_vault_info) - 🗺️ Waypoint operations (
get_folder_waypoint) - 📁 Folder operations (
is_folder_note) - 🔗 Link operations (
validate_wikilinks,resolve_wikilink,backlinks)
- 📖 Read operations (
Notification Settings
Enable notifications- Toggle notifications on/offShow parameters- Include tool parameters in notifications (truncated for readability)Notification duration- How long notifications stay visible (milliseconds)Log to console- Also log tool calls to browser console for debugging- All settings available in plugin settings UI under "UI Notifications" section
Notification History
- Stores last 100 tool calls in memory
- View history via command palette: "View MCP Notification History"
- View history via settings: "View History" button
- History modal features:
- Filter by tool name
- Filter by type (all/success/error)
- Shows timestamp, duration, parameters, and error messages
- Export history to clipboard as JSON
- Clear history button
- Each history entry includes:
timestamp- When the tool was calledtoolName- Name of the toolargs- Tool parameterssuccess- Whether the call succeededduration- Execution time in millisecondserror- Error message (if failed)
Notification Example
- Tool call:
🔧 MCP: list({ path: "projects", recursive: true }) - Note: Only request notifications are shown, not completion or error notifications
Implementation Details
- Non-blocking notification display (async queue)
- Notification queue with rate limiting to prevent UI freezing
- Parameter truncation for long values (max 50 chars)
- Privacy-aware: sensitive data not shown in notifications
- Zero performance impact when disabled
- Integrates seamlessly with existing tool call flow
Files Added
src/ui/notifications.ts- Notification manager with rate limitingsrc/ui/notification-history.ts- History modal for viewing past tool calls
Files Modified
src/types/settings-types.ts- Added notification settings typessrc/settings.ts- Added notification settings UIsrc/tools/index.ts- Integrated notifications into tool call interceptorsrc/server/mcp-server.ts- Added notification manager supportsrc/main.ts- Initialize notification manager and add history command
Benefits
- Developer Experience: Visual feedback for API activity, easier debugging
- User Experience: Awareness when tools are called, transparency into AI agent actions
- Debugging: See exact parameters, track execution times in history, identify bottlenecks
- Optional: Can be completely disabled for production use
- Simple: Single toggle to enable/disable, no complex verbosity settings
[8.0.0] - 2025-10-17
🚀 Phase 9: Linking & Backlinks
This release adds powerful tools for working with wikilinks, resolving links, and querying backlinks. Enables programmatic link validation, resolution, and knowledge graph exploration.
Added
New Tool: validate_wikilinks
- Validate all wikilinks in a note and report unresolved links
- Parses all
[[wikilinks]]in the file using regex - Resolves links using Obsidian's MetadataCache for accuracy
- Provides suggestions for broken links using fuzzy matching
- Returns structured JSON with:
path- File pathtotalLinks- Total number of links foundresolvedLinks- Array of resolved links with:text- Full link text including bracketstarget- Resolved target file pathalias- Display alias (if present)
unresolvedLinks- Array of unresolved links with:text- Full link text including bracketsline- Line number where link appearssuggestions- Array of suggested target paths
- Supports both
[[link]]and[[link|alias]]formats - Handles links with headings
[[note#heading]] - Use to identify and fix broken links in notes
New Tool: resolve_wikilink
- Resolve a single wikilink from a source note to its target path
- Uses Obsidian's MetadataCache.getFirstLinkpathDest() for accurate resolution
- Follows Obsidian's link resolution rules:
- Shortest path matching
- Relative paths
- Aliases
- Headings and blocks
- Returns structured JSON with:
sourcePath- Source note pathlinkText- Link text to resolve (without brackets)resolved- Boolean indicating if link was resolvedtargetPath- Resolved target file path (if found)suggestions- Array of suggested paths (if not found)
- Parameters:
sourcePath- Path of note containing the linklinkText- Link text without brackets (e.g., "target note", "folder/note", "note#heading")
- Supports complex link formats (headings, aliases, relative paths)
- Use to programmatically resolve links before following them
New Tool: backlinks
- Get all backlinks to a note with optional unlinked mentions
- Uses Obsidian's MetadataCache.getBacklinksForFile() for linked backlinks
- Optional text-based search for unlinked mentions
- Returns structured JSON with:
path- Target note pathbacklinks- Array of backlinks with:sourcePath- Source file path containing the linktype- Either "linked" (wikilink) or "unlinked" (text mention)occurrences- Array of occurrences with:line- Line number (1-indexed)snippet- Context snippet around the link
totalBacklinks- Total number of backlinks
- Parameters:
path- Target note pathincludeUnlinked- Include unlinked mentions (default: false)includeSnippets- Include context snippets (default: true)
- Efficient use of Obsidian's built-in caching and indexing
- Use to explore note connections and build knowledge graphs
- Warning:
includeUnlinkedcan be slow for large vaults
New Utility: link-utils.ts
LinkUtilsclass for wikilink operationsparseWikilinks()- Parse all wikilinks from content with positionsresolveLink()- Resolve a wikilink to its target filefindSuggestions()- Find potential matches for unresolved linksgetBacklinks()- Get all backlinks to a filevalidateWikilinks()- Validate all wikilinks in a file- Regex-based wikilink parsing:
/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g - Fuzzy matching algorithm for link suggestions
- Handles edge cases (circular links, missing files)
Modified
Updated: vault-tools.ts
- Added
validateWikilinks()method - Added
resolveWikilink()method - Added
getBacklinks()method - Imports LinkUtils for wikilink operations
Updated: index.ts (Tool Registry)
- Added
validate_wikilinkstool definition - Added
resolve_wikilinktool definition - Added
backlinkstool definition - Added case handlers for three new tools
Updated: mcp-types.ts
- Added Phase 9 types:
ResolvedLink- Resolved wikilink informationUnresolvedLink- Unresolved wikilink informationValidateWikilinksResult- Result from validate_wikilinksResolveWikilinkResult- Result from resolve_wikilinkBacklinkOccurrence- Backlink occurrence in a fileBacklinkInfo- Backlink from a source fileBacklinksResult- Result from backlinks operation
Benefits
- Link Validation: Identify and fix broken links in notes
- Link Resolution: Programmatically resolve links before following them
- Knowledge Graphs: Explore note connections and build knowledge graphs
- Complex Links: Support for headings, aliases, and relative paths
- Accurate Resolution: Uses Obsidian's native link resolution rules
- Performance: Efficient use of MetadataCache and built-in indexing
- Suggestions: Fuzzy matching helps find intended targets for broken links
Technical Details
- Wikilink parsing uses regex:
/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g - Link resolution uses
MetadataCache.getFirstLinkpathDest() - Backlink detection uses
MetadataCache.getBacklinksForFile() - Suggestion engine uses multi-factor scoring (basename, path, character matching)
- Unlinked mentions use word boundary regex for whole-word matching
- Context snippets extracted with configurable length (default: 100 chars)
[7.0.0] - 2025-10-17
🚀 Phase 8: Write Operations & Concurrency
This release implements safe write operations with concurrency control, partial updates, conflict resolution, and file rename/move with automatic link updates.
Added
New Tool: update_frontmatter
- Update frontmatter fields without modifying note content
- Supports patch operations (add/update fields) via
patchparameter - Supports field removal via
removeparameter (array of field names) - Returns structured JSON with:
success- Boolean operation statuspath- File pathversionId- New version ID for subsequent operationsmodified- Modification timestampupdatedFields- Array of fields that were added/updatedremovedFields- Array of fields that were removed
- Includes concurrency control via optional
ifMatchparameter - Preserves content and formatting
- Automatically creates frontmatter if none exists
- Use for metadata-only updates to avoid race conditions
New Tool: update_sections
- Update specific sections of a note by line range
- Reduces race conditions by avoiding full file overwrites
- Supports multiple edits in a single operation
- Edits applied from bottom to top to preserve line numbers
- Returns structured JSON with:
success- Boolean operation statuspath- File pathversionId- New version IDmodified- Modification timestampsectionsUpdated- Count of sections updated
- Each edit specifies:
startLine- Starting line number (1-indexed, inclusive)endLine- Ending line number (1-indexed, inclusive)content- New content to replace the section
- Includes concurrency control via optional
ifMatchparameter - Validates line ranges before applying edits
- Use for surgical edits to specific parts of large notes
New Tool: rename_file
- Rename or move files with automatic wikilink updates
- Uses Obsidian's FileManager to maintain link integrity
- Supports both rename (same folder) and move (different folder)
- Returns structured JSON with:
success- Boolean operation statusoldPath- Original file pathnewPath- New file pathlinksUpdated- Always 0 (tracking not available in current API)affectedFiles- Always empty array (tracking not available in current API)versionId- New version ID
- Parameters:
path- Current file pathnewPath- New file path (can be in different folder)updateLinks- Auto-update wikilinks (default: true)ifMatch- Optional version ID for concurrency control
- Automatically creates parent folders if needed
- Prevents conflicts with existing files
- Links are automatically updated by Obsidian's FileManager
- Use to reorganize vault structure while preserving links
- Note: Link tracking fields return placeholder values due to API limitations
New Utility: version-utils.ts
VersionUtilsclass for ETag-based concurrency controlgenerateVersionId()- Create version ID from file mtime and sizevalidateVersion()- Check if provided version matches currentversionMismatchError()- Generate 412 Precondition Failed errorcreateVersionedResponse()- Add version info to responses- Uses SHA-256 hash with URL-safe base64 encoding
Enhanced Tool: create_note
- Added
onConflictparameter with three strategies:error(default) - Fail if file existsoverwrite- Delete existing file and create newrename- Auto-generate unique name by appending number
- Returns structured JSON with:
success- Boolean operation statuspath- Created file path (may differ if renamed)versionId- Version ID for subsequent operationscreated- Creation timestamprenamed- Boolean indicating if file was renamedoriginalPath- Original path if renamed
- Existing
createParentsparameter still supported - Better conflict handling and error messages
Enhanced Tool: delete_note
- Added
softparameter (default: true):true- Move to.trashfolder (recoverable)false- Permanent deletion (cannot be undone)
- Added
dryRunparameter (default: false):true- Preview deletion without executingfalse- Perform actual deletion
- Added
ifMatchparameter for concurrency control - Returns structured JSON with:
deleted- Boolean indicating if deletion occurredpath- File pathdestination- Trash destination (for soft deletes)dryRun- Boolean indicating preview modesoft- Boolean indicating soft delete mode
- Use for safer file operations with preview and recovery
Type Definitions (src/types/mcp-types.ts)
ConflictStrategy- Type for conflict resolution strategiesSectionEdit- Interface for section edit operationsUpdateFrontmatterResult- Result from frontmatter updatesUpdateSectionsResult- Result from section updatesCreateNoteResult- Enhanced result from note creationRenameFileResult- Result from file rename/moveDeleteNoteResult- Enhanced result from deletion
Frontmatter Serialization (src/utils/frontmatter-utils.ts)
serializeFrontmatter()- Convert frontmatter object to YAML string- Handles arrays, objects, strings, numbers, booleans
- Automatic quoting for strings with special characters
- Proper YAML formatting with delimiters
Improvements
Concurrency Control
- ETag-based optimistic locking across all write operations
ifMatchparameter prevents lost updates in concurrent scenarios- Version mismatch returns 412 Precondition Failed with clear error
- All write operations return
versionIdfor subsequent operations - Get
versionIdfrom read operations to ensure consistency
Conflict Resolution
- Three strategies for handling file conflicts in
create_note - Automatic unique name generation for rename strategy
- Clear error messages for each conflict scenario
- Prevents accidental overwrites
Link Integrity
- Automatic wikilink updates when renaming/moving files
- Uses Obsidian's FileManager for reliable link maintenance
- Tracks affected files and link update count
- Supports moving files between folders
Safe Operations
- Soft delete moves files to trash instead of permanent deletion
- Dry-run preview for deletions
- Parent folder auto-creation for rename operations
- Validation before destructive operations
Partial Updates
- Update frontmatter without touching content
- Update specific sections without full file overwrites
- Reduces race conditions in concurrent editing
- Fine-grained control over modifications
Breaking Changes
None - All changes are additive or enhance existing functionality with backward compatibility.
Implementation
Files Created:
src/utils/version-utils.ts- ETag/version control utilities
Files Modified:
src/tools/note-tools.ts- Added new methods and enhanced existing onessrc/utils/frontmatter-utils.ts- Added serializeFrontmatter methodsrc/tools/index.ts- Added new tool definitions and updated callToolsrc/types/mcp-types.ts- Added Phase 8 type definitions
Benefits
- Concurrency safety - Prevents lost updates in concurrent editing scenarios
- Safer operations - Preview and recovery options for destructive operations
- Link integrity - Maintained vault link integrity during reorganization
- Fine-grained control - Update specific parts without full file overwrites
- Better UX - Clear error messages and conflict resolution strategies
- Production-ready - Robust error handling and validation
Notes
- Manual testing recommended before production use
- All write operations now support concurrency control via
ifMatch - Soft delete is the default for
delete_note(safer) - Rename/move operations automatically update all wikilinks by default
[6.0.0] - 2025-10-17
🚀 Phase 7: Waypoint Support
This release adds specialized tools for working with Waypoint plugin markers and implements edit protection for auto-generated content.
Added
New Tool: get_folder_waypoint
- Extract Waypoint block from a folder note
- Returns structured JSON with:
path- File pathhasWaypoint- Boolean indicating waypoint presencewaypointRange- Line range of waypoint block (start/end)links- Array of extracted wikilinks from waypoint contentrawContent- Raw waypoint content between markers
- Automatically parses
[[wikilinks]]from waypoint blocks - Use to inspect folder note navigation structures
New Tool: is_folder_note
- Check if a note is a folder note
- Returns structured JSON with:
path- File pathisFolderNote- Boolean resultreason- Detection method:basename_match,waypoint_marker,both, ornonefolderPath- Parent folder path
- Detects folder notes by:
- Basename matching parent folder name
- Presence of Waypoint markers
- Use to identify navigation/index notes in vault
New Utilities (src/utils/waypoint-utils.ts)
WaypointUtilsclass for waypoint operationsextractWaypointBlock()- Extract waypoint from content with line rangeshasWaypointMarker()- Quick check for waypoint presenceisFolderNote()- Detect folder notes by multiple criteriawouldAffectWaypoint()- Check if edit would modify waypoint block- Handles edge cases: unclosed waypoints, malformed markers, nested content
Type Definitions (src/types/mcp-types.ts)
FolderWaypointResult- Waypoint extraction resultFolderNoteResult- Folder note detection result
Waypoint Edit Protection
update_notenow validates edits against waypoint blocks- Prevents accidental modification of auto-generated content
- Returns clear error message with:
- Waypoint line range
- Troubleshooting tips
- Suggestion to use
get_folder_waypoint()for inspection
- Detects both content changes and waypoint removal
Improvements
- Smart detection - Multiple criteria for folder note identification
- Link extraction - Automatic wikilink parsing from waypoint content
- Edit safety - Prevents corruption of auto-generated navigation structures
- Clear errors - Actionable guidance when waypoint edits are blocked
- Flexible checking - Allows edits that don't affect waypoint content
Implementation
Files Modified:
src/utils/waypoint-utils.ts(new) - Core waypoint utilitiessrc/tools/vault-tools.ts- AddedgetFolderWaypoint()andisFolderNote()methodssrc/tools/note-tools.ts- Added waypoint edit protection toupdateNote()src/tools/index.ts- Registered new tools in tool registrysrc/types/mcp-types.ts- Added Phase 7 type definitions
Benefits
- Waypoint integration - First-class support for Waypoint plugin workflows
- Data integrity - Prevents accidental corruption of auto-generated content
- Better navigation - Tools to discover and inspect folder structures
- Developer-friendly - Clear APIs for working with folder notes
Notes
update_sectionstool (with waypoint protection) will be implemented in Phase 8- Manual testing recommended for various waypoint formats and edge cases
[5.0.0] - 2025-10-16
🚀 Phase 6: Powerful Search
This release introduces a completely redesigned search system with regex support, advanced filtering, and specialized waypoint search capabilities.
Added
New Tool: search
- Regex support - Full JavaScript regex pattern matching with
isRegexparameter - Case sensitivity control - Toggle case-sensitive search with
caseSensitiveparameter - Advanced filtering:
includes- Glob patterns to include specific files (e.g.,['*.md', 'projects/**'])excludes- Glob patterns to exclude files (e.g.,['.obsidian/**', '*.tmp'])folder- Limit search to specific folder path
- Snippet extraction - Configurable context snippets with
snippetLengthparameter - Result limiting - Control maximum results with
maxResultsparameter (default: 100) - Snippet control - Toggle snippet extraction with
returnSnippetsparameter - Returns enhanced
SearchResultwith:query- Search query stringisRegex- Boolean indicating regex modematches- Array ofSearchMatchobjects with line, column, snippet, and match rangestotalMatches- Total number of matches foundfilesSearched- Number of files searchedfilesWithMatches- Number of files containing matches
New Tool: search_waypoints
- Specialized tool for finding Waypoint plugin markers
- Searches for
%% Begin Waypoint %%...%% End Waypoint %%blocks - Wikilink extraction - Automatically extracts
[[wikilinks]]from waypoint content - Folder scoping - Optional
folderparameter to limit search scope - Returns structured
WaypointSearchResultwith:waypoints- Array of waypoint locations with content and linkstotalWaypoints- Total number of waypoints foundfilesSearched- Number of files searched
New Utilities (src/utils/search-utils.ts)
SearchUtilsclass for advanced search operationssearch()- Main search method with regex, filtering, and snippet extractionsearchInFile()- Search within single file with match highlightingsearchInFilename()- Search in file basenamessearchWaypoints()- Specialized waypoint marker search- Handles edge cases: zero-width regex matches, invalid patterns, large files
Type Definitions (src/types/mcp-types.ts)
- Updated
SearchResult- AddedisRegexfield WaypointResult- Individual waypoint location with content and linksWaypointSearchResult- Waypoint search results with statistics
Implementation (src/tools/vault-tools.ts)
- New
search()method with full parameter support - New
searchWaypoints()method for waypoint discovery - Updated
searchNotes()to includeisRegex: falsein results
Tool Registry (src/tools/index.ts)
- Registered
searchtool with comprehensive schema - Registered
search_waypointstool - Marked
search_notesas DEPRECATED (kept for backward compatibility) - Updated callTool to handle new search tools
Improvements
- Regex power - Full JavaScript regex syntax support with global flag for multiple matches per line
- Smart snippet extraction - Centers matches in snippets with configurable length
- Consistent filtering - Uses existing GlobUtils for glob pattern matching
- Filename search - Searches both content and filenames automatically
- Error handling - Clear error messages for invalid regex patterns
- Performance - Efficient search with early termination when maxResults reached
Breaking Changes
search_notestool removed - Replaced by enhancedsearchtool- Old tool completely removed (no backward compatibility)
- Use
searchtool withisRegex: falsefor equivalent literal search - Migration: Replace
search_notescalls withsearchtool
Benefits
- Powerful queries - Use regex for complex search patterns (e.g.,
^# Heading,TODO.*urgent) - Precise control - Fine-tune search with case sensitivity and glob filtering
- Better results - Context snippets with match highlighting for easier review
- Waypoint discovery - Find all folder notes and navigation structures
- Cleaner API - Single powerful search tool instead of multiple limited ones
[4.0.0] - 2025-10-16
🚀 Phase 5: Advanced Read Operations
This release adds frontmatter parsing capabilities to read_note and introduces specialized support for Excalidraw files. All features have been manually tested and refined based on user feedback.
Added
Enhanced Tool: read_note
- Frontmatter parsing - New
parseFrontmatteroption to separate frontmatter from content - Structured response - Returns
ParsedNoteobject with parsed YAML frontmatter - Flexible options:
withFrontmatter(default: true) - Include frontmatter in responsewithContent(default: true) - Include full content in responseparseFrontmatter(default: false) - Parse and structure frontmatter
- Backward compatible - Default behavior unchanged (returns raw content)
- Returns structured JSON when
parseFrontmatter: truewith:path- File pathhasFrontmatter- Boolean indicating presencefrontmatter- Raw YAML stringparsedFrontmatter- Parsed YAML objectcontent- Full file contentcontentWithoutFrontmatter- Content excluding frontmatter
New Tool: read_excalidraw
- Specialized tool for reading Excalidraw drawing files
- Metadata extraction - Element count, compressed data status
- Preview text - Extract text elements without parsing full drawing
- Optional compressed data - Include full drawing data with
includeCompressed: true - Returns structured
ExcalidrawMetadatawith:path- File pathisExcalidraw- Validation booleanelementCount- Number of drawing elementshasCompressedData- Boolean for compressed filesmetadata- Drawing metadata (appState, version)preview- Text elements preview (optional)compressedData- Full drawing data (optional)
New Utilities (src/utils/frontmatter-utils.ts)
FrontmatterUtilsclass for YAML parsingextractFrontmatter()- Extract and parse YAML frontmatter using Obsidian's parseYamlextractFrontmatterSummary()- Extract common fields (title, tags, aliases)hasFrontmatter()- Quick check for frontmatter presenceparseExcalidrawMetadata()- Parse Excalidraw file structure- Handles edge cases: no frontmatter, malformed YAML, invalid Excalidraw files
Type Definitions (src/types/mcp-types.ts)
ParsedNote- Structured note with separated frontmatterExcalidrawMetadata- Excalidraw file metadata structure
Implementation (src/tools/note-tools.ts)
- Enhanced
readNote()method with options parameter - New
readExcalidraw()method for Excalidraw files - Integrated frontmatter parsing with FrontmatterUtils
- Maintains backward compatibility for existing clients
Tool Registry (src/tools/index.ts)
- Updated
read_noteschema with new optional parameters - Registered
read_excalidrawtool with comprehensive schema - Updated callTool to pass options to readNote and handle read_excalidraw
Improvements (Post-Testing)
- Enhanced error handling - Graceful handling of non-Excalidraw files with structured responses
- Comprehensive documentation - Detailed field descriptions in tool schema with explicit categorization
- Full metadata exposure - All Excalidraw metadata fields properly exposed per spec:
elementCount- Number of drawing elements (always returned)hasCompressedData- Boolean for embedded images (always returned)metadata- Object with appState and version (always returned)preview- Text elements (conditional on includePreview)compressedData- Full drawing data (conditional on includeCompressed)
- Enhanced type definitions - JSDoc comments on all ExcalidrawMetadata fields
- Complete specification - New EXCALIDRAW_METADATA_SPEC.md with comprehensive documentation
Bug Fixes (Post-Testing)
- Fixed missing metadata fields - Resolved issue where
elementCount,hasCompressedData, andmetadatawere not returned- Added support for
compressed-jsoncode fence format (Excalidraw's actual format) - Detects compressed (base64) vs uncompressed JSON data
- For compressed files: Returns
hasCompressedData: trueandmetadata.compressed: true - For uncompressed files: Extracts actual element count and metadata
- Multiple regex patterns to handle different Excalidraw formats
- Always return metadata fields with appropriate values
- Added support for
- Known Limitation:
elementCountreturns 0 for compressed files- Most Excalidraw files use compressed base64 format by default
- Decompression would require pako library (not included to minimize dependencies)
- Text elements are still extracted in
previewfield - Use
hasCompressedData: trueto identify compressed files - This is expected behavior, not a bug
Benefits
- Better frontmatter handling - Separate frontmatter from content for easier processing
- Excalidraw support - First-class support for Excalidraw drawings with complete metadata
- Flexible reading - Choose what data to include in responses
- Backward compatible - Existing code continues to work unchanged
- Type-safe - Structured responses with proper TypeScript types
- Robust - Graceful error handling for edge cases
[3.0.0] - 2025-10-16
🚀 Phase 4: Enhanced List Operations
This release replaces list_notes with a powerful new list tool featuring advanced filtering, recursion, pagination, and frontmatter summaries.
Breaking Changes
Removed Tools
list_notes- Replaced with the more powerfullisttool- Migration: Replace
list_notes({ path })withlist({ path }) - The new
listtool is backwards compatible for basic usage
- Migration: Replace
Added
New Tool: list
- Advanced file/directory listing with comprehensive filtering options
- Recursive listing - Traverse entire directory trees with
recursive: true - Glob pattern filtering - Include/exclude patterns supporting
*,**,?,[abc],{a,b} - Type filtering - Filter by
files,directories, orany - Cursor-based pagination - Handle large result sets efficiently with
limitandcursor - Frontmatter summaries - Extract title, tags, aliases without reading full content
- Returns structured
ListResultwith items, totalCount, hasMore, and nextCursor
New Utilities (src/utils/glob-utils.ts)
GlobUtilsclass for pattern matching- Supports wildcards:
*(any chars except /),**(any chars including /),?(single char) - Supports character classes:
[abc], alternatives:{a,b,c} shouldInclude()- Combined include/exclude filteringmatches()- Test path against glob pattern
Type Definitions (src/types/mcp-types.ts)
FrontmatterSummary- Parsed frontmatter fields (title, tags, aliases, custom fields)FileMetadataWithFrontmatter- Extended file metadata with optional frontmatterListResult- Paginated list response structure
Implementation (src/tools/vault-tools.ts)
list(options)method - Enhanced listing with all Phase 4 featurescreateFileMetadataWithFrontmatter()- Efficient frontmatter extraction using metadata cache- Recursive directory traversal
- Glob pattern filtering integration
- Cursor-based pagination logic
Tool Registry (src/tools/index.ts)
- Registered
listtool with comprehensive schema - Removed
list_notestool definition - Updated call handler to route
listrequests
Features in Detail
Recursive Listing
// List all markdown files in vault recursively
list({ recursive: true, includes: ["*.md"] })
Glob Filtering
// Include only markdown files, exclude .obsidian folder
list({
includes: ["*.md"],
excludes: [".obsidian/**"]
})
Type Filtering
// List only directories
list({ only: "directories" })
Pagination
// First page
list({ limit: 50 })
// Next page using cursor
list({ limit: 50, cursor: "path/from/previous/response" })
Frontmatter Summaries
// Get file list with frontmatter metadata
list({
withFrontmatterSummary: true,
includes: ["*.md"]
})
Example Response
{
"items": [
{
"kind": "directory",
"name": "projects",
"path": "projects",
"childrenCount": 15,
"modified": 1697500800000
},
{
"kind": "file",
"name": "README.md",
"path": "README.md",
"extension": "md",
"size": 2048,
"modified": 1697500800000,
"created": 1697400000000,
"frontmatterSummary": {
"title": "Project Overview",
"tags": ["documentation", "readme"],
"aliases": ["index"]
}
}
],
"totalCount": 2,
"hasMore": false
}
Performance
- Frontmatter extraction uses Obsidian's metadata cache (no file reads)
- Glob matching uses efficient regex compilation
- Pagination prevents memory issues with large vaults
- Recursive listing optimized for vault structure
[2.1.0] - 2025-10-16
✨ Phase 3: Discovery Endpoints
This release adds new tools for exploring vault structure and testing path validity.
Added
New Tools
stat- Get detailed metadata for a file or folder at a specific path- Returns existence status, kind (file/directory), and full metadata
- Includes size, dates, child count, etc.
- More detailed than
exists()but slightly slower
exists- Quickly check if a file or folder exists- Fast path validation without fetching full metadata
- Returns existence status and kind only
- Optimized for quick existence checks
Type Definitions (src/types/mcp-types.ts)
StatResult- Structured result for stat operations (path, exists, kind, metadata)ExistsResult- Structured result for exists operations (path, exists, kind)
Implementation (src/tools/vault-tools.ts)
stat(path)method - Comprehensive path metadata retrievalexists(path)method - Fast existence checking- Both methods use PathUtils for consistent path normalization
- Both methods validate paths and return structured JSON
Tool Registry (src/tools/index.ts)
- Registered
statandexiststools with complete schemas - Added call handlers for both new tools
- Comprehensive descriptions for AI agent usage
Use Cases
stat Tool:
- Verify a path exists before operations
- Get detailed file/folder information
- Check file sizes and modification dates
- Determine if a path is a file or directory
exists Tool:
- Quick existence checks before create operations
- Validate paths in batch operations
- Fast pre-flight checks
- Minimal overhead for simple validation
Example Responses
stat (file exists):
{
"path": "folder/note.md",
"exists": true,
"kind": "file",
"metadata": {
"kind": "file",
"name": "note.md",
"path": "folder/note.md",
"extension": "md",
"size": 1234,
"modified": 1697500800000,
"created": 1697400000000
}
}
exists (folder exists):
{
"path": "projects",
"exists": true,
"kind": "directory"
}
stat (path doesn't exist):
{
"path": "missing/file.md",
"exists": false
}
[2.0.0] - 2025-10-16
🔧 Phase 2.1: Post-Testing Fixes
Based on testing feedback, the following improvements were made to the Phase 2 implementation:
Fixed
Root Listing Semantics (src/tools/vault-tools.ts)
- Clarified root path handling:
undefined,""(empty string), or"."all represent the vault root - Root listing now correctly returns direct children only (excludes vault root itself)
- Added explicit check to skip vault root folder (path === '')
- Improved code clarity with explicit
isRootPathcheck
Alphabetical Sorting
- Fixed sorting to be case-insensitive for stable, consistent ordering
- Directories are sorted alphabetically (case-insensitive), then files alphabetically (case-insensitive)
- Ensures predictable order for names like "CTP Lancaster" and "Construction Game"
Directory Metadata
- Added logic to populate
modifiedtimestamp from filesystem if available - Falls back to
0when filesystem metadata is not available (which is typical for directories) - Added documentation explaining when
modifiedmay be0 - Note: Obsidian's TFolder API doesn't include
statproperty, so directories will typically showmodified: 0
Documentation (src/tools/index.ts)
- Updated
list_notesdescription to document root path options (""or".") - Added explicit warning that leading slashes (e.g.,
"/"or"/folder") are invalid - Clarified that sorting is case-insensitive within each group
- Added note that only direct children are returned (non-recursive)
Technical Details
Root Path Handling:
// All of these list the vault root:
list_notes() // undefined
list_notes({ path: "" }) // empty string
list_notes({ path: "." }) // dot
Invalid Paths:
// These will error:
list_notes({ path: "/" }) // leading slash
list_notes({ path: "/folder" }) // leading slash
🔄 Phase 2: API Unification & Typed Results (BREAKING CHANGES)
This release introduces structured, typed responses for all tools and unifies parameter naming. Note: This is a breaking change as backwards compatibility is not maintained.
Added
Typed Result Interfaces (src/types/mcp-types.ts)
FileMetadata- Structured file information (kind, name, path, extension, size, modified, created)DirectoryMetadata- Structured directory information (kind, name, path, childrenCount, modified)VaultInfo- Structured vault information (name, path, totalFiles, totalFolders, markdownFiles, totalSize)SearchMatch- Detailed search match information (path, line, column, snippet, matchRanges)SearchResult- Comprehensive search results (query, matches, totalMatches, filesSearched, filesWithMatches)ItemKind- Type union for "file" | "directory"
Enhanced Tool Responses
- All tools now return structured JSON instead of plain text
- Consistent response format across all operations
- Machine-readable data for better integration
Changed
list_notes Tool (BREAKING)
- Parameter:
folder→path(breaking change -folderparameter removed) - Response: Now returns array of
FileMetadataandDirectoryMetadataobjects - Behavior: Lists direct children only (non-recursive)
- Includes both files AND directories (not just markdown files)
- Sorted: directories first, then files, alphabetically
- Each item includes detailed metadata (size, dates, child count)
search_notes Tool (BREAKING)
- Response: Now returns structured
SearchResultobject - Includes line numbers, column positions, and context snippets
- Provides match ranges for highlighting
- Tracks files searched and files with matches
- Filename matches indicated with line: 0
get_vault_info Tool (BREAKING)
- Response: Now returns structured
VaultInfoobject - Added:
totalFolderscount - Added:
totalSizein bytes - Renamed:
rootPath→path
Tool Descriptions
- Updated all tool descriptions to reflect structured JSON responses
- Clarified return value formats
- Removed deprecated
folderparameter
Implementation Details
src/tools/vault-tools.ts
searchNotes()- Complete rewrite with line-by-line search and snippet extractiongetVaultInfo()- Added folder counting and size calculationlistNotes()- Rewritten to return structured metadata for files and directories- Added
createFileMetadata()helper method - Added
createDirectoryMetadata()helper method
src/tools/index.ts
- Updated tool schemas to use
pathparameter only - Updated tool descriptions to document structured responses
- Modified
callTool()to passpathparameter
Migration Guide
Before (v1.x):
// list_notes returned plain text
"Found 3 notes:\nfile1.md\nfile2.md\nfile3.md"
// search_notes returned plain text
"Found 2 notes:\npath/to/note1.md\npath/to/note2.md"
// get_vault_info returned simple object
{ "name": "MyVault", "totalFiles": 100, "markdownFiles": 80, "rootPath": "/path" }
After (v2.x):
// list_notes returns structured array
[
{ "kind": "directory", "name": "folder1", "path": "folder1", "childrenCount": 5, "modified": 0 },
{ "kind": "file", "name": "note.md", "path": "note.md", "extension": "md", "size": 1024, "modified": 1697472000000, "created": 1697472000000 }
]
// search_notes returns detailed matches
{
"query": "TODO",
"matches": [
{ "path": "note.md", "line": 5, "column": 10, "snippet": "...context around TODO item...", "matchRanges": [{ "start": 15, "end": 19 }] }
],
"totalMatches": 1,
"filesSearched": 100,
"filesWithMatches": 1
}
// get_vault_info returns comprehensive info
{ "name": "MyVault", "path": "/path", "totalFiles": 100, "totalFolders": 20, "markdownFiles": 80, "totalSize": 5242880 }
Benefits
- Machine-readable: Structured JSON for easy parsing and integration
- Detailed metadata: Rich information for each file and directory
- Search precision: Line numbers, columns, and snippets for exact match location
- Consistency: Unified response format across all tools
- Type safety: Well-defined TypeScript interfaces
[1.2.0] - 2025-10-16
📁 Enhanced Parent Folder Detection (Phase 1.5)
Improved create_note tool with explicit parent folder validation and optional automatic folder creation.
Added
Parent Folder Validation (src/tools/note-tools.ts)
- Explicit parent folder detection before file creation (fail-fast)
- New
createParentsparameter for automatic folder creation - Recursive parent folder creation for deeply nested paths
- Validates parent is a folder (not a file)
- Clear error messages with actionable guidance
Tool Schema Updates (src/tools/index.ts)
- Added
createParentsboolean parameter tocreate_notetool - Default:
false(safe behavior - requires parent folders to exist) - Optional:
true(convenience - auto-creates missing parent folders) - Updated tool description with usage examples
Enhanced Error Messages (src/utils/error-messages.ts)
parentFolderNotFound()now suggests usingcreateParents: true- Provides example usage with auto-creation
- Computes grandparent path for better
list_notes()suggestions - Clear troubleshooting steps for missing parent folders
Comprehensive Test Suite (tests/parent-folder-detection.test.ts)
- 15 test cases covering all scenarios
- Tests explicit parent folder detection
- Tests recursive folder creation
- Tests error handling and edge cases
- Validates error message content
Changed
createNote()signature: added optionalcreateParentsparameter- Parent folder validation now happens before file creation attempt
- Error messages include
createParentsusage examples
Benefits
- Fail-fast behavior: Errors detected before attempting file creation
- Flexibility: Optional auto-creation with
createParents: true - Robustness: Handles deeply nested paths and all edge cases
- Backward compatible: Existing code continues to work (default:
false)
🔐 Enhanced Authentication & Security (Phase 1.5)
This update significantly improves authentication security and user experience with automatic key generation and enhanced UI.
Added
Automatic API Key Generation (src/utils/auth-utils.ts)
generateApiKey()- Cryptographically secure random key generation (32 characters)validateApiKey()- API key validation with strength requirements- Uses
crypto.getRandomValues()for secure randomness - Alphanumeric + special characters (
-,_) for URL-safe keys
Enhanced Settings UI (src/settings.ts)
- Auto-generate API key when authentication is enabled
- Copy to clipboard button for API key
- Regenerate key button with instant refresh
- Static, selectable API key display (full width)
- MCP client configuration snippet generator
- Dynamically includes/excludes Authorization header based on auth status
- Correct
mcpServersformat withserverUrlfield - Copy configuration button for one-click copying
- Partially selectable text for easy copying
- Restart warnings when authentication settings change
- Selectable connection information URLs
Security Improvements (src/server/middleware.ts)
- Defensive authentication check: rejects requests if auth enabled but no key set
- Improved error messages for authentication failures
- Fail-secure design: blocks access when misconfigured
Server Validation (src/main.ts)
- Prevents server start if authentication enabled without API key
- Clear error message guiding users to fix configuration
- Validation runs before server initialization
Changed
- API key field changed from user-editable to auto-generated display
- Configuration snippet now shows for both authenticated and non-authenticated setups
- Connection information URLs are now selectable
Security
- Fixed vulnerability where enabling authentication without API key allowed unrestricted access
- Three-layer defense: UI validation, server start validation, and middleware enforcement
- API keys are now always cryptographically secure (no weak user-chosen keys)
[1.1.0] - 2025-10-16
🎯 Phase 1.1: Path Normalization & Error Handling
This release focuses on robustness, cross-platform compatibility, and significantly improved error messages.
Added
Path Utilities (src/utils/path-utils.ts)
PathUtils.normalizePath()- Cross-platform path normalization (Windows/macOS/Linux)PathUtils.isValidVaultPath()- Path validation with security checksPathUtils.resolveFile()/resolveFolder()- Type-safe path resolutionPathUtils.fileExists()/folderExists()- Existence checkingPathUtils.getPathType()- Determine if path is file or folderPathUtils.ensureMarkdownExtension()- Auto-add .md extensionPathUtils.getParentPath()/getBasename()- Path manipulationPathUtils.joinPath()- Safe path joining- Handles backslashes, drive letters, trailing slashes automatically
- Prevents directory traversal attacks (
..paths)
Enhanced Error Messages (src/utils/error-messages.ts)
- Context-aware error messages with troubleshooting tips
- Dynamic
list_notes()suggestions based on path context - Operation-specific guidance (read, create, update, delete)
- Clear examples of correct path formats
- Platform-specific notes (case sensitivity on macOS/Linux)
ErrorMessages.fileNotFound()- File not found with discovery tipsErrorMessages.folderNotFound()- Folder not found with navigation tipsErrorMessages.invalidPath()- Invalid path with format examplesErrorMessages.pathAlreadyExists()- Conflict resolution guidanceErrorMessages.parentFolderNotFound()- Parent folder missing with verification stepsErrorMessages.cannotDeleteFolder()- Folder deletion attempt with alternativesErrorMessages.notAFile()/notAFolder()- Type mismatch errorsErrorMessages.operationFailed()- Generic operation failures
Testing Infrastructure
- Jest testing framework configured
- 43 unit tests for PathUtils (all passing)
- Mock Obsidian API for testing (
tests/__mocks__/obsidian.ts) - Test coverage for cross-platform path handling
- Integration tests with mock App/Vault
npm test/npm run test:watch/npm run test:coveragescripts
Documentation
docs/TOOL_SELECTION_GUIDE.md- Comprehensive 400+ line guide- Decision table for tool selection
- Path format guidelines (correct vs incorrect)
- Common scenarios with step-by-step examples
- Troubleshooting decision tree
- Best practices checklist
- Quick reference card
docs/ERROR_MESSAGE_IMPROVEMENTS.md- Error message enhancement documentationdocs/TOOL_DESCRIPTION_IMPROVEMENTS.md- AI agent tool description improvementstests/README.md- Testing setup and guidelinesPHASE_1.1_IMPLEMENTATION.md- Complete implementation summary
Changed
All Tool Implementations Enhanced
readNote()- Path validation, better error messages, folder detectioncreateNote()- Path normalization, conflict detection, parent folder validationupdateNote()- Enhanced validation, clearer error messagesdeleteNote()- Folder detection with specific error messagelistNotes()- Path validation, folder verification, better errors
Tool Descriptions for AI Agents
- All 7 MCP tool descriptions significantly enhanced
- Critical constraints stated upfront (e.g., "only files, NOT folders")
- Workflow guidance (e.g., "use list_notes() first if unsure")
- Path requirements clearly documented in every parameter
- Multiple concrete examples per tool
- Failure modes explicitly stated
- Self-documenting for AI agents without external docs
Error Message Consistency
- All errors now include vault-relative path reminders
- Case sensitivity noted for macOS/Linux
- Context-specific
list_notes()commands - Operation-appropriate tool suggestions
- Consistent formatting across all tools
Fixed
- Cross-platform paths - Windows backslashes now handled correctly
- Path validation - Prevents invalid characters and directory traversal
- Delete folder error - Now clearly states "cannot delete folders" instead of confusing message
- Parent folder detection - Clear message when parent folder missing during create
- Error message contradictions - All error headers and bodies now consistent
Technical Details
New Dependencies
- jest: ^29.x (dev)
- @types/jest: ^29.x (dev)
- ts-jest: ^29.x (dev)
Test Coverage
- 43 unit tests passing
- PathUtils: 100% coverage
- Cross-platform scenarios tested
- Mock Obsidian API for isolated testing
Build
- All TypeScript compilation successful
- No breaking changes to existing APIs
- Backward compatible with v1.0.0
Developer Experience
- Centralized path handling logic
- Type-safe path operations
- Comprehensive test suite
- Clear error messages reduce support burden
- Self-documenting code
[1.0.0] - 2025-10-16
🎉 Initial Release
Added
Core Features
- MCP (Model Context Protocol) server implementation
- HTTP transport with Express.js
- JSON-RPC 2.0 message handling
- Protocol version 2024-11-05 support
MCP Tools
read_note- Read note content from vaultcreate_note- Create new notesupdate_note- Update existing notesdelete_note- Delete notessearch_notes- Search notes by content or filenamelist_notes- List all notes or notes in specific folderget_vault_info- Get vault metadata and statistics
Server Features
- Configurable HTTP server (default port: 3000)
- Localhost-only binding (127.0.0.1)
- Health check endpoint (
/health) - MCP endpoint (
/mcp) - Auto-start option
Security
- Origin header validation (DNS rebinding protection)
- Optional Bearer token authentication
- CORS configuration with allowed origins
- Request validation and error handling
User Interface
- Settings panel with full configuration
- Status bar indicator showing server state
- Ribbon icon for quick server toggle
- Start/Stop/Restart commands
- Real-time server status display
- Connection information display
Documentation
- Comprehensive README with examples
- Quick Start Guide
- Implementation Summary
- Test client script
- Example MCP requests
- Security considerations
Developer Tools
- TypeScript implementation
- esbuild bundler
- Test client for validation
- Health check endpoint
Technical Details
Dependencies
- express: ^4.18.2
- cors: ^2.8.5
- obsidian: latest
Build
- TypeScript 4.7.4
- esbuild 0.17.3
- Output: 828KB bundled
Compatibility
- Obsidian minimum version: 0.15.0
- Desktop only (requires Node.js HTTP server)
- Protocol: MCP 2024-11-05
Known Limitations
- Desktop only (not available on mobile)
- Single vault per server instance
- No WebSocket support (HTTP only)
- No SSL/TLS (localhost only)
Future Roadmap
See ROADMAP.md for detailed implementation plans.
Phase 1: Foundation (P0-P1)
- Path Normalization - Consistent path handling across platforms
- Error Message Improvements - Clear, actionable error messages with troubleshooting tips
- Enhanced Authentication - Secure API key management, multiple keys with labels, expiration, rate limiting, audit logging, and permission scopes
- API Unification - Standardize parameter naming and return structured, typed results
- Discovery Endpoints - Add
statandexiststools for exploring vault structure
Phase 2: Enhanced Operations (P1-P2)
- Write Operations & Concurrency - ETag-based version control, partial updates (frontmatter, sections)
- Conflict Resolution - Create notes with conflict strategies (error, overwrite, rename)
- File Rename/Move - Rename or move files with automatic wikilink updates
- Enhanced List Operations - Filtering, recursion control, pagination, frontmatter summaries
- Advanced Search - Regex search, snippet extraction, glob filtering
Phase 3: Advanced Features (P2-P3)
- Frontmatter Parsing - Read and update frontmatter without modifying content
- Linking & Backlinks - Wikilink validation, resolution, and backlink queries
- Waypoint Support - Tools for working with Waypoint plugin markers
- Excalidraw Support - Specialized tool for reading Excalidraw drawings
Future Considerations
- Resources API - Expose notes as MCP resources
- Prompts API - Templated prompts for common operations
- Batch Operations - Multiple operations in single request
- WebSocket Transport - Real-time updates and notifications
- Graph API - Enhanced graph visualization and traversal
- Tag & Canvas APIs - Query tags and manipulate canvas files
- Dataview Integration - Query vault using Dataview syntax
- Performance Enhancements - Indexing, caching, streaming for large vaults
Version History
| Version | Date | Notes |
|---|---|---|
| 1.1.0 | 2025-10-16 | Phase 1.1: Path normalization, enhanced error messages, testing infrastructure |
| 1.0.0 | 2025-10-16 | Initial release |
Upgrade Guide
From 1.0.0 to 1.1.0
This is a backward-compatible update. Simply update the plugin:
- Backup your settings (optional, but recommended)
- Update the plugin files
- Restart Obsidian or reload the plugin
What's New:
- Better error messages with troubleshooting tips
- Improved cross-platform path handling
- Enhanced tool descriptions for AI agents
- No configuration changes required
Breaking Changes: None - fully backward compatible
From Development to 1.0.0
If you were using a development version:
- Backup your settings
- Disable the plugin
- Delete the old plugin folder
- Install version 1.0.0
- Re-enable and reconfigure
Breaking Changes
None (initial release)
Support
For issues, questions, or contributions:
- Check the README.md for documentation
- Review QUICKSTART.md for setup help
- Check existing issues before creating new ones
- Include version number in bug reports
Credits
- MCP Protocol: https://modelcontextprotocol.io
- Obsidian API: https://github.com/obsidianmd/obsidian-api
- Built with TypeScript, Express.js, and ❤️