@mauricio.wolff/mcp-obsidian 0.6.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { readdir, stat, readFile, writeFile, unlink, mkdir, access } from 'node:
3
3
  import { constants } from 'node:fs';
4
4
  import { FrontmatterHandler } from './frontmatter.js';
5
5
  import { PathFilter } from './pathfilter.js';
6
+ import { generateObsidianUri } from './uri.js';
6
7
  export class FileSystemService {
7
8
  vaultPath;
8
9
  frontmatterHandler;
@@ -440,7 +441,10 @@ export class FileSystemService {
440
441
  throw new Error(`Access denied: ${path}`);
441
442
  }
442
443
  const note = await this.readNote(path);
443
- const result = { path };
444
+ const result = {
445
+ path,
446
+ obsidianUri: generateObsidianUri(this.vaultPath, path)
447
+ };
444
448
  if (includeFrontmatter) {
445
449
  result.frontmatter = note.frontmatter;
446
450
  }
@@ -510,7 +514,8 @@ export class FileSystemService {
510
514
  path,
511
515
  size,
512
516
  modified: lastModified,
513
- hasFrontmatter
517
+ hasFrontmatter,
518
+ obsidianUri: generateObsidianUri(this.vaultPath, path)
514
519
  };
515
520
  }));
516
521
  // Return only successful results, filter out failed ones
@@ -1,5 +1,6 @@
1
1
  import { join } from 'path';
2
2
  import { readFile, readdir } from 'node:fs/promises';
3
+ import { generateObsidianUri } from './uri.js';
3
4
  export class SearchService {
4
5
  vaultPath;
5
6
  pathFilter;
@@ -70,7 +71,8 @@ export class SearchService {
70
71
  t: title,
71
72
  ex: excerpt,
72
73
  mc: matchCount,
73
- ln: lineNumber
74
+ ln: lineNumber,
75
+ uri: generateObsidianUri(this.vaultPath, relativePath)
74
76
  });
75
77
  }
76
78
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Generates an Obsidian URI for a given note path.
3
+ * Uses the absolute path format: obsidian:///absolute/path/to/note
4
+ *
5
+ * @param vaultPath - The absolute path to the vault root
6
+ * @param notePath - The relative path to the note within the vault
7
+ * @returns A properly encoded Obsidian URI
8
+ */
9
+ export function generateObsidianUri(vaultPath, notePath) {
10
+ // Remove leading slash from notePath if present
11
+ const cleanPath = notePath.startsWith('/') ? notePath.slice(1) : notePath;
12
+ // Construct absolute path
13
+ const absolutePath = `${vaultPath}/${cleanPath}`;
14
+ // Remove .md extension if present (Obsidian handles this automatically)
15
+ const pathWithoutExtension = absolutePath.replace(/\.md$/, '');
16
+ // URI encode the path, but keep slashes as slashes
17
+ const encodedPath = pathWithoutExtension
18
+ .split('/')
19
+ .map(segment => encodeURIComponent(segment))
20
+ .join('/');
21
+ return `obsidian:///${encodedPath}`;
22
+ }
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateObsidianUri } from './uri.js';
3
+ describe('generateObsidianUri', () => {
4
+ it('generates URI with absolute path', () => {
5
+ const vaultPath = '/Users/test/vault';
6
+ const notePath = 'folder/note.md';
7
+ const uri = generateObsidianUri(vaultPath, notePath);
8
+ expect(uri).toBe('obsidian:////Users/test/vault/folder/note');
9
+ });
10
+ it('handles paths with leading slash', () => {
11
+ const vaultPath = '/Users/test/vault';
12
+ const notePath = '/folder/note.md';
13
+ const uri = generateObsidianUri(vaultPath, notePath);
14
+ expect(uri).toBe('obsidian:////Users/test/vault/folder/note');
15
+ });
16
+ it('removes .md extension', () => {
17
+ const vaultPath = '/Users/test/vault';
18
+ const notePath = 'note.md';
19
+ const uri = generateObsidianUri(vaultPath, notePath);
20
+ expect(uri).toBe('obsidian:////Users/test/vault/note');
21
+ });
22
+ it('encodes special characters', () => {
23
+ const vaultPath = '/Users/test/vault';
24
+ const notePath = 'folder/my note with spaces.md';
25
+ const uri = generateObsidianUri(vaultPath, notePath);
26
+ expect(uri).toBe('obsidian:////Users/test/vault/folder/my%20note%20with%20spaces');
27
+ });
28
+ it('handles notes in root directory', () => {
29
+ const vaultPath = '/Users/test/vault';
30
+ const notePath = 'note.md';
31
+ const uri = generateObsidianUri(vaultPath, notePath);
32
+ expect(uri).toBe('obsidian:////Users/test/vault/note');
33
+ });
34
+ it('handles nested directories', () => {
35
+ const vaultPath = '/Users/test/vault';
36
+ const notePath = 'folder1/folder2/folder3/note.md';
37
+ const uri = generateObsidianUri(vaultPath, notePath);
38
+ expect(uri).toBe('obsidian:////Users/test/vault/folder1/folder2/folder3/note');
39
+ });
40
+ it('encodes special characters in directory names', () => {
41
+ const vaultPath = '/Users/test/vault';
42
+ const notePath = 'my folder/sub folder/note.md';
43
+ const uri = generateObsidianUri(vaultPath, notePath);
44
+ expect(uri).toBe('obsidian:////Users/test/vault/my%20folder/sub%20folder/note');
45
+ });
46
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauricio.wolff/mcp-obsidian",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "Universal AI bridge for Obsidian vaults - connect any MCP-compatible assistant",
5
5
  "author": "bitbonsai",
6
6
  "license": "MIT",