AI Clients Start Cold. My Notes Shouldn’t.

Dimly lit desk with a laptop displaying a self-hosted MCP server architecture diagram connecting AI clients, Authentik, Syncthing, reMarkable notes, and an Obsidian markdown vault.

Building an MCP for My Notes: A Self-Hosted Knowledge Server for AI Clients

For about a year now, my Obsidian vault has been the closest thing I have to a brain backup. Daily notes, meeting records, project logs, source notes, captured thoughts — all of it lives in markdown files I sync between my Mac, iPhone, and a homelab LXC.

But every time I open ChatGPT, Claude Desktop, Claude Code, or an agent workflow, that context disappears. Each session starts cold. I can paste in notes manually, but that does not compose into a durable working system.

So I’ve been building a self-hosted Model Context Protocol server for my notes. In practical terms, MCP gives AI clients a structured way to call tools — read this file, search these notes, create this capture, append to this section — without each client needing a custom integration.

This first post is the design overview — what I'm building, why this shape, and what I deliberately said no to.

What it is

The MCP server itself is a long-running service that:

  • Lives next to my Obsidian vault on a homelab LXC
  • Exposes typed tools for reading, writing, searching, and structuring notes
  • Authenticates clients via OIDC (self-hosted Authentik)
  • Treats the vault as a multi-writer system with conflict awareness, audit logs, and restore paths

A few defined client classes are in scope, each with its own OIDC provider:

  • ChatGPT for conversational capture and retrieval
  • Claude Desktop for research and synthesis
  • Claude Code for project-aware technical work
  • n8n for workflow automation
  • Agentic workflow tools, including OpenFang, Claude Cowork, and an in-house framework for auditable internal automations

What it isn't

A few things this is not tied to, even though my current setup uses them:

  • Obsidian. Obsidian is what I happen to use as the editor. The MCP operates on a folder of markdown files; any editor that works on that folder (Logseq, Foam, vim, VSCode, Zettlr) is fine. The Dataview blocks in my daily template are the one Obsidian-flavored thing, but they are just that — template-level queries over markdown sections, not something the MCP workflow needs to care about.
  • LYT. My schema encodes LYT, but LYT isn't baked into the server. The schema YAML defines type → folder → filename → template → frontmatter; swap the YAML and the same MCP serves PARA, Zettelkasten, Johnny Decimal, or whatever conventions you've combined together into your own workflow.
  • The clients I named. Any MCP-compatible client works against the OAuth resource server. ChatGPT, Claude, OpenFang, n8n, and Cowork are who I'm wiring up first; the surface is the spec, not a hardcoded list.
  • A particular sync transport or search backend. Syncthing today, FTS5 today — both areas are swappable as needs evolve.

Put differently: it's a vault MCP with conventions I happen to like. "Obsidian" is shorthand for "my current editor" in this project.

The design rationale

The architecture is mostly shaped by one constraint: I want AI clients to participate in my note system without becoming the owner of it.

Self-hosted everything. Obsidian publishes a paid Sync product. It works great. I'm not using it — I'd rather own the data path end-to-end. So my vault sync is Syncthing across Mac, iPhone, and the LXC — and on the go, I can still sync from behind my zero trust access layer. Authentication happens with Authentik. I use Cloudflare Tunnels for public ingress (external clients like ChatGPT need to reach the MCP somehow), but everything inside the perimeter is mine.

LYT-aware, not generic. Most "let AI write to your notes" setups treat the vault as a flat dump. This MCP knows about LYT — Linking Your Thinking — the framework I use to organize my "piles of context" via ACE (Atlas / Calendar / Efforts). Each note type has a folder, a filename pattern, a template, and required frontmatter. When a client asks "create a meeting about our Technical Strategy Workshop for September 30th," the MCP knows to file it at Calendar/Records/Meetings/2026-09-30 Technical Strategy Workshop.md with the right frontmatter, not append text to a random place.

