Obsidian MCP Server

Gestiona notas y archivos en un vault de Obsidian. Requiere el plugin Obsidian Local REST API.

Documentación

obsidian-mcp-server

Lee, escribe, busca y edita quirúrgicamente notas, etiquetas y frontmatter de tu bóveda de Obsidian mediante MCP. STDIO o HTTP Streamable.

14 herramientas • 3 recursos

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Descripción general

Lee, escribe, busca y edita quirúrgicamente notas de tu bóveda de Obsidian — secciones, frontmatter, etiquetas — a través del plugin Local REST API, con permisos de lectura/escritura limitados por carpeta integrados. Se ejecuta como proceso stdio o como servidor HTTP Streamable local.

Herramientas

HerramientaDescripción
obsidian_get_noteLee una nota como contenido bruto, forma estructurada completa (contenido + frontmatter + etiquetas + stat, con enlaces salientes opcionales), mapa documental estructural o una sola sección.
obsidian_list_notesLista notas y subdirectorios bajo una ruta de la bóveda. Recorrido recursivo (profundidad predeterminada 2, máxima 20; límite de 1000 entradas) con filtros opcionales extension y nameRegex.
obsidian_list_tagsLista las etiquetas de la bóveda con recuentos de uso, incluidos los padres jerárquicos. Ordenadas por recuento descendente y limitadas a limit (predeterminado 200, máximo 10000), con el resto retenido divulgado. Los nameRegex y minCount opcionales reducen primero el conjunto.
obsidian_list_commandsLista los comandos de la paleta de comandos de Obsidian, opcionalmente filtrados por nameRegex en el nombre mostrado. Opt-in mediante OBSIDIAN_ENABLE_COMMANDS=true (emparejado con obsidian_execute_command).
obsidian_search_notesBusca en la bóveda por texto, JSONLogic u Omnisearch clasificado por BM25 (cuando el plugin es accesible). Los resultados se paginan mediante cursores opacos.
obsidian_write_noteCrea una nota, reemplaza una sola sección en su lugar o — con overwrite: true — sobrescribe un archivo existente. Rechaza escrituras de archivo completo contra una ruta existente por defecto.
obsidian_append_to_noteAñade contenido a una nota. Sin section, crea el archivo si falta. Con section, añade a un encabezado, bloque o campo de frontmatter específico (el archivo debe existir).
obsidian_patch_noteappend / prepend / replace quirúrgico contra un encabezado, referencia de bloque o campo de frontmatter.
obsidian_replace_in_noteReemplazo de búsqueda dentro de una sola nota, limitado al cuerpo por defecto. Coincidencia literal o regex con opciones de palabra completa, flexibilidad de espacios en blanco y sensibilidad a mayúsculas; admite reemplazo con grupos de captura.
obsidian_manage_frontmatterget / set / delete atómico sobre una sola clave de frontmatter.
obsidian_manage_tagsAñade, elimina o lista etiquetas. Por defecto usa el array tags: del frontmatter; location: 'inline' o 'both' opta por mutar el cuerpo de la nota.
obsidian_delete_noteElimina permanentemente una nota. Siempre pide confirmación al usuario primero: la llamada se responde con una solicitud de confirmación y se reintenta con la respuesta.
obsidian_open_in_uiAbre un archivo en la interfaz de la aplicación Obsidian, con alternancias failIfMissing y newLeaf.
obsidian_execute_commandEjecuta un comando de la paleta de comandos de Obsidian por ID. Opt-in mediante OBSIDIAN_ENABLE_COMMANDS=true.

Recursos

RecursoDescripción
obsidian://vault/{+path}Una nota en la bóveda: contenido, frontmatter, etiquetas y metadatos del archivo.
obsidian://tagsTodas las etiquetas encontradas en la bóveda, con recuentos de uso (instantánea completa).
obsidian://statusAccesibilidad del servidor, estado de autenticación, información de versión del plugin/Obsidian y extensiones de API registradas.

