Obsidian MCP Server

Gerencia notas e arquivos em um vault do Obsidian. Requer o plugin Obsidian Local REST API.

Documentação

obsidian-mcp-server

Leia, escreva, pesquise e edite cirurgicamente notas, tags e frontmatter do cofre Obsidian via MCP. STDIO ou Streamable HTTP.

14 Ferramentas • 3 Recursos

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Visão geral

Leia, escreva, pesquise e edite cirurgicamente notas do cofre Obsidian — seções, frontmatter, tags — por meio do plugin Local REST API, com permissões de leitura/escrita com escopo de pasta incorporadas. Executa como um processo stdio ou um servidor HTTP Streamable local.

Ferramentas

FerramentaDescrição
obsidian_get_noteLeia uma nota como conteúdo bruto, forma estruturada completa (conteúdo + frontmatter + tags + stat, com links de saída opcionais), mapa estrutural do documento ou uma única seção.
obsidian_list_notesListe notas e subdiretórios sob um caminho do cofre. Caminhada recursiva (profundidade padrão 2, profundidade máxima 20; limite de 1000 entradas) com filtros opcionais extension e nameRegex.
obsidian_list_tagsListe tags do cofre com contagens de uso, incluindo pais hierárquicos. Ordenado por contagem decrescente e limitado a limit (padrão 200, máximo 10000), com o restante retido divulgado. nameRegex e minCount opcionais restringem o conjunto primeiro.
obsidian_list_commandsListe comandos da paleta de comandos do Obsidian, opcionalmente filtrados por nameRegex no nome de exibição. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true (emparelhado com obsidian_execute_command).
obsidian_search_notesPesquise no cofre por texto, JSONLogic ou Omnisearch classificado por BM25 (quando o plugin está acessível). Os resultados paginam via cursores opacos.
obsidian_write_noteCrie uma nota, substitua uma única seção no lugar ou — com overwrite: true — sobrescreva um arquivo existente. Recusa gravações de arquivo inteiro em um caminho existente por padrão.
obsidian_append_to_noteAcrescente conteúdo a uma nota. Sem section, cria o arquivo se estiver ausente. Com section, acrescenta a um cabeçalho, bloco ou campo de frontmatter específico (o arquivo deve existir).
obsidian_patch_noteappend / prepend / replace cirúrgico contra um cabeçalho, referência de bloco ou campo de frontmatter.
obsidian_replace_in_noteSubstituição de pesquisa dentro de uma única nota, com escopo no corpo por padrão. Correspondência literal ou regex com opções de palavra inteira, flexibilidade de espaços em branco e sensibilidade a maiúsculas/minúsculas; suporta substituição de grupo de captura.
obsidian_manage_frontmatterget / set / delete atômico em uma única chave de frontmatter.
obsidian_manage_tagsAdicione, remova ou liste tags. Padrão para o array tags: do frontmatter; location: 'inline' ou 'both' opta por modificar o corpo da nota.
obsidian_delete_noteExclua permanentemente uma nota. Sempre pede confirmação ao usuário primeiro — a chamada é respondida com uma solicitação de confirmação e repetida com a resposta.
obsidian_open_in_uiAbra um arquivo na interface do aplicativo Obsidian, com alternâncias failIfMissing e newLeaf.
obsidian_execute_commandExecute um comando da paleta de comandos do Obsidian por ID. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true.

Recursos

RecursoDescrição
obsidian://vault/{+path}Uma nota no cofre — conteúdo, frontmatter, tags e metadados do arquivo.
obsidian://tagsTodas as tags encontradas no cofre, com contagens de uso (snapshot completo).
obsidian://statusAcessibilidade do servidor, status de autenticação, informações de versão do plugin/Obsidian e extensões de API registradas.

Dados de notas do cofre e tags também são acessíveis via ferramentas — obsidian_get_note para obsidian://vault/{+path}, obsidian_list_tags para obsidian://tags (classificado por contagem e limitado, ao contrário do snapshot bruto do recurso). obsidian://status não tem equivalente de ferramenta. Os recursos existem para clientes que preferem anexar uma nota ou snapshot do cofre a uma conversa.