Schema lives in the vault, not the server. The LYT type map is _meta/lyt-schema.yaml inside the vault itself. It travels with the sync. The MCP reads it on each request rather than hardcoding any taxonomy. If I evolve my LYT structure, customize it, or even move away from LYT entirely for some reason, the migration path is simple. I edit the YAML; the MCP picks it up. Overlay schemas (_meta/overlays/*.yaml) extend the base for context-specific types — e.g. work-vs-personal people.

reMarkable handwritten notes flow in too. I draft and write a lot on my reMarkable tablets. I've written about past efforts to convert handwritten notes and inject them into my text notes. This workflow evolves that quite a bit and removes a few pieces of unnecessary complexity. My personal email is no longer a transport layer — I have a n8n workflow that pulls notebooks directly from reMarkable Cloud, parses them, and uses the MCP to save that content as captures in my vault. The MCP also makes these captures available to any tool that uses it.

Write safety is a first-class concern. Multiple clients will write concurrently. The MCP uses idempotency keys so a retried request doesn't double-write. Every write gets a mcp_write_id in frontmatter so audit queries can answer "who wrote to this file in the last hour?". Files have anchored sections (<!-- mcp:section daily-captures start -->) so appends land in deterministic places, not dumped at the bottom.

Capture is the killer use case for me. The most-used pattern is "add this thought to today, fast." There are two shapes: append a line to today's daily note's daily log section for quick drafts, or write a standalone capture file under Calendar/Records/Captures/ and let a Dataview block in the daily note render it. The latter is the default — captures stay queryable and don't fight the daily template. The first path is opt-in for clients that want raw inline appends.

What I said no to

A few options I considered and dropped:

Obsidian Sync as the sync layer. Obsidian's paid Sync product works well — but every additional vendor in the data path is another DPA to track, another ToS to vet for what gets shared with whom. Self-hosting Syncthing keeps the vault inside the perimeter I already manage, with an easy path to secure hosting with a cloud provider. The bridge to iOS Obsidian goes through the Synctrain into the "On My iPhone → Obsidian" folder; no iCloud either (this reduces file metadata and sync friction between iCloud and Syncthing).

That said, this isn't a one-way door. The MCP doesn't care how the vault gets to its bind mount. If Obsidian Sync becomes the more pragmatic option later — better mobile resilience, multi-person editing, fewer sync edge cases — swapping Syncthing for Sync would be a transport change, not a redesign.

Implementation note: iCloud is totally viable if the MCP runs directly on a Mac. For my deployment, the MCP lives on an LXC as the primary runtime, which would make iCloud a polling-based integration through something like rclone rather than a real-time sync layer. That adds fragility around Apple 2FA and makes it a poor fit for my use case.

A heavyweight knowledge-graph backend on day one. I could have built this on top of a vector store, embedding pipeline, semantic search, the works. The vault is markdown files; filesystem operations + SQLite FTS5 do everything I need to ship and start using the thing much sooner. FTS5 is exact, fast, debuggable, and runs on a stick of butter — perfect for getting off the ground. The shape of the watcher (file change → reindex) means embeddings can slot in later as a parallel index alongside FTS5, not a replacement: a future search_semantic tool, or a mode: "hybrid" parameter that fuses BM25 + dense vectors. Vectors add contextual reach; FTS5 stays exact and audit-friendly. It's a win-win in this case.

A single shared OAuth client. Every client class gets its own OIDC provider in Authentik. Same audience claim, different client_id/client_secret. That way I can revoke ChatGPT without affecting n8n; cross-client token replay fails because subjects don't match. It's more provisioning work for a much cleaner blast radius.

Putting it all in one repo with the vault. The vault is its own thing — synced to my devices, backed up separately, owned by me. The MCP server runs in a homelab LXC, configured by my Terraform + Ansible workflow that runs the rest of my cluster. Schema lives with the vault that it describes and defines. Server and cloud provisioning lives in infrastructure as code. Clean separation of concerns.

Why this matters

The larger point is not that every note system needs an MCP server. It’s that personal knowledge systems are becoming operational infrastructure. If AI clients are going to help with real work, they need access to durable context, clear permissions, safe write paths, and a way to leave behind artifacts that humans can inspect later.

So what's next?

The plan is to execute this work in multiple phases. So far, the plan is as follows:

  1. Establish the technical foundation and infrastructure layers — Terraform providers and provisioning, LXCs, standing up vault sync, idempotent Ansible roles, and an observability harness to plug into as we go.
  2. The MCP Server — where the system starts to become useful. Creating the binary, establishing the OAuth resource server, FTS5 indexing, and file watcher.
  3. LYT-aware tools + schema management — enabling taxonomy knowledge, and Obsidian workflow integration.
  4. OCR pipeline — reMarkable → OCR → vault.
  5. Client integration & polish — start connecting the clients, observability hooks, runbooks, and kicking the tires in production.

This first post lays the philosophy. The next one is what it actually took to stand up the foundation — and the surprises along the way.