Los datos de notas de la bóveda y etiquetas también son accesibles mediante herramientas: obsidian_get_note para obsidian://vault/{+path}, obsidian_list_tags para obsidian://tags (clasificadas por recuento y limitadas, a diferencia de la instantánea bruta del recurso). obsidian://status no tiene equivalente de herramienta. Los recursos existen para clientes que prefieren adjuntar una nota o instantánea de la bóveda a una conversación.

Referencia de capacidades

obsidian_get_note herramienta

  • format: "content" | "full" | "document-map" | "section" selecciona la proyección; full acepta includeLinks: true para enlaces wiki/markdown salientes (solo internos de la bóveda: las URL externas se filtran)
  • Direccionada por path de la bóveda, el archivo active o una nota periodic (daily / weekly / monthly / quarterly / yearly)
  • Las secciones de encabezado usan sintaxis Parent::Child y encuentran encabezados como lo hace el mapa documental: los encabezados setext (subrayados con === o ---) cuentan, las líneas # dentro de un elemento de lista, bloque HTML o cerca no cuentan — por lo que cada ruta de encabezado que lista el mapa se lee como sí misma, sobre el mismo tramo que edita una escritura de sección; un nombre de hoja simple que coincide con varios encabezados, o una ruta completa que se repite en la nota, devuelve la primera coincidencia y lista cada ruta en conflicto en candidates
  • Resolución path tolerante: una ruta con mayúsculas/minúsculas incorrectas se reintenta contra el nombre de archivo canónico, una coincidencia ambigua falla con Conflict, y un NotFound lleva sugerencias Did you mean: …? cuando existen coincidencias cercanas
  • Los errores tipados incluyen note_missing, path_forbidden, no_active_file, periodic_unsupported / periodic_disabled y path_traversal

obsidian_list_notes herramienta

  • Recorrido recursivo desde path (raíz de la bóveda por defecto); depth 1–20 (predeterminado 2 = objetivo más hijos inmediatos)
  • Filtros opcionales extension y nameRegex (≤256 caracteres, sin cuantificadores anidados); un directorio que falla nameRegex se omite sin recurrir en él
  • Límite máximo de 1000 entradas por llamada: excluded.reason: "entry_cap" señala un recorrido truncado; reduce path o los filtros para ver el resto
  • truncated: true por directorio marca entradas cortadas por el límite de profundidad o por la política de rutas

obsidian_list_tags herramienta

  • Recuentos de etiquetas en toda la bóveda, incluidos los padres jerárquicos (work/tasks contribuye tanto a work como a work/tasks)
  • Ordenadas por recuento descendente, limitadas a limit (predeterminado 200, máximo 10000); los nameRegex y minCount opcionales reducen el conjunto candidato antes de clasificar
  • Informa truncated / shown / cap cuando el límite retiene resultados
  • No se reduce por OBSIDIAN_READ_PATHS: los nombres de etiquetas (nunca los contenidos de notas) pueden aparecer desde fuera del alcance de lectura

obsidian_list_commands herramienta

  • Lista los IDs y nombres mostrados de la paleta de comandos de Obsidian; el nameRegex opcional filtra por nombre mostrado
  • Opt-in mediante OBSIDIAN_ENABLE_COMMANDS=true — ausente de tools/list cuando no está configurado
  • Socio de descubrimiento para obsidian_execute_command

obsidian_search_notes herramienta

  • mode: "text" | "jsonlogic" siempre; "omnisearch" se añade al esquema solo cuando el servidor HTTP del plugin Omnisearch es accesible al inicio (reinicia para volver a sondear)
  • text — tokens separados por espacios en blanco, todos requeridos, cada uno coincidente sin distinguir mayúsculas/minúsculas como subcadena (las comillas son literales, por lo que no hay operador de frase), con ventanas de contexto de tamaño contextLength (predeterminado 100) y un pathPrefix opcional; los tokens dentro de 2 × contextLength entre sí, como las palabras de una frase, comparten una ubicación de coincidencia; jsonlogic — un árbol JSONLogic con rutas var hacia path / content / frontmatter.<key> / tags / stat.{ctime,mtime,size}, más operadores glob / regexp que toman [PATTERN, VALUE]; omnisearch — clasificado por BM25, frases entre comillas, filtros -exclusion, path: / ext:, tolerancia a errores tipográficos, PDF/OCR mediante Text Extractor, límite máximo de 50 resultados ascendentes (truncated: true cuando es probable que haya más)
  • Paginación por cursor: omite cursor para la primera página, pasa nextCursor de la respuesta anterior; los resultados en modo texto además se recortan a maxMatchesPerHit ubicaciones de coincidencia (predeterminado 10), marcadas con truncated / totalMatches
  • Sin herramienta dedicada de backlinks: expresa "qué enlaza aquí" mediante jsonlogic: {"regexp": ["\\[\\[Target Note(\\||#|\\]\\])", {"var": "content"}]}