Referência de capacidades

obsidian_get_note ferramenta

  • format: "content" | "full" | "document-map" | "section" seleciona a projeção; full aceita includeLinks: true para links wiki/markdown de saída (somente internos ao cofre — URLs externas são filtradas)
  • Endereçado pelo path do cofre, o arquivo active ou uma nota periodic (daily / weekly / monthly / quarterly / yearly)
  • Seções de cabeçalho usam sintaxe Parent::Child e encontram cabeçalhos da mesma forma que o mapa do documento — cabeçalhos setext (sublinhados com === ou ---) contam, linhas # dentro de um item de lista, bloco HTML ou cerca não contam — então cada caminho de cabeçalho que o mapa lista é lido de volta como ele mesmo, no mesmo intervalo que uma gravação de seção edita; um nome de folha simples correspondendo a vários cabeçalhos, ou um caminho completo que se repete na nota, retorna a primeira correspondência e lista cada caminho conflitante em candidates
  • Resolução path tolerante: um caminho com maiúsculas/minúsculas incompatíveis tenta novamente com o nome de arquivo canônico, uma correspondência ambígua de maiúsculas/minúsculas falha com Conflict, e um NotFound carrega sugestões Did you mean: …? quando existem correspondências próximas
  • Erros tipados incluem note_missing, path_forbidden, no_active_file, periodic_unsupported / periodic_disabled e path_traversal

obsidian_list_notes ferramenta

  • Caminhada recursiva de path (padrão raiz do cofre); depth 1–20 (padrão 2 = alvo mais filhos imediatos)
  • Filtros opcionais extension e nameRegex (≤256 caracteres, sem quantificadores aninhados); um diretório que falha nameRegex é ignorado sem recursar nele
  • Limite rígido de 1000 entradas por chamada — excluded.reason: "entry_cap" sinaliza uma caminhada truncada; restrinja path ou os filtros para ver o restante
  • truncated: true por diretório marca entradas cortadas pelo limite de profundidade ou pela política de caminho

obsidian_list_tags ferramenta

  • Contagens de tags em todo o cofre, incluindo pais hierárquicos (work/tasks contribui tanto para work quanto para work/tasks)
  • Ordenado por contagem decrescente, limitado a limit (padrão 200, máximo 10000); nameRegex e minCount opcionais restringem o conjunto candidato antes da classificação
  • Relata truncated / shown / cap quando o limite reteve resultados
  • Não restringido por OBSIDIAN_READ_PATHS — nomes de tags (nunca conteúdos de notas) podem surgir de fora do escopo de leitura

obsidian_list_commands ferramenta

  • Lista IDs e nomes de exibição da paleta de comandos do Obsidian; nameRegex opcional filtra no nome de exibição
  • Opt-in via OBSIDIAN_ENABLE_COMMANDS=true — ausente de tools/list quando não definido
  • Parceiro de descoberta para obsidian_execute_command

obsidian_search_notes ferramenta

  • mode: "text" | "jsonlogic" sempre; "omnisearch" é adicionado ao esquema somente quando o servidor HTTP do plugin Omnisearch está acessível na inicialização (reinicie para re-testar)
  • text — tokens divididos por espaços em branco, todos obrigatórios, cada um correspondido sem diferenciar maiúsculas/minúsculas como substring (aspas são literais, então não há operador de frase), com janelas de contexto de tamanho contextLength (padrão 100) e um pathPrefix opcional; tokens dentro de 2 × contextLength um do outro, como palavras de uma frase, compartilham um local de correspondência; jsonlogic — uma árvore JSONLogic com caminhos var em path / content / frontmatter.<key> / tags / stat.{ctime,mtime,size}, além de operadores glob / regexp que aceitam [PATTERN, VALUE]; omnisearch — classificado por BM25, frases entre aspas, filtros -exclusion, path: / ext:, tolerância a erros de digitação, PDF/OCR via Text Extractor, limite rígido de 50 resultados upstream (truncated: true quando provavelmente atingido)
  • Paginação por cursor — omita cursor para a primeira página, passe nextCursor da resposta anterior; resultados em modo texto também recortam para maxMatchesPerHit locais de correspondência (padrão 10), sinalizados com truncated / totalMatches
  • Sem ferramenta dedicada de backlinks — expresse "o que linka aqui" via jsonlogic: {"regexp": ["\\[\\[Target Note(\\||#|\\]\\])", {"var": "content"}]}

