I wanted one place for my notes that I own, that is always on, and that I can write to from anywhere. My phone while walking, a browser on my desktop, or a chat with Claude. This is how I got there. It runs self-hosted on my Pi.
Where I started
I tried Obsidian. The paid version allowed sync on multiple devices. I wanted to self-host and didn’t want to pay, so I tried Syncthing, but it’s fimsy on the iphone. I tried a number of self hosted solutions like Blinko and Nextcloud, but they seemed like an overkill.
For a while my notes lived in Notion. I had older notes from Obsidian as plain markdown files, and I imported them into a Notion database so everything would be in one place, with Claude connected through Notion's MCP connector.
It did not work out, for three reasons:
- It was slow. Every search or fetch through the Notion connector was a round trip to Notion's servers and their API. Reading a note, or checking what was already there before adding something, took far longer than opening a local file.
- It is a lock-in. Notion stores pages as blocks in its own database, not as files. Wikilinks, frontmatter and the folder structure did not survive the move cleanly, and links between notes had to be dropped on import.
- It is hard to export and manage outside Notion. Getting notes out means a lossy export, and there is no simple way to script, grep, back up or version them. Even the import was painful: no API token, so every page had to be pushed through the connector in batches.
My original markdown files were still sitting in my old Obsidian folder, so I went back to them. Plain files I own, on hardware I own, with Claude connected through my own MCP server instead of someone else's platform.
The idea
My notes are plain markdown files in a folder (a Zettelkasten folder with around 800 notes). The folder lives on the Raspberry Pi in my house, and everything else is just a different door into the same folder:
| SilverBullet | A web editor, so any desktop browser can edit the notes folder without installing anything |
| A notes MCP server | Lets Claude (claude.ai and the mobile app) search, read and write the notes folder |
There is no database and no proprietary format. If every service below disappeared, I would still have a folder of markdown files.
flowchart LR
Phone["Claude on phone"] --> CF["Cloudflare Tunnel"]
Web["claude.ai"] --> CF
CF --> MCP["notes-mcp (Docker)"]
Browser["Desktop browser (home network)"] --> SB["SilverBullet (Docker)"]
Sync["Syncthing (laptop sync)"] --> V
MCP --> V[("Notes folder on the Pi")]
SB --> V
Part 1: the MCP server
MCP (Model Context Protocol) is a standard way to give an AI assistant tools. Claude supports remote MCP servers as "custom connectors", so if you can host a small server, Claude can use it from the web and from the phone.
I wrote a small Python server using the MCP SDK and run it in Docker on the Pi. You can find it here: karanmhatre1/notes-mcp on GitHub has the code and a getting started guide. It mounts the notes folder read-write and exposes a handful of tools:
search_notes(query, limit) | Full-text search over titles and contents. Every word must match; title matches rank first. |
read_note(title) | Returns the full markdown of a note. |
list_notes(limit, order, contains) | Lists notes by most recently modified or by title, optionally filtered. |
backlinks(title) | Lists every note that links to [[title]]. |
create_note(title, content, tags) | Creates a new note in the notes folder. Fails if the title already exists. Optional tags go into YAML frontmatter. |
append_to_note(title, content) | Adds text to the end of an existing note. The safest way to add to something. |
edit_note(title, old_text, new_text, replace_all) | Exact-text replacement. old_text must match exactly once unless replace_all is set. |
rewrite_note(title, content, keep_frontmatter) | Replaces a note's whole body, keeping its frontmatter. The previous version is saved to .trash/versions/. |
rename_note(title, new_title) | Renames a note and updates [[wikilinks]] to it everywhere. |
trash_note(title) | Moves a note to .trash/. Nothing is ever permanently deleted. |
refresh_mocs(title, dry_run) | Regenerates auto-generated link lists inside notes. |
The trash choice matters. I am giving an AI write access to my notes, so the worst thing it can do should be recoverable.
Getting it onto the internet safely
Claude's servers need to reach the MCP server, but I do not open any ports on my router. The server is exposed through the same Cloudflare Tunnel that serves my websites, on its own hostname.
Auth
A public endpoint that can write to my notes needs real authentication. The server implements single-owner OAuth with dynamic client registration, which is what Claude's connector flow expects. When I add the connector, Claude opens a login page on my server and I enter a passphrase. Only a scrypt hash of the passphrase is stored, login attempts are rate limited, and tokens are stored hashed. Rotating the passphrase is a new hash in the .env file and a container restart.
What it feels like
From my phone I can say "add this to my note about the Berlin trip", "what did I write about Immich backups?" or "turn this voice rambling into a note and link it to the right topics". Claude searches first, appends to an existing note when one fits, and creates a new one only when it does not. Capturing a thought takes a few seconds, wherever I am.
Part 2: SilverBullet
The MCP server covers capture from my phone, but for long writing I want a real editor on a big screen. SilverBullet is a self-hosted, browser-based markdown editor that works directly on a folder of files, which is exactly what my notes folder is.
It runs as a Docker container on the Pi. Two details I like:
- I mount the main notes folder into SilverBullet's space. Its internal files never end up inside my notes folder.
- It is reachable on my home network only. There is no tunnel and no DNS entry for it, so it is not on the public internet. Remote access is on the to-do list, probably via Tailscale.
Because SilverBullet edits the same files as the MCP server, a change made in any of the two shows up in the others.
What is next
- Reach SilverBullet remotely over Tailscale
- Backups of the folder (restic or borg) to a second location
Why bother
Because the notes are mine. The AI is a convenient interface to them, not their owner. A few things follow from that:
- No lock-in to an AI provider. MCP is an open standard, so if I switch assistants tomorrow I point the new one at the same MCP endpoint and carry on.
- No lock-in to a note-taking app. The notes are plain markdown files, not tied to Notion or any single app, and any markdown editor can sit on top.
- Easy to publish. Since everything is markdown, I can publish notes straight from the folder to my website. This article started as a note.
- Context for AI assistants. The notes double as a knowledge base that any connected assistant can search and read, so it has my background, projects and past thinking as context instead of starting cold every conversation.