pkm-mcp-server 1.3.0 → 1.3.2
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 +10 -0
- package/README.md +33 -40
- package/init.js +88 -95
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.3.2] - 2026-03-21
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Fix `claude mcp add` argument ordering — the `-e` flag is variadic and was greedily consuming the server name. Moved `--` separator before the server name to terminate option parsing.
|
|
13
|
+
|
|
14
|
+
## [1.3.1] - 2026-03-21
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `pkm-mcp-server init` now correctly registers the MCP server with Claude Code via `claude mcp add` instead of writing to the wrong config file (`~/.claude/settings.json`). Previously, the server appeared to register successfully but was never visible to Claude Code.
|
|
18
|
+
|
|
9
19
|
## [1.3.0] - 2026-03-19
|
|
10
20
|
|
|
11
21
|
### Added
|
package/README.md
CHANGED
|
@@ -82,69 +82,59 @@ Ambiguous matches return an error listing candidates. Exact paths always work un
|
|
|
82
82
|
|
|
83
83
|
## Quick Start
|
|
84
84
|
|
|
85
|
-
### 1. Install
|
|
85
|
+
### 1. Install and Set Up
|
|
86
86
|
|
|
87
87
|
**From npm** (recommended):
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
90
|
npm install -g pkm-mcp-server
|
|
91
|
+
pkm-mcp-server init
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
The setup wizard walks you through:
|
|
95
|
+
1. Vault path (existing or new)
|
|
96
|
+
2. Note templates (full set, minimal, or skip)
|
|
97
|
+
3. PARA folder structure
|
|
98
|
+
4. OpenAI API key for semantic search (optional)
|
|
99
|
+
5. Automatic registration with Claude Code
|
|
100
|
+
|
|
101
|
+
Restart Claude Code after setup. The server provides all tools except semantic search out of the box.
|
|
102
|
+
|
|
93
103
|
**From source:**
|
|
94
104
|
|
|
95
105
|
```bash
|
|
96
106
|
git clone https://github.com/AdrianV101/Obsidian-MCP.git
|
|
97
107
|
cd Obsidian-MCP
|
|
98
108
|
npm install
|
|
109
|
+
node cli.js init
|
|
99
110
|
```
|
|
100
111
|
|
|
101
|
-
### 2.
|
|
102
|
-
|
|
103
|
-
Add to `~/.claude/settings.json`:
|
|
112
|
+
### 2. Manual Registration (alternative)
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
If you prefer to skip the wizard, register directly with the Claude CLI:
|
|
106
115
|
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
"mcpServers": {
|
|
110
|
-
"obsidian-pkm": {
|
|
111
|
-
"command": "npx",
|
|
112
|
-
"args": ["-y", "pkm-mcp-server"],
|
|
113
|
-
"env": {
|
|
114
|
-
"VAULT_PATH": "/absolute/path/to/your/obsidian/vault"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
116
|
+
```bash
|
|
117
|
+
claude mcp add -s user -e VAULT_PATH=/absolute/path/to/your/vault -- obsidian-pkm npx -y pkm-mcp-server
|
|
119
118
|
```
|
|
120
119
|
|
|
121
|
-
|
|
120
|
+
For a source install:
|
|
122
121
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
"mcpServers": {
|
|
126
|
-
"obsidian-pkm": {
|
|
127
|
-
"command": "node",
|
|
128
|
-
"args": ["/absolute/path/to/index.js"],
|
|
129
|
-
"env": {
|
|
130
|
-
"VAULT_PATH": "/absolute/path/to/your/obsidian/vault"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
122
|
+
```bash
|
|
123
|
+
claude mcp add -s user -e VAULT_PATH=/absolute/path/to/your/vault -- obsidian-pkm node /absolute/path/to/cli.js
|
|
135
124
|
```
|
|
136
125
|
|
|
137
|
-
|
|
126
|
+
Verify with `claude mcp list` — you should see `obsidian-pkm: ... - Connected`.
|
|
138
127
|
|
|
139
128
|
### 3. Enable Semantic Search (optional)
|
|
140
129
|
|
|
141
|
-
|
|
130
|
+
If you didn't set this up during `init`, add your OpenAI API key by re-registering:
|
|
142
131
|
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
132
|
+
```bash
|
|
133
|
+
claude mcp remove obsidian-pkm
|
|
134
|
+
claude mcp add -s user \
|
|
135
|
+
-e VAULT_PATH=/absolute/path/to/your/vault \
|
|
136
|
+
-e OPENAI_API_KEY=sk-... \
|
|
137
|
+
-- obsidian-pkm npx -y pkm-mcp-server
|
|
148
138
|
```
|
|
149
139
|
|
|
150
140
|
This enables `vault_semantic_search` and `vault_suggest_links`. Uses `text-embedding-3-large` with a SQLite + sqlite-vec index stored at `.obsidian/semantic-index.db`. The index rebuilds automatically — delete the DB file to force a full re-embed.
|
|
@@ -290,13 +280,16 @@ All paths passed to tools are relative to vault root. The server includes path s
|
|
|
290
280
|
You need C++ build tools. See [Prerequisites](#prerequisites) for your platform. On Linux, `sudo apt install build-essential python3` usually fixes it.
|
|
291
281
|
|
|
292
282
|
**Server starts but all tool calls fail with ENOENT**
|
|
293
|
-
Your `VAULT_PATH` is wrong or missing. The server
|
|
283
|
+
Your `VAULT_PATH` is wrong or missing. The server validates this at startup and exits with a clear error. Re-register with the correct path: `claude mcp remove obsidian-pkm && claude mcp add -s user -e VAULT_PATH=/correct/path -- obsidian-pkm npx -y pkm-mcp-server`
|
|
294
284
|
|
|
295
285
|
**`vault_write` says "no templates available"**
|
|
296
|
-
|
|
286
|
+
Run `pkm-mcp-server init` to install templates, or copy the `templates/` files from this repo into your vault's `05-Templates/` directory. The server loads templates from there at startup.
|
|
297
287
|
|
|
298
288
|
**Semantic search not appearing in tool list**
|
|
299
|
-
Set `OPENAI_API_KEY` in your
|
|
289
|
+
Set `OPENAI_API_KEY` in your MCP server registration. See [Enable Semantic Search](#3-enable-semantic-search-optional). Without it, `vault_semantic_search` and `vault_suggest_links` are hidden entirely.
|
|
290
|
+
|
|
291
|
+
**Server not showing up in Claude Code after install**
|
|
292
|
+
Run `claude mcp list` to check. If `obsidian-pkm` is missing, register it with `claude mcp add` (see [Manual Registration](#2-manual-registration-alternative)). Note: editing `~/.claude/settings.json` directly does **not** register MCP servers — use the CLI.
|
|
300
293
|
|
|
301
294
|
**Semantic index not updating after file changes**
|
|
302
295
|
Check your Node version with `node -v`. The file watcher uses `fs.watch({ recursive: true })` which requires Node.js >= 18.13 on Linux.
|
package/init.js
CHANGED
|
@@ -2,6 +2,10 @@ import os from "os";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
+
import { execFile as execFileCb } from "child_process";
|
|
6
|
+
import { promisify } from "util";
|
|
7
|
+
|
|
8
|
+
const execFileAsync = promisify(execFileCb);
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Resolve user-provided path input: expand ~, $HOME, resolve relative, normalise.
|
|
@@ -119,41 +123,44 @@ export async function backupVault(vaultPath) {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
/**
|
|
122
|
-
*
|
|
123
|
-
* @param {string
|
|
124
|
-
* @
|
|
125
|
-
* @returns {Promise<object>} The full merged config object
|
|
126
|
+
* Build argument array for `claude mcp add` command.
|
|
127
|
+
* @param {{ vaultPath: string, openaiKey: string|null, installType: { command: string, args: string[] } }} opts
|
|
128
|
+
* @returns {string[]}
|
|
126
129
|
*/
|
|
127
|
-
export
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
export function buildMcpAddArgs({ vaultPath, openaiKey, installType }) {
|
|
131
|
+
const args = ["mcp", "add", "-s", "user"];
|
|
132
|
+
args.push("-e", `VAULT_PATH=${vaultPath}`);
|
|
133
|
+
if (openaiKey) {
|
|
134
|
+
args.push("-e", `OPENAI_API_KEY=${openaiKey}`);
|
|
135
|
+
}
|
|
136
|
+
args.push("--", "obsidian-pkm", installType.command, ...installType.args);
|
|
137
|
+
return args;
|
|
138
|
+
}
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Check if the `claude` CLI is available on PATH.
|
|
142
|
+
* @returns {Promise<boolean>}
|
|
143
|
+
*/
|
|
144
|
+
export async function checkClaudeCli() {
|
|
133
145
|
try {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const err = new Error(`${settingsPath} is not valid JSON. Please fix it manually or delete it to start fresh.`);
|
|
139
|
-
err.code = "INVALID_JSON";
|
|
140
|
-
throw err;
|
|
141
|
-
}
|
|
142
|
-
} catch (e) {
|
|
143
|
-
if (e.code !== "ENOENT") throw e;
|
|
144
|
-
// File doesn't exist — start with {}
|
|
146
|
+
await execFileAsync("claude", ["--version"]);
|
|
147
|
+
return true;
|
|
148
|
+
} catch {
|
|
149
|
+
return false;
|
|
145
150
|
}
|
|
151
|
+
}
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Check if obsidian-pkm is already registered in Claude Code.
|
|
155
|
+
* @returns {Promise<boolean>}
|
|
156
|
+
*/
|
|
157
|
+
export async function checkExistingRegistration() {
|
|
158
|
+
try {
|
|
159
|
+
await execFileAsync("claude", ["mcp", "get", "obsidian-pkm"]);
|
|
160
|
+
return true;
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
/**
|
|
@@ -207,7 +214,6 @@ export async function runInit() {
|
|
|
207
214
|
const { confirm: confirmPrompt, input, select, password } = await import("@inquirer/prompts");
|
|
208
215
|
|
|
209
216
|
const bundledTemplatesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "templates");
|
|
210
|
-
const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
211
217
|
const steps = [];
|
|
212
218
|
|
|
213
219
|
try {
|
|
@@ -299,8 +305,8 @@ Nothing is written until you confirm each step. Press Ctrl+C at any time to canc
|
|
|
299
305
|
console.log(`
|
|
300
306
|
Get an API key at: https://platform.openai.com/api-keys
|
|
301
307
|
|
|
302
|
-
This key is stored only in your
|
|
303
|
-
(~/.claude
|
|
308
|
+
This key is stored only in your Claude Code configuration
|
|
309
|
+
(~/.claude.json) and is never sent to us or anyone else.
|
|
304
310
|
It's used solely for generating text embeddings via OpenAI's API.
|
|
305
311
|
`);
|
|
306
312
|
openaiKey = await password({ message: "OpenAI API key (Enter to skip):", mask: "*" });
|
|
@@ -309,79 +315,66 @@ Nothing is written until you confirm each step. Press Ctrl+C at any time to canc
|
|
|
309
315
|
console.log(" You can add this later by setting OPENAI_API_KEY in your Claude Code settings.\n");
|
|
310
316
|
}
|
|
311
317
|
// ── Step 6: Registration ──
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
if (openaiKey) {
|
|
319
|
-
serverConfig.env.OPENAI_API_KEY = openaiKey;
|
|
320
|
-
}
|
|
318
|
+
const hasClaude = await checkClaudeCli();
|
|
319
|
+
if (!hasClaude) {
|
|
320
|
+
const installType = detectInstallType();
|
|
321
|
+
const manualCmd = `claude mcp add -s user -e VAULT_PATH=${vaultPath} -- obsidian-pkm ${installType.command} ${installType.args.join(" ")}`;
|
|
322
|
+
console.log(`
|
|
323
|
+
Claude Code CLI not found on PATH. To register manually, run:
|
|
321
324
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
325
|
+
${manualCmd}
|
|
326
|
+
`);
|
|
327
|
+
steps.push("MCP server: skipped (Claude CLI not found)");
|
|
328
|
+
} else {
|
|
329
|
+
const installType = detectInstallType();
|
|
330
|
+
const hasExisting = await checkExistingRegistration();
|
|
331
|
+
|
|
332
|
+
let skipRegistration = false;
|
|
333
|
+
if (hasExisting) {
|
|
334
|
+
const overwrite = await confirmPrompt({ message: "Claude Code is already configured for pkm-mcp-server. Overwrite?", default: false });
|
|
335
|
+
if (!overwrite) {
|
|
336
|
+
console.log(" Registration skipped.\n");
|
|
337
|
+
skipRegistration = true;
|
|
338
|
+
} else {
|
|
339
|
+
// Remove existing before re-adding
|
|
340
|
+
try {
|
|
341
|
+
await execFileAsync("claude", ["mcp", "remove", "obsidian-pkm"]);
|
|
342
|
+
} catch (e) {
|
|
343
|
+
console.warn(` Warning: could not remove existing registration: ${e.message}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
333
346
|
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
let skipRegistration = false;
|
|
337
|
-
if (hasExisting) {
|
|
338
|
-
const overwrite = await confirmPrompt({ message: "Claude Code is already configured for pkm-mcp-server. Overwrite?", default: false });
|
|
339
|
-
if (!overwrite) { console.log(" Registration skipped.\n"); skipRegistration = true; }
|
|
340
|
-
}
|
|
341
347
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
try {
|
|
361
|
-
await updateSettingsJson(settingsPath, serverConfig);
|
|
362
|
-
registered = true;
|
|
363
|
-
} catch (regErr) {
|
|
364
|
-
if (regErr.code === "INVALID_JSON") {
|
|
365
|
-
console.error(`\n ${regErr.message}`);
|
|
348
|
+
if (!skipRegistration) {
|
|
349
|
+
const addArgs = buildMcpAddArgs({ vaultPath, openaiKey, installType });
|
|
350
|
+
const displayCmd = `claude ${addArgs.join(" ")}`;
|
|
351
|
+
console.log(`\nWill run:\n\n ${displayCmd}\n`);
|
|
352
|
+
|
|
353
|
+
const doRegister = await confirmPrompt({
|
|
354
|
+
message: "Register MCP server with Claude Code?",
|
|
355
|
+
default: true,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
if (doRegister) {
|
|
359
|
+
try {
|
|
360
|
+
await execFileAsync("claude", addArgs);
|
|
361
|
+
console.log(" MCP server registered with Claude Code");
|
|
362
|
+
steps.push("MCP server: registered");
|
|
363
|
+
} catch (regErr) {
|
|
364
|
+
console.error(`\n Registration failed: ${regErr.message}`);
|
|
365
|
+
if (regErr.stderr) console.error(` ${regErr.stderr.trim()}`);
|
|
366
366
|
const skipReg = await confirmPrompt({ message: "Skip registration and finish setup?", default: true });
|
|
367
367
|
if (!skipReg) throw regErr;
|
|
368
368
|
console.log(" Registration skipped.\n");
|
|
369
|
-
|
|
370
|
-
throw regErr;
|
|
369
|
+
steps.push("MCP server: skipped (registration failed)");
|
|
371
370
|
}
|
|
372
|
-
}
|
|
373
|
-
if (registered) {
|
|
374
|
-
console.log(" MCP server registered");
|
|
375
|
-
steps.push("MCP server: registered");
|
|
376
371
|
} else {
|
|
377
|
-
|
|
372
|
+
console.log(" Registration: skipped (you can run `pkm-mcp-server init` again later)");
|
|
373
|
+
steps.push("MCP server: skipped");
|
|
378
374
|
}
|
|
379
375
|
} else {
|
|
380
|
-
console.log(" Registration: skipped (you can run `pkm-mcp-server init` again later)");
|
|
381
376
|
steps.push("MCP server: skipped");
|
|
382
377
|
}
|
|
383
|
-
} else {
|
|
384
|
-
steps.push("MCP server: skipped");
|
|
385
378
|
}
|
|
386
379
|
|
|
387
380
|
// ── Step 7: Summary ──
|
|
@@ -398,7 +391,7 @@ Nothing is written until you confirm each step. Press Ctrl+C at any time to canc
|
|
|
398
391
|
// Determine registration summary from steps
|
|
399
392
|
const regStep = steps.find(s => s.startsWith("MCP server:"));
|
|
400
393
|
const registrationSummary = regStep && regStep.includes("registered")
|
|
401
|
-
?
|
|
394
|
+
? "Registered with Claude Code"
|
|
402
395
|
: "Skipped";
|
|
403
396
|
|
|
404
397
|
console.log(`
|