obsidian_write_note ferramenta

  • Sem section — gravação de arquivo inteiro; recusa sobrescrever uma nota existente a menos que overwrite: true (conflito file_exists caso contrário, nomeando as ferramentas de edição cirúrgica como alternativa)
  • Com section — PATCH-com-substituição contra um alvo de cabeçalho/bloco/frontmatter, deixando o restante do arquivo intocado (overwrite é ignorado); uma folha de cabeçalho simples compartilhada por vários cabeçalhos falha com ambiguous_section a menos que um deles não tenha cabeçalho pai, que a gravação então visa, e um caminho de cabeçalho completo que se repete na nota falha da mesma forma
  • A saída relata created, além de previousSizeInBytes / currentSizeInBytes em cada chamada para detectar uma sobrescrita acidental ou um caminho digitado incorretamente

obsidian_append_to_note ferramenta

  • Sem section — acrescenta a um arquivo existente, ou o cria com o conteúdo fornecido como corpo inteiro (created: true sinaliza o segundo caso)
  • Com section — acrescenta a um alvo de cabeçalho/bloco/frontmatter; o arquivo deve já existir, e createTargetIfMissing: true traz a própria seção à existência. No plugin v5.0 e posterior, conteúdo acrescentado a um cabeçalho é separado do conteúdo existente da seção por uma linha em branco (exceto um item de lista acrescentado a uma seção que termina em lista e não tem sub-cabeçalhos, que continua essa lista), e um cabeçalho nele deve ficar abaixo do nível da própria seção (heading_outside_section caso contrário)
  • Alvos de referência de bloco concatenam sem separador — inclua uma nova linha inicial em content para um
  • previousSizeInBytes / currentSizeInBytes envolvem cada chamada para detecção de desvio

obsidian_patch_note ferramenta

  • operation: "append" | "prepend" | "replace" contra um cabeçalho, referência de bloco ou campo de frontmatter por chamada; no plugin v5.0 e posterior, conteúdo acrescentado ou prefixado a um cabeçalho é separado do conteúdo existente da seção por uma linha em branco (exceto um item de lista acrescentado a uma seção que termina em lista, ou prefixado a uma que abre com lista, que continua essa lista), e um cabeçalho nele deve ficar abaixo do nível da própria seção (heading_outside_section caso contrário)
  • Alvos de cabeçalho aceitam o caminho completo Parent::Child ou um nome de folha simples; uma folha correspondendo a vários cabeçalhos falha com ambiguous_section e lista os candidatos, a menos que um deles não tenha cabeçalho pai, que o patch então visa; um caminho completo que se repete na nota falha com ambiguous_section também
  • patchOptions: createTargetIfMissing, applyIfContentPreexists (proteção de idempotência — caso contrário content_preexists), trimTargetWhitespace (plugin v4.x apenas; v5.0 e posterior colocam as linhas em branco ao redor do conteúdo inserido por conta própria)

obsidian_replace_in_note ferramenta

  • Uma ou mais replacements, aplicadas em ordem de array, cada uma sobre a saída da anterior
  • scope: "body" (padrão, frontmatter deixado byte-idêntico) | "frontmatter" | "both"; frontmatter/ambos re-analisam o YAML reescrito depois e não escrevem nada se quebrar (frontmatter_invalid)
  • Opções por substituição: useRegex (≤1024 caracteres, sem quantificadores aninhados), caseSensitive, wholeWord (\b…\b em ambos os modos), flexibleWhitespace (somente modo literal), replaceAll (padrão true)
  • perReplacement[] relata bodyCount / frontmatterCount por entrada; totalReplacements os soma