obsidian_write_note herramienta

  • Sin section — escritura de archivo completo; se niega a sobrescribir una nota existente a menos que overwrite: true (conflicto file_exists en caso contrario, nombrando las herramientas de edición quirúrgica como alternativa)
  • Con section — PATCH-con-reemplazo contra un objetivo de encabezado/bloque/frontmatter, dejando el resto del archivo intacto (overwrite se ignora); una hoja de encabezado simple compartida por varios encabezados falla con ambiguous_section a menos que uno de ellos no tenga encabezado padre, al que la escritura entonces apunta, y una ruta de encabezado completa que se repite en la nota falla de la misma manera
  • La salida informa created, más previousSizeInBytes / currentSizeInBytes en cada llamada para detectar una sobrescritura accidental o una ruta mal escrita

obsidian_append_to_note herramienta

  • Sin section — añade a un archivo existente, o lo crea con el contenido dado como cuerpo completo (created: true marca el segundo caso)
  • Con section — añade a un objetivo de encabezado/bloque/frontmatter; el archivo ya debe existir, y createTargetIfMissing: true trae la sección misma a la existencia. En el plugin v5.0 y posterior, el contenido añadido a un encabezado se separa del contenido existente de la sección por una línea en blanco (excepto un elemento de lista añadido a una sección que termina en una lista y no tiene subencabezados, que continúa esa lista), y un encabezado en él debe situarse por debajo del nivel de la propia sección (heading_outside_section en caso contrario)
  • Los objetivos de referencia de bloque se concatenan sin separador: incluye un salto de línea inicial en content para uno
  • previousSizeInBytes / currentSizeInBytes encierran cada llamada para detección de desviaciones

obsidian_patch_note herramienta

  • operation: "append" | "prepend" | "replace" contra un encabezado, referencia de bloque o campo de frontmatter por llamada; en el plugin v5.0 y posterior, el contenido añadido o antepuesto a un encabezado se separa del contenido existente de la sección por una línea en blanco (excepto un elemento de lista añadido a una sección que termina en una lista, o antepuesto a una que abre con una lista, que continúa esa lista), y un encabezado en él debe situarse por debajo del nivel de la propia sección (heading_outside_section en caso contrario)
  • Los objetivos de encabezado aceptan la ruta Parent::Child completa o un nombre de hoja simple; una hoja que coincide con varios encabezados falla con ambiguous_section y lista los candidatos, a menos que uno de ellos no tenga encabezado padre, al que el parche entonces apunta; una ruta completa que se repite en la nota falla con ambiguous_section también
  • patchOptions: createTargetIfMissing, applyIfContentPreexists (protección de idempotencia — de lo contrario content_preexists), trimTargetWhitespace (solo plugin v4.x; v5.0 y posterior colocan las líneas en blanco alrededor del contenido insertado por sí mismos)

obsidian_replace_in_note herramienta

  • Uno o más replacements, aplicados en orden de array, cada uno sobre la salida del anterior
  • scope: "body" (predeterminado, frontmatter dejado byte-idéntico) | "frontmatter" | "both"; frontmatter/ambos vuelven a analizar el YAML reescrito después y no escriben nada si se rompe (frontmatter_invalid)
  • Opciones por reemplazo: useRegex (≤1024 caracteres, sin cuantificadores anidados), caseSensitive, wholeWord (\b…\b en ambos modos), flexibleWhitespace (solo modo literal), replaceAll (predeterminado true)
  • perReplacement[] informa bodyCount / frontmatterCount por entrada; totalReplacements los suma

