LabscoMCP early access ↗
maxkuminovMCP SERVER

Obsidian MCP Server by maxkuminov

Self-hosted MCP over your Obsidian vault: keyword and semantic search, section-level edits, wikilink graph traversal and a file-transfer path.

Note-Taking & Personal Knowledge BasesCommunity

LABSCO SUMMARY

Writes are staged and published atomically — a crash cannot truncate a note.

The engineering here is unusually explicit about failure. Every write stages bytes in a temporary inode, fsyncs, and only then publishes: creation uses a kernel-atomic hard link that refuses to clobber, and the soft delete uses a single non-replacing rename. Where the filesystem cannot do that, the operation refuses with a named error rather than degrading to something that can overwrite. The system checks are the same story — an old kernel or an old pgvector makes it exit at startup and say which one, instead of quietly returning worse search results. The requirements list is long, and it is long on purpose.

What it is

A self-hosted server that indexes an Obsidian vault into PostgreSQL with pgvector and serves it over MCP. Agents read what you read, follow the same wikilinks, and pick up your folder layout, frontmatter schema and tag conventions on the first call.

What you get

  • 25 tools across five families. Search: keyword_search over PostgreSQL tsvector, semantic_search via pgvector, list_notes, get_recent, get_tags, and get_vault_guide which serves your vault's own CLAUDE.md live
  • Read and write: read_note bounded by MAX_READ_RESPONSE_CHARS with section for one heading and offset to continue; create_note refuses overwrite; edit_note has four exclusive modes — full replace, append, find/replace and section — with dry_run=True returning a unified diff
  • move_note optionally rewrites incoming [[Old]], [[Old|alias]] and ![[Old]] references; delete_note soft-deletes into .trash by default; set_frontmatter mutates YAML leaving the body byte-identical
  • Non-markdown files get peers rather than overloads: read_file returns text, an inline image block, or base64; write_file, list_files and delete_file round it out — all sharing the path-traversal guard that excludes dot-directories
  • File transfer closes the gap MCP cannot: request_upload mints a single-use link bound to one destination path, check_upload reports its state, request_download mints a save link, and import_from_url fetches a public https asset under a deny policy that blocks private, loopback, link-local and metadata addresses at every redirect
  • Wikilink graph: get_backlinks, get_links with resolved and dangling entries, get_neighborhood as an undirected BFS, find_related by averaged chunk embeddings, and find_orphans
  • API keys carry read or readwrite scopes and write tools refuse on a read-only key; OAuth 2.0 with PKCE covers ChatGPT, Claude Desktop and claude.ai; every call is logged with name, params, duration and calling credential

Requirements

Docker and Docker Compose on Linux, kernel 5.6 or newer — every directory below the vault root is opened with a single openat2 call, so the kernel proves a write stayed inside the vault, and there is no fallback. Kernel 5.8 is needed for the file-transfer tools; below that they refuse and everything else works. PostgreSQL 16 with pgvector 0.8.0 or newer, and either an Ollama instance running bge-m3 or an OpenAI API key. The filesystem must be case-sensitive and support hard links and RENAME_NOREPLACE. macOS and Windows hosts are out of scope.

Setup effort

Run a container — build the image from the repository, then point your client at it