obsidian_manage_frontmatter tool

  • operation: "get" | "set" | "delete" em um único key de frontmatter; set exige um value tipado como JSON (string, número, booleano, array ou objeto)
  • get precisa de acesso de leitura; set / delete precisam do caminho dentro de OBSIDIAN_WRITE_PATHS com OBSIDIAN_READ_ONLY=false
  • set / delete retornam o frontmatter completo após a alteração, além de previousSizeInBytes / currentSizeInBytes

obsidian_manage_tags tool

  • operation: "add" | "remove" | "list"; location: "frontmatter" (padrão, array canônico de tags:) | "inline" (corpo #tag, add acrescenta ao final do arquivo) | "both" (reconcilia ambos)
  • A detecção inline ignora código (cercado, indentado e inline), wikilinks ([[...]]), imagens, o destino ou o rótulo de um link markdown (seu texto é lido), blocos e comentários HTML e matemática ($…$, $$…$$), de modo que uma âncora de cabeçalho ou um alias de wikilink nunca seja confundido com uma tag; comentários %% … %% ainda são lidos, assim como o Obsidian os lê
  • Tags inline seguem a gramática do Obsidian: uma tag começa no início da linha, após espaços em branco, após outra tag (#a#b são duas tags) ou logo após marcação como **, _…_, ==, [, o | de uma célula de tabela, <br> ou um escape de \ (**#x** é uma tag; (#x, .#x, a *#x e \#x não são) e percorre letras e dígitos em qualquer script, emoji, _, - e /, com pelo menos um caractere que não seja um dígito ASCII (#1990s, #café, #日本語 e #✅done são tags; #1984 não é)
  • add / remove relatam tags applied vs. skipped além do conjunto completo de tags após a alteração; list ignora o array de tags de entrada

obsidian_delete_note tool

  • Sempre pede confirmação primeiro — a chamada inicial retorna uma solicitação de elicitação informando o tamanho do arquivo em bytes e é repetida com a resposta; recusar falha com cancelled e não emite nenhum DELETE
  • Não há desfazer no nível da API — a recuperação exige a lixeira local do Obsidian
  • Exige um cliente MCP que possa atender a uma ida e volta de elicitação; todas as outras ferramentas funcionam sem isso

obsidian_open_in_ui tool

  • failIfMissing (padrão true) controla abrir-vs-criar: abrir um arquivo existente exige acesso de leitura; abrir um arquivo ausente (com failIfMissing: false) o cria e exige acesso de escrita
  • newLeaf abre em um painel dividido em vez do ativo
  • Mesma resolução de caminho tolerante que obsidian_get_note (fallback de maiúsculas/minúsculas, sugestões de Did you mean); obsidian_delete_note deliberadamente não a recebe — uma operação destrutiva nunca reescreve silenciosamente seu alvo
  • A saída relata createdIfMissing para que o chamador possa saber qual ramo foi executado

obsidian_execute_command tool

  • Despacha um comando da paleta de comandos do Obsidian por commandId (descubra via obsidian_list_commands); executa com a mesma autoridade de uma invocação por teclado
  • Opt-in via OBSIDIAN_ENABLE_COMMANDS=true — ausente de tools/list quando não definido
  • O comportamento depende do comando — alguns são destrutivos (excluir arquivo, fechar cofre), alguns abrem interface

obsidian://vault/{+path} resource

  • O segmento {+path} captura tudo após /vault/, incluindo barras
  • Os caminhos podem ser enviados literalmente ou codificados em percentual — Folder/Test Note.md e Folder/Test%20Note.md resolvem para a mesma nota, assim como nomes não ASCII e um % simples
  • Retorna a mesma forma que obsidian_get_note com format: "full" — conteúdo, frontmatter, tags, stat
  • Controlado por OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS como o equivalente de ferramenta

obsidian://tags resource

  • Snapshot completo do payload upstream de /tags/ — não ordenado, sem limite, inclui pais hierárquicos
  • Não é um espelho de obsidian_list_tags: sem ordem decrescente de contagem, sem limit / nameRegex / minCount

obsidian://status resource

  • Acessibilidade, versão do plugin, authenticated (se o OBSIDIAN_API_KEY configurado foi aceito) e informações do manifesto do plugin
  • apiExtensions[] lista extensões de plugin registradas — verifique local-rest-api-periodic-notes antes de confiar em alvos de periodic no plugin v5.0.2 e posterior
  • Ainda relata acessibilidade quando a chave de API está mal configurada; apenas authenticated reflete a validade da chave

Política de caminhos (permissões com escopo de pasta)

Três variáveis de ambiente opcionais controlam quais caminhos do cofre cada ferramenta pode acessar. Padrão não definido = cofre inteiro para leituras e escritas — compatível com versões anteriores.

ObjetivoConfiguração
Padrão (comportamento atual)todas não definidas
Ler em qualquer lugar, escrever apenas em projects/ e scratch/OBSIDIAN_WRITE_PATHS=projects/,scratch/
Ler apenas public/, escrever apenas public/inbox/OBSIDIAN_READ_PATHS=public/, OBSIDIAN_WRITE_PATHS=public/inbox/
Implantação somente leitura — sem escritas em qualquer lugarOBSIDIAN_READ_ONLY=true

A correspondência é baseada em prefixo com recursão implícita, sem diferenciar maiúsculas de minúsculas, com barras finais normalizadas. projects/ corresponde a projects/a.md, projects/sub/b.md, etc.

Caminhos de escrita são implicitamente legíveis — você não pode editar de forma sensata o que não pode ver. Portanto, uma leitura passa quando o alvo corresponde a READ_PATHS ou WRITE_PATHS.

OBSIDIAN_READ_ONLY=true entra em curto-circuito antes das verificações de caminho — toda ferramenta de escrita e o par da paleta de comandos são envolvidos com disabledTool() na inicialização (ausente de tools/list), e qualquer escrita que ainda chegue ao serviço é negada em tempo de execução, independentemente de WRITE_PATHS.

As negações são tipadas como path_forbidden (código JSON-RPC Forbidden) com o escopo ativo ecoado de volta em data.recovery.hint e data.activeScope, para que o LLM possa se autocorrigir sem inspecionar os logs do servidor. Os resultados de pesquisa de obsidian_search_notes são filtrados contra READ_PATHS silenciosamente — exibir um indicador de "ocultamos N resultados" derrotaria o controle.

A listagem de tags abrange todo o cofre. obsidian_list_tags e o recurso obsidian://tags agregam nomes de tags em todo o cofre e não são restringidos por OBSIDIAN_READ_PATHS — eles não recebem caminho para controlar, portanto, nomes de tags (nunca conteúdos de notas) de fora do escopo de leitura podem aparecer.

O banner de inicialização registra o escopo ativo para que os operadores possam verificar sua configuração na inicialização.

Recursos

Construído sobre @cyanheads/mcp-ts-core: transportes stdio e Streamable HTTP, autenticação plugável (none / jwt / oauth), armazenamento substituível (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), registro estruturado com rastreamento OpenTelemetry opcional.

Específico do Obsidian:

  • Envolve o plugin Obsidian Local REST API — cliente tipado, mapeamento de erros determinístico
  • Edição ciente de seções em cabeçalhos, referências de bloco e campos de frontmatter via operações PATCH-com-alvo
  • Pesquisa em três modos — texto, JSONLogic e (quando acessível) Omnisearch classificado por BM25 — paginada por cursor conforme a especificação MCP 2025-11-25
  • Reconciliação de tags em ambas as representações: array de frontmatter tags: e sintaxe inline #tag
  • Permissões de leitura/escrita com escopo de pasta via OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS e um interruptor global OBSIDIAN_READ_ONLY; par da paleta de comandos opt-in controlado por OBSIDIAN_ENABLE_COMMANDS. instructions no nível do servidor em initialize relatam a política ativa ao chamador

Saída amigável para agentes:

  • Erros guiados por recuperação — toda falha declarada carrega um reason, um código JSON-RPC e um recovery.hint escrito para esse caso, de modo que uma rejeição nomeia o que fazer em seguida em vez de apenas o que quebrou
  • Autocorreção por delta de tamanho — toda ferramenta mutável retorna previousSizeInBytes / currentSizeInBytes, para que um chamador possa detectar uma sobrescrita acidental ou comportamento upstream inesperado sem uma leitura de acompanhamento
  • Ambiguidade exposta estruturalmente — um nome de folha de cabeçalho compartilhado por vários cabeçalhos retorna candidates em vez de escolher silenciosamente um; operações de tag relatam applied vs. skipped para que um chamador veja exatamente o que mudou
  • Contratos de saída discriminados — format em obsidian_get_note, operation em obsidian_manage_frontmatter e obsidian_manage_tags, mode em obsidian_search_notes — chamadores ramificam em campos tipados em vez de analisar texto

Começando

Adicione o seguinte ao arquivo de configuração do seu cliente MCP. O plugin Obsidian Local REST API deve estar instalado e habilitado no seu cofre — veja Pré-requisitos.

{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["obsidian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OBSIDIAN_API_KEY": "your-local-rest-api-key"
      }
    }
  }
}

