# 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`) **Notification Settings** - `Enable notifications` - Toggle notifications on/off - `Show 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 called - `toolName` - Name of the tool - `args` - Tool parameters - `success` - Whether the call succeeded - `duration` - Execution time in milliseconds - `error` - 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 limiting - `src/ui/notification-history.ts` - History modal for viewing past tool calls #### Files Modified - `src/types/settings-types.ts` - Added notification settings types - `src/settings.ts` - Added notification settings UI - `src/tools/index.ts` - Integrated notifications into tool call interceptor - `src/server/mcp-server.ts` - Added notification manager support - `src/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 path - `totalLinks` - Total number of links found - `resolvedLinks` - Array of resolved links with: - `text` - Full link text including brackets - `target` - Resolved target file path - `alias` - Display alias (if present) - `unresolvedLinks` - Array of unresolved links with: - `text` - Full link text including brackets - `line` - Line number where link appears - `suggestions` - 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 path - `linkText` - Link text to resolve (without brackets) - `resolved` - Boolean indicating if link was resolved - `targetPath` - Resolved target file path (if found) - `suggestions` - Array of suggested paths (if not found) - Parameters: - `sourcePath` - Path of note containing the link - `linkText` - 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 path - `backlinks` - Array of backlinks with: - `sourcePath` - Source file path containing the link - `type` - 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 path - `includeUnlinked` - 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: `includeUnlinked` can be slow for large vaults **New Utility: `link-utils.ts`** - `LinkUtils` class for wikilink operations - `parseWikilinks()` - Parse all wikilinks from content with positions - `resolveLink()` - Resolve a wikilink to its target file - `findSuggestions()` - Find potential matches for unresolved links - `getBacklinks()` - Get all backlinks to a file - `validateWikilinks()` - 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_wikilinks` tool definition - Added `resolve_wikilink` tool definition - Added `backlinks` tool definition - Added case handlers for three new tools **Updated: `mcp-types.ts`** - Added Phase 9 types: - `ResolvedLink` - Resolved wikilink information - `UnresolvedLink` - Unresolved wikilink information - `ValidateWikilinksResult` - Result from validate_wikilinks - `ResolveWikilinkResult` - Result from resolve_wikilink - `BacklinkOccurrence` - Backlink occurrence in a file - `BacklinkInfo` - Backlink from a source file - `BacklinksResult` - 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 `patch` parameter - Supports field removal via `remove` parameter (array of field names) - Returns structured JSON with: - `success` - Boolean operation status - `path` - File path - `versionId` - New version ID for subsequent operations - `modified` - Modification timestamp - `updatedFields` - Array of fields that were added/updated - `removedFields` - Array of fields that were removed - Includes concurrency control via optional `ifMatch` parameter - 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 status - `path` - File path - `versionId` - New version ID - `modified` - Modification timestamp - `sectionsUpdated` - 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 `ifMatch` parameter - 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 status - `oldPath` - Original file path - `newPath` - New file path - `linksUpdated` - 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 path - `newPath` - 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`** - `VersionUtils` class for ETag-based concurrency control - `generateVersionId()` - Create version ID from file mtime and size - `validateVersion()` - Check if provided version matches current - `versionMismatchError()` - Generate 412 Precondition Failed error - `createVersionedResponse()` - Add version info to responses - Uses SHA-256 hash with URL-safe base64 encoding **Enhanced Tool: `create_note`** - Added `onConflict` parameter with three strategies: - `error` (default) - Fail if file exists - `overwrite` - Delete existing file and create new - `rename` - Auto-generate unique name by appending number - Returns structured JSON with: - `success` - Boolean operation status - `path` - Created file path (may differ if renamed) - `versionId` - Version ID for subsequent operations - `created` - Creation timestamp - `renamed` - Boolean indicating if file was renamed - `originalPath` - Original path if renamed - Existing `createParents` parameter still supported - Better conflict handling and error messages **Enhanced Tool: `delete_note`** - Added `soft` parameter (default: true): - `true` - Move to `.trash` folder (recoverable) - `false` - Permanent deletion (cannot be undone) - Added `dryRun` parameter (default: false): - `true` - Preview deletion without executing - `false` - Perform actual deletion - Added `ifMatch` parameter for concurrency control - Returns structured JSON with: - `deleted` - Boolean indicating if deletion occurred - `path` - File path - `destination` - Trash destination (for soft deletes) - `dryRun` - Boolean indicating preview mode - `soft` - 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 strategies - `SectionEdit` - Interface for section edit operations - `UpdateFrontmatterResult` - Result from frontmatter updates - `UpdateSectionsResult` - Result from section updates - `CreateNoteResult` - Enhanced result from note creation - `RenameFileResult` - Result from file rename/move - `DeleteNoteResult` - 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 - `ifMatch` parameter prevents lost updates in concurrent scenarios - Version mismatch returns 412 Precondition Failed with clear error - All write operations return `versionId` for subsequent operations - Get `versionId` from 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 ones - `src/utils/frontmatter-utils.ts` - Added serializeFrontmatter method - `src/tools/index.ts` - Added new tool definitions and updated callTool - `src/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 path - `hasWaypoint` - Boolean indicating waypoint presence - `waypointRange` - Line range of waypoint block (start/end) - `links` - Array of extracted wikilinks from waypoint content - `rawContent` - 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 path - `isFolderNote` - Boolean result - `reason` - Detection method: `basename_match`, `waypoint_marker`, `both`, or `none` - `folderPath` - 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`)** - `WaypointUtils` class for waypoint operations - `extractWaypointBlock()` - Extract waypoint from content with line ranges - `hasWaypointMarker()` - Quick check for waypoint presence - `isFolderNote()` - Detect folder notes by multiple criteria - `wouldAffectWaypoint()` - 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 result - `FolderNoteResult` - Folder note detection result **Waypoint Edit Protection** - `update_note` now 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 utilities - `src/tools/vault-tools.ts` - Added `getFolderWaypoint()` and `isFolderNote()` methods - `src/tools/note-tools.ts` - Added waypoint edit protection to `updateNote()` - `src/tools/index.ts` - Registered new tools in tool registry - `src/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_sections` tool (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 `isRegex` parameter - **Case sensitivity control** - Toggle case-sensitive search with `caseSensitive` parameter - **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 `snippetLength` parameter - **Result limiting** - Control maximum results with `maxResults` parameter (default: 100) - **Snippet control** - Toggle snippet extraction with `returnSnippets` parameter - Returns enhanced `SearchResult` with: - `query` - Search query string - `isRegex` - Boolean indicating regex mode - `matches` - Array of `SearchMatch` objects with line, column, snippet, and match ranges - `totalMatches` - Total number of matches found - `filesSearched` - Number of files searched - `filesWithMatches` - 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 `folder` parameter to limit search scope - Returns structured `WaypointSearchResult` with: - `waypoints` - Array of waypoint locations with content and links - `totalWaypoints` - Total number of waypoints found - `filesSearched` - Number of files searched **New Utilities (`src/utils/search-utils.ts`)** - `SearchUtils` class for advanced search operations - `search()` - Main search method with regex, filtering, and snippet extraction - `searchInFile()` - Search within single file with match highlighting - `searchInFilename()` - Search in file basenames - `searchWaypoints()` - Specialized waypoint marker search - Handles edge cases: zero-width regex matches, invalid patterns, large files **Type Definitions (`src/types/mcp-types.ts`)** - Updated `SearchResult` - Added `isRegex` field - `WaypointResult` - Individual waypoint location with content and links - `WaypointSearchResult` - 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 include `isRegex: false` in results **Tool Registry (`src/tools/index.ts`)** - Registered `search` tool with comprehensive schema - Registered `search_waypoints` tool - Marked `search_notes` as 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_notes` tool removed** - Replaced by enhanced `search` tool - Old tool completely removed (no backward compatibility) - Use `search` tool with `isRegex: false` for equivalent literal search - Migration: Replace `search_notes` calls with `search` tool #### 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 `parseFrontmatter` option to separate frontmatter from content - **Structured response** - Returns `ParsedNote` object with parsed YAML frontmatter - **Flexible options**: - `withFrontmatter` (default: true) - Include frontmatter in response - `withContent` (default: true) - Include full content in response - `parseFrontmatter` (default: false) - Parse and structure frontmatter - **Backward compatible** - Default behavior unchanged (returns raw content) - Returns structured JSON when `parseFrontmatter: true` with: - `path` - File path - `hasFrontmatter` - Boolean indicating presence - `frontmatter` - Raw YAML string - `parsedFrontmatter` - Parsed YAML object - `content` - Full file content - `contentWithoutFrontmatter` - 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 `ExcalidrawMetadata` with: - `path` - File path - `isExcalidraw` - Validation boolean - `elementCount` - Number of drawing elements - `hasCompressedData` - Boolean for compressed files - `metadata` - Drawing metadata (appState, version) - `preview` - Text elements preview (optional) - `compressedData` - Full drawing data (optional) **New Utilities (`src/utils/frontmatter-utils.ts`)** - `FrontmatterUtils` class for YAML parsing - `extractFrontmatter()` - Extract and parse YAML frontmatter using Obsidian's parseYaml - `extractFrontmatterSummary()` - Extract common fields (title, tags, aliases) - `hasFrontmatter()` - Quick check for frontmatter presence - `parseExcalidrawMetadata()` - 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 frontmatter - `ExcalidrawMetadata` - 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_note` schema with new optional parameters - Registered `read_excalidraw` tool 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`, and `metadata` were not returned - Added support for `compressed-json` code fence format (Excalidraw's actual format) - Detects compressed (base64) vs uncompressed JSON data - For compressed files: Returns `hasCompressedData: true` and `metadata.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 - **Known Limitation:** `elementCount` returns 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 `preview` field - Use `hasCompressedData: true` to 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 powerful `list` tool - **Migration:** Replace `list_notes({ path })` with `list({ path })` - The new `list` tool is backwards compatible for basic usage #### 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`, or `any` - **Cursor-based pagination** - Handle large result sets efficiently with `limit` and `cursor` - **Frontmatter summaries** - Extract title, tags, aliases without reading full content - Returns structured `ListResult` with items, totalCount, hasMore, and nextCursor **New Utilities (`src/utils/glob-utils.ts`)** - `GlobUtils` class 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 filtering - `matches()` - 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 frontmatter - `ListResult` - Paginated list response structure **Implementation (`src/tools/vault-tools.ts`)** - `list(options)` method - Enhanced listing with all Phase 4 features - `createFileMetadataWithFrontmatter()` - Efficient frontmatter extraction using metadata cache - Recursive directory traversal - Glob pattern filtering integration - Cursor-based pagination logic **Tool Registry (`src/tools/index.ts`)** - Registered `list` tool with comprehensive schema - Removed `list_notes` tool definition - Updated call handler to route `list` requests #### Features in Detail **Recursive Listing** ```typescript // List all markdown files in vault recursively list({ recursive: true, includes: ["*.md"] }) ``` **Glob Filtering** ```typescript // Include only markdown files, exclude .obsidian folder list({ includes: ["*.md"], excludes: [".obsidian/**"] }) ``` **Type Filtering** ```typescript // List only directories list({ only: "directories" }) ``` **Pagination** ```typescript // First page list({ limit: 50 }) // Next page using cursor list({ limit: 50, cursor: "path/from/previous/response" }) ``` **Frontmatter Summaries** ```typescript // Get file list with frontmatter metadata list({ withFrontmatterSummary: true, includes: ["*.md"] }) ``` #### Example Response ```json { "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 retrieval - `exists(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 `stat` and `exists` tools 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):** ```json { "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):** ```json { "path": "projects", "exists": true, "kind": "directory" } ``` **stat (path doesn't exist):** ```json { "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 `isRootPath` check **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 `modified` timestamp from filesystem if available - Falls back to `0` when filesystem metadata is not available (which is typical for directories) - Added documentation explaining when `modified` may be `0` - **Note:** Obsidian's TFolder API doesn't include `stat` property, so directories will typically show `modified: 0` **Documentation (`src/tools/index.ts`)** - Updated `list_notes` description 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:** ```typescript // All of these list the vault root: list_notes() // undefined list_notes({ path: "" }) // empty string list_notes({ path: "." }) // dot ``` **Invalid Paths:** ```typescript // 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 - `folder` parameter removed) - Response: Now returns array of `FileMetadata` and `DirectoryMetadata` objects - 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 `SearchResult` object - 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 `VaultInfo` object - Added: `totalFolders` count - Added: `totalSize` in bytes - Renamed: `rootPath` β†’ `path` **Tool Descriptions** - Updated all tool descriptions to reflect structured JSON responses - Clarified return value formats - Removed deprecated `folder` parameter #### Implementation Details **`src/tools/vault-tools.ts`** - `searchNotes()` - Complete rewrite with line-by-line search and snippet extraction - `getVaultInfo()` - Added folder counting and size calculation - `listNotes()` - 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 `path` parameter only - Updated tool descriptions to document structured responses - Modified `callTool()` to pass `path` parameter #### Migration Guide **Before (v1.x):** ```javascript // 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):** ```javascript // 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 `createParents` parameter 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 `createParents` boolean parameter to `create_note` tool - 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 using `createParents: 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 optional `createParents` parameter - Parent folder validation now happens before file creation attempt - Error messages include `createParents` usage 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 `mcpServers` format with `serverUrl` field - 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 checks - `PathUtils.resolveFile()` / `resolveFolder()` - Type-safe path resolution - `PathUtils.fileExists()` / `folderExists()` - Existence checking - `PathUtils.getPathType()` - Determine if path is file or folder - `PathUtils.ensureMarkdownExtension()` - Auto-add .md extension - `PathUtils.getParentPath()` / `getBasename()` - Path manipulation - `PathUtils.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 tips - `ErrorMessages.folderNotFound()` - Folder not found with navigation tips - `ErrorMessages.invalidPath()` - Invalid path with format examples - `ErrorMessages.pathAlreadyExists()` - Conflict resolution guidance - `ErrorMessages.parentFolderNotFound()` - Parent folder missing with verification steps - `ErrorMessages.cannotDeleteFolder()` - Folder deletion attempt with alternatives - `ErrorMessages.notAFile()` / `notAFolder()` - Type mismatch errors - `ErrorMessages.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:coverage` scripts **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 documentation - `docs/TOOL_DESCRIPTION_IMPROVEMENTS.md` - AI agent tool description improvements - `tests/README.md` - Testing setup and guidelines - `PHASE_1.1_IMPLEMENTATION.md` - Complete implementation summary #### Changed **All Tool Implementations Enhanced** - `readNote()` - Path validation, better error messages, folder detection - `createNote()` - Path normalization, conflict detection, parent folder validation - `updateNote()` - Enhanced validation, clearer error messages - `deleteNote()` - Folder detection with specific error message - `listNotes()` - 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 vault - `create_note` - Create new notes - `update_note` - Update existing notes - `delete_note` - Delete notes - `search_notes` - Search notes by content or filename - `list_notes` - List all notes or notes in specific folder - `get_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](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 `stat` and `exists` tools 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: 1. Backup your settings (optional, but recommended) 2. Update the plugin files 3. 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: 1. Backup your settings 2. Disable the plugin 3. Delete the old plugin folder 4. Install version 1.0.0 5. 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 ❀️