@leonardocrdso/obsidian-mcp 1.0.0 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +30 -8
  2. package/build/index.js +164 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -7,17 +7,38 @@ Cobertura completa da API com **22 tools** organizadas em 5 módulos.
7
7
  ## Requisitos
8
8
 
9
9
  - [Obsidian](https://obsidian.md/) com o plugin **Local REST API** instalado e ativo
10
- - [Bun](https://bun.sh/) (desenvolvimento) ou Node.js 18+ (produção)
10
+ - Node.js 18+ ou [Bun](https://bun.sh/)
11
11
 
12
- ## Instalação
12
+ ## Configuração
13
+
14
+ ### 1. Setup interativo (recomendado)
13
15
 
14
16
  ```bash
15
- npm install -g @leonardocrdso/obsidian-mcp
17
+ npx @leonardocrdso/obsidian-mcp --setup
16
18
  ```
17
19
 
18
- ## Configuração
20
+ ```
21
+ Obsidian MCP — Configuracao
22
+
23
+ API Key: sua-api-key-aqui
24
+ Host [127.0.0.1]: 192.168.1.50
25
+ Porta [27124]:
26
+ Protocolo [https]:
27
+
28
+ Configuracao salva em ~/.obsidian-mcp.json
29
+ ```
30
+
31
+ O setup pede cada item e salva em `~/.obsidian-mcp.json`. Para reconfigurar, basta rodar `--setup` novamente.
19
32
 
20
- ### Variáveis de ambiente
33
+ ### 2. Registrar no Claude Code
34
+
35
+ ```bash
36
+ claude mcp add obsidian -- npx @leonardocrdso/obsidian-mcp
37
+ ```
38
+
39
+ ### Variáveis de ambiente (alternativa)
40
+
41
+ Se preferir, configure via variáveis de ambiente em vez do setup interativo:
21
42
 
22
43
  | Variável | Obrigatória | Padrão | Descrição |
23
44
  |---|---|---|---|
@@ -26,8 +47,6 @@ npm install -g @leonardocrdso/obsidian-mcp
26
47
  | `OBSIDIAN_PORT` | Não | `27124` | Porta do plugin |
27
48
  | `OBSIDIAN_PROTOCOL` | Não | `https` | Protocolo (http ou https) |
28
49
 
29
- ### Claude Code (`settings.json`)
30
-
31
50
  ```json
32
51
  {
33
52
  "mcpServers": {
@@ -42,13 +61,16 @@ npm install -g @leonardocrdso/obsidian-mcp
42
61
  }
43
62
  ```
44
63
 
64
+ Prioridade de configuração: arquivo `~/.obsidian-mcp.json` > variáveis de ambiente.
65
+
45
66
  ### Desenvolvimento
46
67
 
47
68
  ```bash
48
69
  git clone https://github.com/leonardocrdso/obsidian-mcp.git
49
70
  cd obsidian-mcp
50
71
  bun install
51
- OBSIDIAN_API_KEY=sua-key bun run dev
72
+ bun run dev --setup # configurar
73
+ bun run dev # iniciar servidor
52
74
  ```
53
75
 
54
76
  ## Tools (22)
package/build/index.js CHANGED
@@ -25,6 +25,7 @@ var __export = (target, all) => {
25
25
  set: (newValue) => all[name] = () => newValue
26
26
  });
27
27
  };
28
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
29
 
29
30
  // node_modules/ajv/dist/compile/codegen/code.js
30
31
  var require_code = __commonJS((exports) => {
@@ -6498,6 +6499,116 @@ var require_dist = __commonJS((exports, module) => {
6498
6499
  exports.default = formatsPlugin;
6499
6500
  });
6500
6501
 
6502
+ // src/shared/setup.ts
6503
+ var exports_setup = {};
6504
+ __export(exports_setup, {
6505
+ runSetup: () => runSetup,
6506
+ loadSavedConfig: () => loadSavedConfig
6507
+ });
6508
+ import { writeFileSync, readFileSync, existsSync } from "fs";
6509
+ import { homedir } from "os";
6510
+ import { join } from "path";
6511
+ function loadSavedConfig() {
6512
+ if (!existsSync(CONFIG_PATH))
6513
+ return null;
6514
+ try {
6515
+ return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
6516
+ } catch {
6517
+ return null;
6518
+ }
6519
+ }
6520
+ function write(text) {
6521
+ process.stderr.write(text);
6522
+ }
6523
+ function createLineReader() {
6524
+ const lines = [];
6525
+ let waiting = null;
6526
+ let buffer = "";
6527
+ process.stdin.setEncoding("utf-8");
6528
+ process.stdin.on("data", (chunk) => {
6529
+ buffer += chunk;
6530
+ const parts = buffer.split(`
6531
+ `);
6532
+ buffer = parts.pop();
6533
+ for (const line of parts) {
6534
+ if (waiting) {
6535
+ const resolve = waiting;
6536
+ waiting = null;
6537
+ resolve(line.trim());
6538
+ } else {
6539
+ lines.push(line.trim());
6540
+ }
6541
+ }
6542
+ });
6543
+ process.stdin.on("end", () => {
6544
+ if (buffer && waiting) {
6545
+ const resolve = waiting;
6546
+ waiting = null;
6547
+ resolve(buffer.trim());
6548
+ buffer = "";
6549
+ }
6550
+ });
6551
+ return (label, fallback) => {
6552
+ const suffix = fallback ? ` [${fallback}]` : "";
6553
+ write(` ${label}${suffix}: `);
6554
+ if (lines.length > 0) {
6555
+ const value = lines.shift();
6556
+ write(value + `
6557
+ `);
6558
+ return Promise.resolve(value || fallback || "");
6559
+ }
6560
+ return new Promise((resolve) => {
6561
+ waiting = (value) => resolve(value || fallback || "");
6562
+ });
6563
+ };
6564
+ }
6565
+ function mask(value) {
6566
+ if (value.length <= 8)
6567
+ return "*".repeat(value.length);
6568
+ return value.slice(0, 4) + "*".repeat(value.length - 4);
6569
+ }
6570
+ async function runSetup() {
6571
+ const existing = loadSavedConfig();
6572
+ const prompt = createLineReader();
6573
+ write(`
6574
+ Obsidian MCP — Configuracao
6575
+
6576
+ `);
6577
+ const apiKey = await prompt("API Key", existing?.apiKey ? mask(existing.apiKey) : undefined);
6578
+ const host = await prompt("Host", existing?.host ?? "127.0.0.1");
6579
+ const port = await prompt("Porta", existing?.port ?? "27124");
6580
+ const protocol = await prompt("Protocolo", existing?.protocol ?? "https");
6581
+ process.stdin.destroy();
6582
+ if (!apiKey || apiKey.includes("*")) {
6583
+ if (existing?.apiKey && apiKey.includes("*")) {
6584
+ saveConfig({ apiKey: existing.apiKey, host, port, protocol });
6585
+ return;
6586
+ }
6587
+ write(`
6588
+ API Key e obrigatoria.
6589
+
6590
+ `);
6591
+ process.exit(1);
6592
+ }
6593
+ saveConfig({ apiKey, host, port, protocol });
6594
+ }
6595
+ function saveConfig(config2) {
6596
+ writeFileSync(CONFIG_PATH, JSON.stringify(config2, null, 2));
6597
+ write(`
6598
+ Configuracao salva em ${CONFIG_PATH}
6599
+ `);
6600
+ write(`
6601
+ Adicione ao Claude Code:
6602
+ `);
6603
+ write(` claude mcp add obsidian -- npx @leonardocrdso/obsidian-mcp
6604
+
6605
+ `);
6606
+ }
6607
+ var CONFIG_PATH;
6608
+ var init_setup = __esm(() => {
6609
+ CONFIG_PATH = join(homedir(), ".obsidian-mcp.json");
6610
+ });
6611
+
6501
6612
  // node_modules/zod/v3/external.js
6502
6613
  var exports_external = {};
6503
6614
  __export(exports_external, {
@@ -19455,18 +19566,29 @@ class StdioServerTransport {
19455
19566
  }
19456
19567
 
19457
19568
  // src/shared/config.ts
19569
+ init_setup();
19458
19570
  function loadConfig() {
19571
+ const saved = loadSavedConfig();
19572
+ if (saved) {
19573
+ const baseUrl = `${saved.protocol}://${saved.host}:${saved.port}`;
19574
+ return { ...saved, baseUrl };
19575
+ }
19459
19576
  const apiKey = process.env.OBSIDIAN_API_KEY;
19460
- if (!apiKey) {
19461
- throw new Error("OBSIDIAN_API_KEY não configurada. Defina a variável de ambiente com a API key do plugin Local REST API.");
19577
+ if (apiKey) {
19578
+ const host = process.env.OBSIDIAN_HOST ?? "127.0.0.1";
19579
+ const port = process.env.OBSIDIAN_PORT ?? "27124";
19580
+ const protocol = process.env.OBSIDIAN_PROTOCOL ?? "https";
19581
+ const baseUrl = `${protocol}://${host}:${port}`;
19582
+ return { apiKey, host, port, protocol, baseUrl };
19462
19583
  }
19463
- const host = process.env.OBSIDIAN_HOST ?? "127.0.0.1";
19464
- const port = process.env.OBSIDIAN_PORT ?? "27124";
19465
- const protocol = process.env.OBSIDIAN_PROTOCOL ?? "https";
19466
- const baseUrl = `${protocol}://${host}:${port}`;
19467
- return { apiKey, host, port, protocol, baseUrl };
19584
+ throw new Error("Obsidian MCP nao configurado. Execute: npx @leonardocrdso/obsidian-mcp --setup");
19585
+ }
19586
+ var cached2 = null;
19587
+ function getConfig() {
19588
+ if (!cached2)
19589
+ cached2 = loadConfig();
19590
+ return cached2;
19468
19591
  }
19469
- var config2 = loadConfig();
19470
19592
 
19471
19593
  // src/shared/errors.ts
19472
19594
  class ObsidianApiError extends Error {
@@ -19571,7 +19693,14 @@ class ObsidianClient {
19571
19693
 
19572
19694
  // src/modules/vault/vault.tools.ts
19573
19695
  function registerVaultTools(server, client) {
19574
- server.tool("vaultListFiles", "Lista arquivos e pastas de um diretório do vault. Sem parâmetros lista a raiz.", {
19696
+ server.tool("vaultListFiles", [
19697
+ "Lista arquivos e pastas de um diretório do vault. Sem parâmetros lista a raiz.",
19698
+ "",
19699
+ "IMPORTANTE: Use esta tool ANTES de criar arquivos para entender a estrutura de pastas existente.",
19700
+ "Navegue pela raiz e subpastas para mapear como o vault está organizado por assunto.",
19701
+ "Pastas terminam com '/' no resultado."
19702
+ ].join(`
19703
+ `), {
19575
19704
  path: exports_external.string().optional().describe("Caminho do diretório no vault (ex: 'Notes/Projects')")
19576
19705
  }, safeTool(async (params) => {
19577
19706
  const dirPath = params.path ? `${client.encodePath(params.path)}/` : "";
@@ -19596,8 +19725,20 @@ function registerVaultTools(server, client) {
19596
19725
  content: [{ type: "text", text: JSON.stringify(metadata, null, 2) }]
19597
19726
  };
19598
19727
  }));
19599
- server.tool("vaultCreateFile", "Cria ou substitui um arquivo no vault.", {
19600
- path: exports_external.string().describe("Caminho do arquivo a criar (ex: 'Notes/novo.md')"),
19728
+ server.tool("vaultCreateFile", [
19729
+ "Cria ou substitui um arquivo no vault.",
19730
+ "",
19731
+ "ANTES de chamar esta tool, você DEVE:",
19732
+ "1. Usar vaultListFiles (sem parâmetros) para ver as pastas raiz do vault.",
19733
+ "2. Explorar as subpastas relevantes para entender a organização por assunto.",
19734
+ "3. Escolher a pasta que melhor se encaixa no tema do arquivo sendo criado.",
19735
+ "4. Se nenhuma pasta existente fizer sentido, crie uma nova seguindo o padrão de nomenclatura já usado no vault.",
19736
+ "",
19737
+ "NUNCA crie arquivos soltos na raiz se houver uma estrutura de pastas organizada.",
19738
+ "O objetivo é manter o vault coerente — cada arquivo deve estar na pasta que melhor representa seu assunto."
19739
+ ].join(`
19740
+ `), {
19741
+ path: exports_external.string().describe("Caminho completo do arquivo incluindo a pasta adequada (ex: 'Projetos/meu-projeto/reuniao.md')"),
19601
19742
  content: exports_external.string().describe("Conteúdo do arquivo")
19602
19743
  }, safeTool(async (params) => {
19603
19744
  await client.fetchVoid(`/vault/${client.encodePath(params.path)}`, {
@@ -19609,7 +19750,12 @@ function registerVaultTools(server, client) {
19609
19750
  content: [{ type: "text", text: `Arquivo criado: ${params.path}` }]
19610
19751
  };
19611
19752
  }));
19612
- server.tool("vaultAppendContent", "Adiciona conteúdo ao final de um arquivo existente no vault.", {
19753
+ server.tool("vaultAppendContent", [
19754
+ "Adiciona conteúdo ao final de um arquivo existente no vault.",
19755
+ "",
19756
+ "Se não souber o path exato do arquivo, use vaultListFiles para navegar pelas pastas e encontrá-lo."
19757
+ ].join(`
19758
+ `), {
19613
19759
  path: exports_external.string().describe("Caminho do arquivo no vault"),
19614
19760
  content: exports_external.string().describe("Conteúdo a adicionar ao final")
19615
19761
  }, safeTool(async (params) => {
@@ -19885,10 +20031,16 @@ function registerPeriodicTools(server, client) {
19885
20031
  }
19886
20032
  // src/index.ts
19887
20033
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
20034
+ if (process.argv.includes("--setup")) {
20035
+ const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), exports_setup));
20036
+ await runSetup2();
20037
+ process.exit(0);
20038
+ }
19888
20039
  var server = new McpServer({
19889
20040
  name: "obsidian-mcp",
19890
20041
  version: "1.0.0"
19891
20042
  });
20043
+ var config2 = getConfig();
19892
20044
  var client = new ObsidianClient(config2.baseUrl, config2.apiKey);
19893
20045
  registerVaultTools(server, client);
19894
20046
  registerCommandsTools(server, client);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leonardocrdso/obsidian-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for Obsidian — full Local REST API integration with 22 tools",
5
5
  "type": "module",
6
6
  "main": "build/index.js",