Ou com npx (sem Bun necessário):

{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "obsidian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OBSIDIAN_API_KEY": "your-local-rest-api-key"
      }
    }
  }
}

Ou com Docker:

{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "MCP_LOG_LEVEL=info",
        "-e", "OBSIDIAN_API_KEY=your-local-rest-api-key",
        "ghcr.io/cyanheads/obsidian-mcp-server:latest"
      ]
    }
  }
}

O OBSIDIAN_BASE_URL padrão (http://127.0.0.1:27123) aponta para o loopback do próprio contêiner, não para o seu host — adicione -e OBSIDIAN_BASE_URL=http://host.docker.internal:27123 (Docker Desktop) ou execute com --network host (Linux) para que o contêiner possa alcançar o plugin.

Para Streamable HTTP, defina o transporte e inicie o servidor. Variáveis de ambiente inline funcionam para execuções únicas; para uso repetido, copie os valores para .env (veja .env.example) e execute bun run start:http.

MCP_TRANSPORT_TYPE=http OBSIDIAN_API_KEY=... bun run start:http
# Server listens at http://127.0.0.1:3010/mcp by default

Pré-requisitos

  • Bun v1.4.0 ou superior (ou Node.js v24+).
  • O plugin Obsidian Local REST API, v4.0.0 ou posterior, instalado e habilitado no seu cofre. Gere uma chave de API em Configurações → Plugins da Comunidade → Local REST API e copie-a para OBSIDIAN_API_KEY. Escritas direcionadas a seções e o mapa de documentos falam markdown-patch 2.0 para o plugin v5.0 e posterior e o formato 1.x para v4.x; o servidor lê a versão do plugin uma vez e escolhe o formato por conta própria. Duas escritas de linha de tabela (contentType: "json") que o markdown-patch 2.0 não pode expressar saem como 1.x também no v5.x: linhas escritas sob um cabeçalho e linhas escritas por meio de um ID de bloco em sua própria linha abaixo da tabela. O plugin v6.0 remove o 1.x, então no v6.0 essas duas formas falham; direcione a tabela por um ID em sua última linha.
  • Alvos de nota periódica (target: { "type": "periodic" }) funcionam em toda essa faixa: nativamente no plugin v5.0.1 e anterior, e no v5.0.2 e posterior — que moveu as rotas de /periodic/ para fora do plugin — uma vez que a extensão complementar periodic-notes API extension esteja instalada. Sem essa extensão no v5.0.2+, alvos periódicos falham com um erro periodic_unsupported nomeando-a; obsidian://status lista as extensões registradas se você quiser verificar primeiro. Todos os outros tipos de alvo não são afetados.
  • Um cliente MCP que possa responder a uma solicitação de entrada (elicitação). obsidian_delete_note sempre pede confirmação antes de excluir, então um cliente sem esse suporte pode ler e escrever notas, mas não pode excluir uma.
  • Este servidor usa como padrão http://127.0.0.1:27123 por simplicidade. Habilite "Servidor não criptografado (HTTP)" nas configurações do plugin para usá-lo. Para usar a porta HTTPS sempre ativa, defina OBSIDIAN_BASE_URL=https://127.0.0.1:27124; o certificado autoassinado do plugin é tratado por OBSIDIAN_VERIFY_SSL=false (o padrão), que relaxa a verificação para as solicitações deste servidor apenas para esse endpoint.

Instalação

  1. Clone o repositório:

    git clone https://github.com/cyanheads/obsidian-mcp-server.git
    
  2. Navegue para o diretório:

    cd obsidian-mcp-server
    
  3. Instale as dependências:

    bun install
    
  4. Configure o ambiente:

    cp .env.example .env
    # edit .env and set OBSIDIAN_API_KEY
    

Configuração

VariávelDescriçãoPadrão
OBSIDIAN_API_KEYObrigatório. Token Bearer para o plugin Obsidian Local REST API.—
OBSIDIAN_BASE_URLURL base do plugin Local REST API. Use https://127.0.0.1:27124 para a porta HTTPS sempre ativa (certificado autoassinado). Uma barra final é removida na inicialização. Quando nada responde lá (Obsidian fechado, plugin desabilitado, host ou porta errados), as chamadas falham com obsidian_unreachable — um GET, PUT ou DELETE após suas tentativas, qualquer outra solicitação na primeira tentativa.http://127.0.0.1:27123
OBSIDIAN_VERIFY_SSLVerifica o certificado TLS. Padrão false porque o plugin usa um certificado autoassinado. A flexibilização é aplicada por solicitação, apenas a um https: OBSIDIAN_BASE_URL — todas as outras conexões HTTPS que o processo faz ainda verificam normalmente, tanto no Bun quanto no Node. Com true, um certificado que o runtime não confia faz todas as chamadas falharem na primeira tentativa com certificate_rejected.false
OBSIDIAN_REQUEST_TIMEOUT_MSTempo limite por solicitação em milissegundos.30000
OBSIDIAN_ENABLE_COMMANDSSinalizador opcional para o par da paleta de comandos (obsidian_list_commands + obsidian_execute_command). Desativado por padrão — os comandos do Obsidian são opacos e podem ser destrutivos.false
OBSIDIAN_READ_PATHSLista de permissões de pastas relativas ao cofre, separadas por vírgula, para operações de leitura. Baseada em prefixo com recursão implícita; insensível a maiúsculas/minúsculas; barras finais normalizadas. Não definido = cofre completo. Caminhos de escrita são implicitamente legíveis.não definido
OBSIDIAN_WRITE_PATHSLista de permissões de pastas relativas ao cofre, separadas por vírgula, para operações de escrita. Mesma sintaxe que OBSIDIAN_READ_PATHS. Não definido = cofre completo.não definido
OBSIDIAN_READ_ONLYInterruptor global de desligamento. Quando true, nega toda escrita independentemente de OBSIDIAN_WRITE_PATHS e suprime o par OBSIDIAN_ENABLE_COMMANDS (comandos podem mutar).false
OBSIDIAN_OMNISEARCH_URLURL de substituição para o servidor HTTP do plugin Omnisearch. Quando não definido, deriva do host OBSIDIAN_BASE_URL com porta 51361 (recorrendo a http://localhost:51361). Verificado uma vez na inicialização — se acessível, o modo omnisearch é adicionado a obsidian_search_notes; caso contrário, é omitido do esquema da ferramenta. Reinicie o servidor para verificar novamente.derivado
MCP_TRANSPORT_TYPETransporte: stdio ou http.stdio
MCP_HTTP_HOSTHost para o servidor HTTP.127.0.0.1
MCP_HTTP_PORTPorta para o servidor HTTP.3010
MCP_HTTP_ENDPOINT_PATHCaminho do endpoint para o manipulador JSON-RPC./mcp
MCP_SESSION_MODEGerenciamento de sessão para o transporte HTTP: stateless, stateful ou auto. Padrão stateful aqui — obsidian_delete_note confirma por meio de uma rodada de elicitação, e sob stateless a rodada de um cliente da era 2025 é recusada (client_capability_missing).stateful
MCP_PUBLIC_URLSubstituição de origem pública para implantações de proxy reverso com terminação TLS (página inicial, Server Card, metadados RFC 9728).não definido
MCP_AUTH_MODEModo de autenticação: none, jwt ou oauth.none
MCP_AUTH_SECRET_KEYObrigatório quando MCP_AUTH_MODE=jwt. Segredo compartilhado com ≥32 caracteres usado para verificar JWTs recebidos.—
MCP_AUTH_DISABLE_SCOPE_CHECKSQuando true, ignora a aplicação de escopo por ferramenta após a verificação de presença do contexto de autenticação. A assinatura do token, público, emissor e validação de expiração permanecem intactos. Use apenas quando uma declaração personalizada não puder ser injetada e combine com OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS / OBSIDIAN_READ_ONLY para controle de acesso. Um WARNING é registrado na inicialização sempre que o bypass está ativo.false
MCP_LOG_LEVELNível de log (RFC 5424).info
LOGS_DIRDiretório para arquivos de log (somente Node.js).<project-root>/logs
OTEL_ENABLEDHabilita instrumentação OpenTelemetry (spans, métricas, logs de conclusão).false

Veja .env.example para a lista completa de substituições opcionais.

Executando o servidor

Desenvolvimento local

  • Compilar e executar a versão de produção:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Executar verificações e testes:

    bun run devcheck   # Lint, format, typecheck, security, changelog sync
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    

Docker

docker build -t obsidian-mcp-server .
docker run --rm -e OBSIDIAN_API_KEY=your-key -p 3010:3010 obsidian-mcp-server

O Dockerfile usa como padrão transporte HTTP, modo de sessão com estado (necessário para a rodada de confirmação obsidian_delete_note) e registra logs em /var/log/obsidian-mcp-server. Aponte OBSIDIAN_BASE_URL para http://host.docker.internal:27123 (Docker Desktop) ou execute com --network host (Linux) para que o contêiner alcance o plugin no seu host. Dependências pares do OpenTelemetry são instaladas por padrão — compile com --build-arg OTEL_ENABLED=false para omiti-las.

A imagem vincula a 0.0.0.0 dentro do contêiner (necessário para o mapeamento de porta do Docker). Para qualquer implantação acessível além da sua própria máquina, defina MCP_AUTH_MODE=jwt (com MCP_AUTH_SECRET_KEY) ou oauth — caso contrário, o ouvinte encaminha seu OBSIDIAN_API_KEY para o cofre em nome de cada chamador.

Estrutura do projeto

DiretórioFinalidade
src/index.tsPonto de entrada createApp() — registra ferramentas/recursos e inicializa o serviço do Obsidian.
src/configAnálise de variáveis de ambiente específicas do servidor (OBSIDIAN_*) com Zod.
src/services/obsidianCliente Local REST API, operações de frontmatter, extrator de seções, tipos de domínio.
src/mcp-server/toolsDefinições de ferramentas (*.tool.ts) e esquemas de entrada compartilhados.
src/mcp-server/resourcesDefinições de recursos (*.resource.ts).
src/mcp-server/promptsDefinições de prompts (atualmente vazio — a forma CRUD/busca não se beneficia de um modelo estruturado).
tests/Testes Vitest espelhando src/.
docs/Especificação OpenAPI upstream para o plugin Local REST API e o tree.md gerado.
changelog/Notas de versão por versão; CHANGELOG.md é o rollup regenerado.

Guia de desenvolvimento

Veja CLAUDE.md para diretrizes de desenvolvimento e regras arquiteturais. A versão curta:

  • Manipuladores lançam, o framework captura — sem try/catch na lógica da ferramenta
  • Use ctx.log para registro com escopo de solicitação, ctx.state para armazenamento com escopo de locatário
  • Registre novas ferramentas e recursos por meio dos barris em src/mcp-server/*/definitions/index.ts
  • Encapsule chamadas de API externas: valide bruto → normalize para tipo de domínio → retorne esquema de saída; nunca invente campos ausentes

Contribuindo

Bugs, solicitações de recursos e lacunas de documentação pertencem a uma issue — veja CONTRIBUTING.md para o que torna uma acionável, e CODE_OF_CONDUCT.md para como trabalhamos juntos. Relatórios de segurança passam por SECURITY.md, nunca por uma issue pública.

Execute verificações e testes antes de enviar:

bun run devcheck
bun run test

Licença

Apache-2.0 — veja LICENSE para detalhes.