pkm-mcp-server 1.5.2 → 1.6.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.
- package/CHANGELOG.md +50 -2
- package/README.md +2 -2
- package/handlers.js +45 -47
- package/hooks/capture-handler.sh +17 -13
- package/index.js +1 -1
- package/init.js +23 -2
- package/package.json +2 -2
- package/sample-project/CLAUDE.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.6.0] - 2026-03-23
|
|
10
|
+
|
|
11
|
+
### Security
|
|
12
|
+
- **Fix command injection in capture-handler.sh** — replaced `eval` of Node.js output with safe per-variable stdout capture. Previously, crafted `title` or `content` values containing shell metacharacters (e.g., `$(...)`) could execute arbitrary commands.
|
|
13
|
+
- `handleTrash` and `handleMove` now catch ENOENT errors and return relative paths instead of leaking absolute vault paths in error messages
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Wikilink extraction in `handleLinks` and `handleSuggestLinks` now uses shared `extractWikilinks` from `graph.js` instead of duplicating the regex
|
|
17
|
+
- Extracted `addToBasenameMap`/`removeFromBasenameMap` helpers in `handlers.js` (replaces 3 inline copies)
|
|
18
|
+
- Named constant `SESSION_ID_DISPLAY_LEN` replaces magic number `8` for session ID truncation
|
|
19
|
+
- `@modelcontextprotocol/sdk` version range tightened from `^1.0.0` to `^1.27.0` to reflect actual minimum tested version
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- README hook configuration referenced deleted `stop-sweep.sh` (renamed to `stop-sweep.js` in v1.5.0)
|
|
23
|
+
- `vault_peek` tool description no longer claims "line numbers" in heading outline (removed in v1.1.0)
|
|
24
|
+
- CHANGELOG: added missing entries for v1.5.3, v1.5.2, v1.1.1; fixed all comparison links
|
|
25
|
+
- CLAUDE.md and sample-project/CLAUDE.md: added missing `note.md` template to template lists
|
|
26
|
+
- CONTRIBUTING.md: clarified that double quotes and semicolons are conventions, not lint-enforced
|
|
27
|
+
- CI workflow: added `permissions: {}` for least privilege; added `npm audit --omit=dev` step
|
|
28
|
+
|
|
29
|
+
## [1.5.3] - 2026-03-21
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- Init wizard `patchMcpConfig()` now handles multi-line `MCP_CONFIG=` blocks correctly — previously only replaced the first line, leaving orphaned continuation lines
|
|
33
|
+
|
|
34
|
+
## [1.5.2] - 2026-03-21
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- Hook scripts now auto-detect repo vs installed location — `capture-handler.sh` no longer hardcodes `node $SCRIPT_DIR/../index.js`, falling back to `npx pkm-mcp-server@latest` when `index.js` is not present
|
|
38
|
+
|
|
9
39
|
## [1.5.1] - 2026-03-21
|
|
10
40
|
|
|
11
41
|
### Fixed
|
|
@@ -109,6 +139,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
109
139
|
### Security
|
|
110
140
|
- Resolved 7 transitive dependency vulnerabilities (hono, @hono/node-server, ajv, express-rate-limit, flatted, minimatch, qs)
|
|
111
141
|
|
|
142
|
+
## [1.1.1] - 2026-02-24
|
|
143
|
+
|
|
144
|
+
### Added
|
|
145
|
+
- Enum validation for task `status` and `priority` fields in `vault_write` and `vault_update_frontmatter`
|
|
146
|
+
|
|
112
147
|
## [1.1.0] - 2026-02-23
|
|
113
148
|
|
|
114
149
|
### Changed
|
|
@@ -158,8 +193,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
158
193
|
- Atomic file creation in `vault_write` (`wx` flag) prevents race conditions
|
|
159
194
|
- Error messages sanitized to prevent leaking absolute vault paths
|
|
160
195
|
|
|
161
|
-
[Unreleased]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.
|
|
196
|
+
[Unreleased]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.6.0...HEAD
|
|
197
|
+
[1.6.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.5.3...v1.6.0
|
|
198
|
+
[1.5.3]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.5.2...v1.5.3
|
|
199
|
+
[1.5.2]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.5.1...v1.5.2
|
|
200
|
+
[1.5.1]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.5.0...v1.5.1
|
|
201
|
+
[1.5.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.4.2...v1.5.0
|
|
202
|
+
[1.4.2]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.4.1...v1.4.2
|
|
203
|
+
[1.4.1]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.4.0...v1.4.1
|
|
204
|
+
[1.4.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.3.3...v1.4.0
|
|
205
|
+
[1.3.3]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.3.2...v1.3.3
|
|
206
|
+
[1.3.2]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.3.1...v1.3.2
|
|
207
|
+
[1.3.1]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.3.0...v1.3.1
|
|
208
|
+
[1.3.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.2.1...v1.3.0
|
|
162
209
|
[1.2.1]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.2.0...v1.2.1
|
|
163
|
-
[1.2.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.1.
|
|
210
|
+
[1.2.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.1.1...v1.2.0
|
|
211
|
+
[1.1.1]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.1.0...v1.1.1
|
|
164
212
|
[1.1.0]: https://github.com/AdrianV101/Obsidian-MCP/compare/v1.0.0...v1.1.0
|
|
165
213
|
[1.0.0]: https://github.com/AdrianV101/Obsidian-MCP/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ Add to your `~/.claude/settings.json` (alongside the `mcpServers` block):
|
|
|
190
190
|
"hooks": [
|
|
191
191
|
{
|
|
192
192
|
"type": "command",
|
|
193
|
-
"command": "VAULT_PATH=\"/path/to/your/vault\" /path/to/Obsidian-MCP/hooks/stop-sweep.
|
|
193
|
+
"command": "VAULT_PATH=\"/path/to/your/vault\" node /path/to/Obsidian-MCP/hooks/stop-sweep.js",
|
|
194
194
|
"async": true,
|
|
195
195
|
"timeout": 10
|
|
196
196
|
}
|
|
@@ -219,7 +219,7 @@ Replace `/path/to/your/vault` with your Obsidian vault path and `/path/to/Obsidi
|
|
|
219
219
|
| Hook | Event | What it does |
|
|
220
220
|
|------|-------|--------------|
|
|
221
221
|
| `session-start.js` | SessionStart | Loads project context (index, devlog, active tasks) at session start |
|
|
222
|
-
| `stop-sweep.
|
|
222
|
+
| `stop-sweep.js` | Stop | PKM librarian: creates structured, graph-linked vault notes from the latest exchange |
|
|
223
223
|
| `capture-handler.sh` | PostToolUse | Creates structured vault notes when `vault_capture` is called |
|
|
224
224
|
|
|
225
225
|
See [hooks/README.md](hooks/README.md) for architecture details and troubleshooting.
|
package/handlers.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
FORCE_HARD_CAP,
|
|
24
24
|
CHUNK_SIZE,
|
|
25
25
|
} from "./helpers.js";
|
|
26
|
-
import { exploreNeighborhood, formatNeighborhood, findFilesLinkingTo, rewriteWikilinks } from "./graph.js";
|
|
26
|
+
import { exploreNeighborhood, formatNeighborhood, findFilesLinkingTo, rewriteWikilinks, extractWikilinks } from "./graph.js";
|
|
27
27
|
import { getAllMarkdownFiles, extractFrontmatter } from "./utils.js";
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -63,6 +63,26 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
63
63
|
return resolvePath(resolvedFolder);
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
const SESSION_ID_DISPLAY_LEN = 8;
|
|
67
|
+
|
|
68
|
+
function addToBasenameMap(relativePath) {
|
|
69
|
+
const bn = path.basename(relativePath, ".md").toLowerCase();
|
|
70
|
+
if (!basenameMap.has(bn)) basenameMap.set(bn, []);
|
|
71
|
+
basenameMap.get(bn).push(relativePath);
|
|
72
|
+
allFilesSet.add(relativePath);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function removeFromBasenameMap(relativePath) {
|
|
76
|
+
allFilesSet.delete(relativePath);
|
|
77
|
+
const bn = path.basename(relativePath, ".md").toLowerCase();
|
|
78
|
+
const entries = basenameMap.get(bn);
|
|
79
|
+
if (entries) {
|
|
80
|
+
const idx = entries.indexOf(relativePath);
|
|
81
|
+
if (idx !== -1) entries.splice(idx, 1);
|
|
82
|
+
if (entries.length === 0) basenameMap.delete(bn);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
66
86
|
async function handleRead(args) {
|
|
67
87
|
const filePath = resolveFile(args.path);
|
|
68
88
|
const content = await fs.readFile(filePath, "utf-8");
|
|
@@ -193,12 +213,7 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
193
213
|
}
|
|
194
214
|
|
|
195
215
|
// Update basename map with the new file
|
|
196
|
-
|
|
197
|
-
if (!basenameMap.has(newBasename)) {
|
|
198
|
-
basenameMap.set(newBasename, []);
|
|
199
|
-
}
|
|
200
|
-
basenameMap.get(newBasename).push(outputPath);
|
|
201
|
-
allFilesSet.add(outputPath);
|
|
216
|
+
addToBasenameMap(outputPath);
|
|
202
217
|
|
|
203
218
|
const fm = validation.frontmatter;
|
|
204
219
|
const createdStr = fm.created instanceof Date
|
|
@@ -403,11 +418,7 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
403
418
|
const result = { outgoing: [], incoming: [] };
|
|
404
419
|
|
|
405
420
|
if (args.direction !== "incoming") {
|
|
406
|
-
|
|
407
|
-
let match;
|
|
408
|
-
while ((match = linkRegex.exec(content)) !== null) {
|
|
409
|
-
result.outgoing.push(match[1]);
|
|
410
|
-
}
|
|
421
|
+
result.outgoing = extractWikilinks(content);
|
|
411
422
|
}
|
|
412
423
|
|
|
413
424
|
if (args.direction !== "outgoing") {
|
|
@@ -580,20 +591,20 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
580
591
|
|
|
581
592
|
if (entries.length === 0) {
|
|
582
593
|
return {
|
|
583
|
-
content: [{ type: "text", text: `No activity entries found. (current session: ${sessionId.slice(0,
|
|
594
|
+
content: [{ type: "text", text: `No activity entries found. (current session: ${sessionId.slice(0, SESSION_ID_DISPLAY_LEN)})` }]
|
|
584
595
|
};
|
|
585
596
|
}
|
|
586
597
|
|
|
587
598
|
const formatted = entries.map(e => {
|
|
588
599
|
const ts = e.timestamp.replace("T", " ").slice(0, 19);
|
|
589
|
-
const sessionShort = e.session_id.slice(0,
|
|
600
|
+
const sessionShort = e.session_id.slice(0, SESSION_ID_DISPLAY_LEN);
|
|
590
601
|
return `[${ts}] [${sessionShort}] ${e.tool_name}\n${e.args_json}`;
|
|
591
602
|
}).join("\n\n");
|
|
592
603
|
|
|
593
604
|
return {
|
|
594
605
|
content: [{
|
|
595
606
|
type: "text",
|
|
596
|
-
text: `Activity log (${entries.length} entr${entries.length === 1 ? "y" : "ies"}, current session: ${sessionId.slice(0,
|
|
607
|
+
text: `Activity log (${entries.length} entr${entries.length === 1 ? "y" : "ies"}, current session: ${sessionId.slice(0, SESSION_ID_DISPLAY_LEN)}):\n\n${formatted}`
|
|
597
608
|
}]
|
|
598
609
|
};
|
|
599
610
|
}
|
|
@@ -651,13 +662,9 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
651
662
|
}
|
|
652
663
|
if (!body) throw new Error("No content to analyze");
|
|
653
664
|
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
while ((match = linkRegex.exec(inputText)) !== null) {
|
|
658
|
-
const target = match[1];
|
|
659
|
-
linkedNames.add(path.basename(target, ".md").toLowerCase());
|
|
660
|
-
}
|
|
665
|
+
const linkedNames = new Set(
|
|
666
|
+
extractWikilinks(inputText).map(t => path.basename(t, ".md").toLowerCase())
|
|
667
|
+
);
|
|
661
668
|
|
|
662
669
|
const excludeFiles = new Set();
|
|
663
670
|
if (sourcePath) excludeFiles.add(sourcePath);
|
|
@@ -696,7 +703,12 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
696
703
|
const filePath = resolvePath(resolvedRelative);
|
|
697
704
|
|
|
698
705
|
// Verify file exists
|
|
699
|
-
|
|
706
|
+
try {
|
|
707
|
+
await fs.access(filePath);
|
|
708
|
+
} catch (e) {
|
|
709
|
+
if (e.code === "ENOENT") throw new Error(`ENOENT: File not found: ${resolvedRelative}`, { cause: e });
|
|
710
|
+
throw e;
|
|
711
|
+
}
|
|
700
712
|
|
|
701
713
|
// Find incoming links for warning output
|
|
702
714
|
const allFilesList = Array.from(allFilesSet);
|
|
@@ -725,14 +737,7 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
725
737
|
await fs.rename(filePath, trashAbsolute);
|
|
726
738
|
|
|
727
739
|
// Update in-memory basename map
|
|
728
|
-
|
|
729
|
-
const oldBasename = path.basename(resolvedRelative, ".md").toLowerCase();
|
|
730
|
-
const entries = basenameMap.get(oldBasename);
|
|
731
|
-
if (entries) {
|
|
732
|
-
const idx = entries.indexOf(resolvedRelative);
|
|
733
|
-
if (idx !== -1) entries.splice(idx, 1);
|
|
734
|
-
if (entries.length === 0) basenameMap.delete(oldBasename);
|
|
735
|
-
}
|
|
740
|
+
removeFromBasenameMap(resolvedRelative);
|
|
736
741
|
|
|
737
742
|
// Build output
|
|
738
743
|
let text = `Trashed ${resolvedRelative} → ${trashRelative}`;
|
|
@@ -754,7 +759,12 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
754
759
|
const newAbsolute = resolvePath(newRelative);
|
|
755
760
|
|
|
756
761
|
// Verify source exists
|
|
757
|
-
|
|
762
|
+
try {
|
|
763
|
+
await fs.access(oldAbsolute);
|
|
764
|
+
} catch (e) {
|
|
765
|
+
if (e.code === "ENOENT") throw new Error(`ENOENT: File not found: ${oldRelative}`, { cause: e });
|
|
766
|
+
throw e;
|
|
767
|
+
}
|
|
758
768
|
|
|
759
769
|
// Verify destination does NOT exist
|
|
760
770
|
try {
|
|
@@ -775,23 +785,11 @@ export async function createHandlers({ vaultPath, templateRegistry, semanticInde
|
|
|
775
785
|
await fs.rename(oldAbsolute, newAbsolute);
|
|
776
786
|
|
|
777
787
|
// Update basename map: remove old, add new
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
const oldEntries = basenameMap.get(oldBasename);
|
|
781
|
-
if (oldEntries) {
|
|
782
|
-
const idx = oldEntries.indexOf(oldRelative);
|
|
783
|
-
if (idx !== -1) oldEntries.splice(idx, 1);
|
|
784
|
-
if (oldEntries.length === 0) basenameMap.delete(oldBasename);
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
allFilesSet.add(newRelative);
|
|
788
|
-
const newBasename = path.basename(newRelative, ".md").toLowerCase();
|
|
789
|
-
if (!basenameMap.has(newBasename)) {
|
|
790
|
-
basenameMap.set(newBasename, []);
|
|
791
|
-
}
|
|
792
|
-
basenameMap.get(newBasename).push(newRelative);
|
|
788
|
+
removeFromBasenameMap(oldRelative);
|
|
789
|
+
addToBasenameMap(newRelative);
|
|
793
790
|
|
|
794
791
|
// Determine new link target — use full path if basename is now ambiguous
|
|
792
|
+
const newBasename = path.basename(newRelative, ".md").toLowerCase();
|
|
795
793
|
const newEntries = basenameMap.get(newBasename);
|
|
796
794
|
const isAmbiguous = newEntries && newEntries.length > 1;
|
|
797
795
|
const newLinkTarget = isAmbiguous
|
package/hooks/capture-handler.sh
CHANGED
|
@@ -15,19 +15,23 @@ trap cleanup EXIT
|
|
|
15
15
|
# Read hook input from stdin
|
|
16
16
|
INPUT=$(cat)
|
|
17
17
|
|
|
18
|
-
# Extract tool_input fields (
|
|
19
|
-
|
|
20
|
-
let b='';
|
|
21
|
-
process.stdin.on('
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
")
|
|
18
|
+
# Extract tool_input fields safely (no eval — stdout capture only)
|
|
19
|
+
TOOL_INPUT=$(echo "$INPUT" | node -e "
|
|
20
|
+
let b=''; process.stdin.on('data',c=>b+=c);
|
|
21
|
+
process.stdin.on('end',()=>{ process.stdout.write(JSON.stringify(JSON.parse(b).tool_input||{})); })
|
|
22
|
+
")
|
|
23
|
+
CAPTURE_TYPE=$(echo "$INPUT" | node -e "
|
|
24
|
+
let b=''; process.stdin.on('data',c=>b+=c);
|
|
25
|
+
process.stdin.on('end',()=>{ process.stdout.write((JSON.parse(b).tool_input||{}).type||''); })
|
|
26
|
+
")
|
|
27
|
+
CAPTURE_TITLE=$(echo "$INPUT" | node -e "
|
|
28
|
+
let b=''; process.stdin.on('data',c=>b+=c);
|
|
29
|
+
process.stdin.on('end',()=>{ process.stdout.write((JSON.parse(b).tool_input||{}).title||''); })
|
|
30
|
+
")
|
|
31
|
+
CAPTURE_CONTENT=$(echo "$INPUT" | node -e "
|
|
32
|
+
let b=''; process.stdin.on('data',c=>b+=c);
|
|
33
|
+
process.stdin.on('end',()=>{ process.stdout.write((JSON.parse(b).tool_input||{}).content||''); })
|
|
34
|
+
")
|
|
31
35
|
|
|
32
36
|
# Skip if missing required fields
|
|
33
37
|
if [ -z "$CAPTURE_TYPE" ] || [ -z "$CAPTURE_TITLE" ] || [ -z "$CAPTURE_CONTENT" ]; then
|
package/index.js
CHANGED
|
@@ -73,7 +73,7 @@ export async function startServer() {
|
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
name: "vault_peek",
|
|
76
|
-
description: "Inspect a file's metadata and structure without reading full content. Returns file size, frontmatter, heading outline with
|
|
76
|
+
description: "Inspect a file's metadata and structure without reading full content. Returns file size, frontmatter, heading outline with approximate section sizes, and a brief preview. Use this to plan which sections to read from large files.",
|
|
77
77
|
inputSchema: {
|
|
78
78
|
type: "object",
|
|
79
79
|
properties: {
|
package/init.js
CHANGED
|
@@ -208,8 +208,29 @@ export function patchMcpConfig(scriptContent, installType) {
|
|
|
208
208
|
const argsJson = JSON.stringify(installType.args);
|
|
209
209
|
const replacement = `MCP_CONFIG='{"mcpServers":{"obsidian-pkm":{"command":"${installType.command}","args":${argsJson},"env":{"VAULT_PATH":"'"$VAULT_PATH"'"}}}}'`;
|
|
210
210
|
const lines = scriptContent.split("\n");
|
|
211
|
-
const
|
|
212
|
-
|
|
211
|
+
const result = [];
|
|
212
|
+
let i = 0;
|
|
213
|
+
|
|
214
|
+
while (i < lines.length) {
|
|
215
|
+
if (lines[i].startsWith("MCP_CONFIG=")) {
|
|
216
|
+
result.push(replacement);
|
|
217
|
+
// Multi-line command substitution: contains $( but closing ) is on a later line
|
|
218
|
+
if (lines[i].includes("$(") && !lines[i].trimEnd().endsWith(")")) {
|
|
219
|
+
i++;
|
|
220
|
+
while (i < lines.length && !lines[i].trimEnd().endsWith(")")) {
|
|
221
|
+
i++;
|
|
222
|
+
}
|
|
223
|
+
i++; // skip the closing line
|
|
224
|
+
} else {
|
|
225
|
+
i++;
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
result.push(lines[i]);
|
|
229
|
+
i++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return result.join("\n");
|
|
213
234
|
}
|
|
214
235
|
|
|
215
236
|
const PKM_HOOK_BASENAMES = new Set(["session-start.js", "stop-sweep.js", "capture-handler.sh"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pkm-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "MCP server for Obsidian vault integration with Claude Code — 19 tools for notes, search, and graph traversal",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"exports": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@inquirer/prompts": "^8.3.2",
|
|
56
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
57
57
|
"better-sqlite3": "^12.6.2",
|
|
58
58
|
"js-yaml": "^4.1.0",
|
|
59
59
|
"sqlite-vec": "^0.1.7"
|
package/sample-project/CLAUDE.md
CHANGED
|
@@ -185,6 +185,7 @@ Use these with `vault_write({ template: "name", path: "...", frontmatter: { tags
|
|
|
185
185
|
| `moc` | Maps of Content (index/hub notes) |
|
|
186
186
|
| `daily-note` | Daily notes |
|
|
187
187
|
| `task` | Structured task notes with status, priority, due date |
|
|
188
|
+
| `note` | Minimal generic notes |
|
|
188
189
|
|
|
189
190
|
## Session End
|
|
190
191
|
|