obsidian_manage_frontmatter tool

  • operation: "get" | "set" | "delete" en un solo campo key de frontmatter; set requiere un value con tipo JSON (cadena, número, booleano, arreglo u objeto)
  • get necesita acceso de lectura; set / delete necesitan la ruta dentro de OBSIDIAN_WRITE_PATHS con OBSIDIAN_READ_ONLY=false
  • set / delete devuelven el frontmatter completo después del cambio más previousSizeInBytes / currentSizeInBytes

obsidian_manage_tags tool

  • operation: "add" | "remove" | "list"; location: "frontmatter" (predeterminado, arreglo canónico de tags:) | "inline" (cuerpo #tag, add agrega al final del archivo) | "both" (concilia ambos)
  • La detección en línea omite código (delimitado, indentado y en línea), wikilinks ([[...]]), imágenes, el destino o la etiqueta de un enlace Markdown (su texto se lee), bloques y comentarios HTML, y matemáticas ($…$, $$…$$), por lo que un ancla de encabezado o un alias de wikilink nunca se confunde con una etiqueta; los comentarios %% … %% aún se leen, tal como los lee Obsidian
  • Las etiquetas en línea siguen la gramática de Obsidian: una etiqueta comienza al inicio de la línea, después de espacios en blanco, después de otra etiqueta (#a#b son dos etiquetas), o justo después de marcado como **, _…_, ==, [, el | de una celda de tabla, <br>, o un escape de \ (**#x** es una etiqueta; (#x, .#x, a *#x y \#x no lo son) y continúa con letras y dígitos en cualquier escritura, emojis, _, - y /, con al menos un carácter que no sea un dígito ASCII (#1990s, #café, #日本語 y #✅done son etiquetas; #1984 no lo es)
  • add / remove informan etiquetas applied vs. skipped más el conjunto completo de tags después del cambio; list ignora el arreglo de tags de entrada

obsidian_delete_note tool

  • Siempre pide confirmación primero: la llamada inicial devuelve una solicitud de obtención que indica el tamaño del archivo en bytes, y se reintenta con la respuesta; rechazar falla con cancelled y no emite ningún DELETE
  • No hay deshacer a nivel de API: la recuperación requiere la papelera local de Obsidian
  • Requiere un cliente MCP que pueda manejar un ciclo de ida y vuelta de obtención; todas las demás herramientas funcionan sin uno

obsidian_open_in_ui tool

  • failIfMissing (predeterminado true) controla abrir-vs-crear: abrir un archivo existente necesita acceso de lectura, abrir uno faltante (con failIfMissing: false) lo crea y necesita acceso de escritura
  • newLeaf abre en un panel dividido en lugar del activo
  • Misma resolución de ruta indulgente que obsidian_get_note (respaldo de mayúsculas, sugerencias de Did you mean); obsidian_delete_note deliberadamente no la recibe: una operación destructiva nunca reescribe silenciosamente su objetivo
  • La salida informa createdIfMissing para que el llamador pueda saber qué rama se ejecutó

obsidian_execute_command tool

  • Despacha un comando de la paleta de comandos de Obsidian por commandId (descúbralo mediante obsidian_list_commands); se ejecuta con la misma autoridad que una invocación de teclado
  • Opt-in mediante OBSIDIAN_ENABLE_COMMANDS=true — ausente de tools/list cuando no está configurado
  • El comportamiento depende del comando: algunos son destructivos (eliminar archivo, cerrar bóveda), algunos abren interfaz de usuario

obsidian://vault/{+path} resource

  • El segmento {+path} captura todo después de /vault/, incluidas las barras
  • Las rutas pueden enviarse literalmente o con codificación porcentual: Folder/Test Note.md y Folder/Test%20Note.md se resuelven a la misma nota, al igual que los nombres no ASCII y un % simple
  • Devuelve la misma forma que obsidian_get_note con format: "full" — contenido, frontmatter, etiquetas, stat
  • Controlado por OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS como el equivalente de herramienta

obsidian://tags resource

  • Instantánea completa de la carga útil de /tags/ ascendente — sin ordenar, sin límite, incluye padres jerárquicos
  • No es un espejo de obsidian_list_tags: sin orden descendente por recuento, sin limit / nameRegex / minCount

obsidian://status resource

  • Accesibilidad, versión del plugin, authenticated (si el OBSIDIAN_API_KEY configurado fue aceptado) e información del manifiesto del plugin
  • apiExtensions[] enumera las extensiones de plugin registradas: verifique local-rest-api-periodic-notes antes de confiar en objetivos de periodic en el plugin v5.0.2 y posteriores
  • Aún informa accesibilidad cuando la clave API está mal configurada; solo authenticated refleja la validez de la clave

Política de rutas (permisos limitados por carpeta)

Tres variables de entorno opcionales controlan qué rutas de bóveda puede apuntar cada herramienta. Predeterminado sin configurar = bóveda completa tanto para lecturas como para escrituras — compatible con versiones anteriores.

ObjetivoConfiguración
Predeterminado (comportamiento actual)todo sin configurar
Leer en todas partes, escribir solo en projects/ y scratch/OBSIDIAN_WRITE_PATHS=projects/,scratch/
Leer solo public/, escribir solo public/inbox/OBSIDIAN_READ_PATHS=public/, OBSIDIAN_WRITE_PATHS=public/inbox/
Implementación de solo lectura — sin escrituras en ningún lugarOBSIDIAN_READ_ONLY=true

La coincidencia se basa en prefijos con recursión implícita, sin distinción de mayúsculas, con barras finales normalizadas. projects/ coincide con projects/a.md, projects/sub/b.md, etc.

Las rutas de escritura son implícitamente legibles — no se puede editar de manera sensata lo que no se puede ver. Por lo tanto, una lectura pasa cuando el objetivo coincide con READ_PATHS o WRITE_PATHS.

OBSIDIAN_READ_ONLY=true se cortocircuita antes de las verificaciones de ruta — cada herramienta de escritura y el par de paleta de comandos están envueltos con disabledTool() al inicio (ausente de tools/list), y cualquier escritura que aún llegue al servicio se deniega en tiempo de ejecución independientemente de WRITE_PATHS.

Las denegaciones se tipan como path_forbidden (código JSON-RPC Forbidden) con el alcance activo reflejado en data.recovery.hint y data.activeScope, para que el LLM pueda autocorregirse sin inspeccionar los registros del servidor. Los resultados de búsqueda de obsidian_search_notes se filtran contra READ_PATHS silenciosamente — mostrar un indicador de "ocultamos N coincidencias" anularía la protección.

El listado de etiquetas es de toda la bóveda. obsidian_list_tags y el recurso obsidian://tags agregan nombres de etiquetas en toda la bóveda y no se limitan por OBSIDIAN_READ_PATHS — no toman ninguna ruta para filtrar, por lo que los nombres de etiquetas (nunca los contenidos de notas) fuera del alcance de lectura pueden aparecer.

El banner de inicio registra el alcance activo para que los operadores puedan verificar su configuración al arrancar.

Características

Construido sobre @cyanheads/mcp-ts-core: transportes stdio y Streamable HTTP, autenticación conectable (none / jwt / oauth), almacenamiento intercambiable (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), registro estructurado con rastreo opcional de OpenTelemetry.

Específico de Obsidian:

  • Envuelve el plugin Obsidian Local REST API — cliente tipado, mapeo de errores determinista
  • Edición consciente de secciones en encabezados, referencias de bloque y campos de frontmatter mediante operaciones PATCH-con-objetivo
  • Búsqueda en tres modos — texto, JSONLogic y (cuando está accesible) Omnisearch clasificado por BM25 — paginada por cursor según la especificación MCP 2025-11-25
  • Reconciliación de etiquetas en ambas representaciones: arreglo de frontmatter tags: y sintaxis en línea #tag
  • Permisos de lectura/escritura limitados por carpeta mediante OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS y un interruptor de apagado global OBSIDIAN_READ_ONLY; par de paleta de comandos opt-in controlado por OBSIDIAN_ENABLE_COMMANDS. instructions a nivel de servidor en initialize informan la política activa al llamador

Salida amigable para agentes:

  • Errores guiados por recuperación — cada fallo declarado lleva un reason, un código JSON-RPC y un recovery.hint escrito para ese caso, de modo que un rechazo nombra qué hacer a continuación en lugar de solo qué se rompió
  • Autocorrección por delta de tamaño — cada herramienta mutante devuelve previousSizeInBytes / currentSizeInBytes, para que un llamador pueda detectar una sobrescritura accidental o un comportamiento ascendente inesperado sin una lectura de seguimiento
  • Ambigüedad expuesta estructuralmente — un nombre de hoja de encabezado compartido por varios encabezados devuelve candidates en lugar de elegir uno silenciosamente; las operaciones de etiquetas informan applied vs. skipped para que un llamador vea exactamente qué cambió
  • Contratos de salida discriminados — format en obsidian_get_note, operation en obsidian_manage_frontmatter y obsidian_manage_tags, mode en obsidian_search_notes — los llamadores ramifican en campos tipados en lugar de analizar texto

Primeros pasos

Agregue lo siguiente a su archivo de configuración del cliente MCP. El plugin Obsidian Local REST API debe estar instalado y habilitado en su bóveda — consulte Prerrequisitos.

{
  "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"
      }
    }
  }
}

