@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.
- package/README.md +30 -8
- package/build/index.js +164 -12
- 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/)
|
|
10
|
+
- Node.js 18+ ou [Bun](https://bun.sh/)
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Configuração
|
|
13
|
+
|
|
14
|
+
### 1. Setup interativo (recomendado)
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
|
|
17
|
+
npx @leonardocrdso/obsidian-mcp --setup
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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 (
|
|
19461
|
-
|
|
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
|
-
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
|
|
19467
|
-
|
|
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",
|
|
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",
|
|
19600
|
-
|
|
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",
|
|
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);
|