O con npx (sin necesidad de Bun):

{
  "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"
      }
    }
  }
}

O con 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"
      ]
    }
  }
}

El OBSIDIAN_BASE_URL predeterminado (http://127.0.0.1:27123) apunta al loopback del propio contenedor, no al de su host — agregue -e OBSIDIAN_BASE_URL=http://host.docker.internal:27123 (Docker Desktop) o ejecute con --network host (Linux) para que el contenedor pueda alcanzar el plugin.

Para Streamable HTTP, configure el transporte e inicie el servidor. Las variables de entorno en línea funcionan para ejecuciones únicas; para uso repetido, copie los valores en .env (consulte .env.example) y ejecute 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

Prerrequisitos

  • Bun v1.4.0 o superior (o Node.js v24+).
  • El plugin Obsidian Local REST API, v4.0.0 o posterior, instalado y habilitado en su bóveda. Genere una clave API en Configuración → Plugins de la comunidad → Local REST API y cópiela en OBSIDIAN_API_KEY. Las escrituras dirigidas a secciones y el mapa de documentos hablan markdown-patch 2.0 con el plugin v5.0 y posterior, y el formato 1.x con v4.x; el servidor lee la versión del plugin una vez y elige el formato por sí mismo. Dos escrituras de filas de tabla (contentType: "json") que markdown-patch 2.0 no puede expresar se envían como 1.x también en v5.x: filas escritas bajo un encabezado, y filas escritas mediante un ID de bloque en su propia línea debajo de la tabla. El plugin v6.0 elimina 1.x, por lo que en v6.0 esas dos formas fallan; apunte a la tabla mediante un ID en su última fila en su lugar.
  • Los objetivos de notas periódicas (target: { "type": "periodic" }) funcionan en todo ese rango: nativamente en el plugin v5.0.1 y anteriores, y en v5.0.2 y posteriores — que movió las rutas de /periodic/ fuera del plugin — una vez que la extensión complementaria periodic-notes API extension esté instalada. Sin esa extensión en v5.0.2+, los objetivos periódicos fallan con un error periodic_unsupported que la nombra; obsidian://status enumera las extensiones registradas si desea verificar primero. Todos los demás tipos de objetivos no se ven afectados.
  • Un cliente MCP que pueda responder una solicitud de entrada (obtención). obsidian_delete_note siempre pide confirmación antes de eliminar, por lo que un cliente sin ese soporte puede leer y escribir notas pero no puede eliminar una.
  • Este servidor usa http://127.0.0.1:27123 de forma predeterminada por simplicidad. Habilite "Servidor no cifrado (HTTP)" en la configuración del plugin para usarlo. Para usar el puerto HTTPS siempre activo en su lugar, configure OBSIDIAN_BASE_URL=https://127.0.0.1:27124; el certificado autofirmado del plugin lo maneja OBSIDIAN_VERIFY_SSL=false (el predeterminado), que relaja la verificación para las solicitudes de este servidor solo a ese endpoint.

Instalación

  1. Clone el repositorio:

    git clone https://github.com/cyanheads/obsidian-mcp-server.git
    
  2. Navegue al directorio:

    cd obsidian-mcp-server
    
  3. Instale las dependencias:

    bun install
    
  4. Configure el entorno:

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

Configuración

VariableDescripciónPredeterminado
OBSIDIAN_API_KEYRequerido. Token Bearer para el plugin Obsidian Local REST API.—
OBSIDIAN_BASE_URLURL base del plugin Local REST API. Usa https://127.0.0.1:27124 para el puerto HTTPS siempre activo (certificado autofirmado). La barra final se elimina al inicio. Cuando no hay respuesta allí (Obsidian cerrado, plugin deshabilitado, host o puerto incorrectos), las llamadas fallan con obsidian_unreachable — un GET, PUT o DELETE después de sus reintentos, cualquier otra solicitud en el primer intento.http://127.0.0.1:27123
OBSIDIAN_VERIFY_SSLVerifica el certificado TLS. El valor predeterminado es false porque el plugin usa un certificado autofirmado. La relajación se aplica por solicitud, solo a un https: OBSIDIAN_BASE_URL — cualquier otra conexión HTTPS que el proceso realice sigue verificándose normalmente, tanto en Bun como en Node. Con true, un certificado que el runtime no confía hace fallar cada llamada en su primer intento con certificate_rejected.false
OBSIDIAN_REQUEST_TIMEOUT_MSTiempo de espera por solicitud en milisegundos.30000
OBSIDIAN_ENABLE_COMMANDSIndicador opcional para el par de paleta de comandos (obsidian_list_commands + obsidian_execute_command). Desactivado por defecto: los comandos de Obsidian son opacos y pueden ser destructivos.false
OBSIDIAN_READ_PATHSLista de carpetas permitidas relativas al vault, separadas por comas, para operaciones de lectura. Basada en prefijos con recursión implícita; insensible a mayúsculas; barras finales normalizadas. Sin definir = vault completo. Las rutas de escritura son implícitamente legibles.sin definir
OBSIDIAN_WRITE_PATHSLista de carpetas permitidas relativas al vault, separadas por comas, para operaciones de escritura. Misma sintaxis que OBSIDIAN_READ_PATHS. Sin definir = vault completo.sin definir
OBSIDIAN_READ_ONLYInterruptor global de apagado. Cuando true, deniega toda escritura independientemente de OBSIDIAN_WRITE_PATHS y suprime el par OBSIDIAN_ENABLE_COMMANDS (los comandos pueden mutar).false
OBSIDIAN_OMNISEARCH_URLURL de anulación para el servidor HTTP del plugin Omnisearch. Cuando no está definido, se deriva del host de OBSIDIAN_BASE_URL con el puerto 51361 (con respaldo a http://localhost:51361). Se sondea una vez al inicio: si es accesible, el modo omnisearch se agrega a obsidian_search_notes; de lo contrario, se omite del esquema de herramientas. Reinicia el servidor para volver a sondear.derivado
MCP_TRANSPORT_TYPETransporte: stdio o http.stdio
MCP_HTTP_HOSTHost para el servidor HTTP.127.0.0.1
MCP_HTTP_PORTPuerto para el servidor HTTP.3010
MCP_HTTP_ENDPOINT_PATHRuta del endpoint para el manejador JSON-RPC./mcp
MCP_SESSION_MODEManejo de sesiones para el transporte HTTP: stateless, stateful o auto. Aquí el valor predeterminado es stateful — obsidian_delete_note confirma mediante una ronda de elicitación, y bajo stateless la ronda de un cliente de la era 2025 es rechazada (client_capability_missing).stateful
MCP_PUBLIC_URLAnulación de origen público para despliegues con proxy inverso que termina TLS (página de inicio, tarjeta de servidor, metadatos RFC 9728).sin definir
MCP_AUTH_MODEModo de autenticación: none, jwt o oauth.none
MCP_AUTH_SECRET_KEYRequerido cuando MCP_AUTH_MODE=jwt. Secreto compartido de ≥32 caracteres usado para verificar los JWT entrantes.—
MCP_AUTH_DISABLE_SCOPE_CHECKSCuando true, omite la aplicación de alcance por herramienta después de la verificación de presencia del contexto de autenticación. La firma del token, la audiencia, el emisor y la validación de expiración permanecen intactos. Úsalo solo cuando no se pueda inyectar una claim personalizada y combínalo con OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS / OBSIDIAN_READ_ONLY para el control de acceso. Se registra un WARNING al inicio siempre que el bypass esté activo.false
MCP_LOG_LEVELNivel de registro (RFC 5424).info
LOGS_DIRDirectorio para archivos de registro (solo Node.js).<project-root>/logs
OTEL_ENABLEDHabilita instrumentación OpenTelemetry (spans, métricas, registros de finalización).false

Consulta .env.example para la lista completa de anulaciones opcionales.

Ejecutar el servidor

Desarrollo local

  • Compilar y ejecutar la versión de producción:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Ejecutar verificaciones y pruebas:

    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

El Dockerfile usa por defecto transporte HTTP, modo de sesión con estado (requerido para la ronda de confirmación obsidian_delete_note) y registra en /var/log/obsidian-mcp-server. Apunta OBSIDIAN_BASE_URL a http://host.docker.internal:27123 (Docker Desktop) o ejecuta con --network host (Linux) para que el contenedor alcance el plugin en tu host. Las dependencias opcionales de OpenTelemetry se instalan por defecto: compila con --build-arg OTEL_ENABLED=false para omitirlas.

La imagen se vincula a 0.0.0.0 dentro del contenedor (requerido para el mapeo de puertos de Docker). Para cualquier despliegue accesible más allá de tu propia máquina, establece MCP_AUTH_MODE=jwt (con MCP_AUTH_SECRET_KEY) o oauth — de lo contrario, el listener reenvía tu OBSIDIAN_API_KEY al vault en nombre de cada llamador.

Estructura del proyecto

DirectorioPropósito
src/index.tsPunto de entrada de createApp() — registra herramientas/recursos e inicializa el servicio de Obsidian.
src/configAnálisis de variables de entorno específicas del servidor (OBSIDIAN_*) con Zod.
src/services/obsidianCliente de Local REST API, operaciones de frontmatter, extractor de secciones, tipos de dominio.
src/mcp-server/toolsDefiniciones de herramientas (*.tool.ts) y esquemas de entrada compartidos.
src/mcp-server/resourcesDefiniciones de recursos (*.resource.ts).
src/mcp-server/promptsDefiniciones de prompts (actualmente vacías — la forma CRUD/búsqueda no se beneficia de una plantilla estructurada).
tests/Pruebas Vitest que reflejan src/.
docs/Especificación OpenAPI ascendente para el plugin Local REST API y el tree.md generado.
changelog/Notas de versión por versión; CHANGELOG.md es el resumen regenerado.

Guía de desarrollo

Consulta CLAUDE.md para las pautas de desarrollo y reglas arquitectónicas. La versión corta:

  • Los manejadores lanzan, el framework captura — sin try/catch en la lógica de herramientas
  • Usa ctx.log para registro con ámbito de solicitud, ctx.state para almacenamiento con ámbito de tenant
  • Registra nuevas herramientas y recursos mediante los barriles en src/mcp-server/*/definitions/index.ts
  • Envuelve las llamadas a API externas: valida el dato crudo → normaliza al tipo de dominio → devuelve el esquema de salida; nunca inventes campos faltantes

Contribuciones

Errores, solicitudes de funciones y brechas de documentación pertenecen a un issue — consulta CONTRIBUTING.md para saber qué hace que uno sea accionable, y CODE_OF_CONDUCT.md para saber cómo trabajamos juntos. Los informes de seguridad pasan por SECURITY.md, nunca por un issue público.

Ejecuta verificaciones y pruebas antes de enviar:

bun run devcheck
bun run test

Licencia

Apache-2.0 — consulta LICENSE para más detalles.