{"slug": "my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server", "title": "My notes app has no database, just a folder of Markdown and an MCP server", "summary": "Developer Mohak Bajaj shipped Jot, a Mac note-taking app that stores every note as a Markdown file with YAML front matter in a single folder at ~/Documents/Jot, with no database, sync server or account system, and exposes the vault to AI agents through a seven-tool MCP server launched via `jot mcp` on stdio for Claude Code, Codex and Cursor. The roughly 600-line TypeScript storage layer writes atomically via temp file plus rename, caches parsed files by inode, mtime and size, and skips unparseable files rather than crashing; the MCP server deliberately omits a delete tool so agents can add, tag, finish and archive notes but cannot remove them. Two generated files, INDEX.md and SKILL.md, let any agent that can read a folder use the vault without MCP.", "body_md": "[blog](https://sayjot.xyz/blog) ·  · Mohak Bajaj\n\n# My notes app has no database, just a folder of Markdown and an MCP server\n\nI make a small Mac app called Jot. You select text anywhere, tap Shift twice, and it saves a note. When I started, I thought about SQLite, a sync server and an account system. I shipped none of them. All of Jot's storage is a folder: `~/Documents/Jot`.\n\nThis post covers how that folder works, what broke, and why AI agents turned out to be the best reason for it.\n\n## One note is one file\n\nEvery note is a Markdown file with YAML front matter:\n\n```\n~/Documents/Jot/\n  2026-11-09-6tjhzv.md\n  2026-11-09-gnump0.md\n  INDEX.md\n  SKILL.md\n  attachments/6tjhzv/\n  .trash/\n---\narchived: false\ncreated: 2026-11-09T09:12:04.511Z\ndone: false\nid: 6tjhzv\nimages: []\npin: false\nsection: ''\nsource: Safari\nurl: https://example.com/article\ntags: [reading]\nupdated: 2026-11-09T09:12:04.511Z\n---\nA line I selected and wanted to keep.\n```\n\nThe filename is `YYYY-MM-DD-<id>.md`. The id is 6 random characters from `[0-9a-z]`. The date at the front makes `ls` sort by day for free. If a file loses its `created` field, Jot falls back to the date in the name, so the order stays stable.\n\nImages and audio go in `attachments/<id>/`. A deleted note moves to `.trash/<id>/`, so undo is a rename back.\n\n## The problems a database would have solved\n\n**Half-written files.** If the app crashes in the middle of a write, the note is gone. So every write goes to a temp file next to the real one (`.name.<16 hex>.tmp`), and then a rename puts it in place. A rename is atomic on one filesystem. The rename lives in the folder entry, so Jot also syncs the folder, or a power cut can undo it. When Jot opens the vault, it deletes temp files left by a crash.\n\n**Reading every file, every time.** Each operation lists the folder again. Parsing hundreds of files with YAML on each keypress is slow. Jot keeps a cache keyed by inode, mtime and size. An atomic write gives the file a new inode, so any change misses the cache, and a file that did not change is not parsed again.\n\n**A file someone else broke.** You can edit these files in Vim, Obsidian or a script. If the front matter stops parsing, Jot leaves that one file out of the list, logs why once, and keeps going. It does not crash, and it does not \"fix\" your file.\n\n**Changes from outside.** Jot watches the folder. If another program adds or edits a file, the inbox updates by itself.\n\nThat is the whole storage layer, in about 600 lines of TypeScript.\n\n## Then agents showed up\n\nI added a CLI first (`jot list`, `jot search`, `jot add`, `jot tag`, `jot done`, `jot archive`). Then `jot mcp` started an MCP server on stdio, so Claude Code, Codex and Cursor can use the same vault.\n\nThe MCP server has seven tools:\n\n| Tool | What it does | \n|---|---|\n| `list_jots` | List by status, section or tag, newest first | \n| `search_jots` | Case-insensitive match on body, tags, source app and URL | \n| `read_jot` | The whole file, plus absolute paths to its images | \n| `add_jot` | Create a note; the first line is its title | \n| `tag_jot` | Add tags; existing tags stay | \n| `set_done` | Mark done, or open again | \n| `archive_jot` | Hide from the inbox; the file stays | \n\nThere is no delete tool, on purpose. An agent can add, tag, finish and archive. It cannot remove anything. The worst an agent can do is leave a mess you can see in Finder.\n\nThe server also does very little. It reads the files, changes the front matter, and writes them back with the same atomic write. The app sees the change through the folder watcher. There is no IPC between the server and the app, and the app does not need to be running.\n\n## Files help agents even without MCP\n\nTwo generated files are for agents:\n\n- `INDEX.md` lists every note as a Markdown link with its title. An agent reads one file and knows what is there.\n- `SKILL.md` describes the layout: where files live, what the front matter means, and how ids look. Any agent that can read a folder can use the vault correctly.\n\nSo the setup for most agents is just this: \"my notes are in ~/Documents/Jot, read SKILL.md.\" Something like \"what was I thinking about last week\" becomes a `grep` and a `read`.\n\n## What I gave up\n\n- **Sync.** Jot does not sync. If you want it, put the folder in iCloud Drive or Syncthing. I have not built conflict handling for two Macs that write at the same time.\n- **Fast queries over large vaults.** Search is a substring scan over parsed files. That is fine for thousands of notes. For hundreds of thousands, I would add an index.\n- **Schema migrations.** The front matter is now an on-disk format that other tools read, so I can only add fields, not rename them.\n\nFor a capture inbox, these trades were worth it. Your notes outlive the app, every tool you already use can open them, and `ls ~/Documents/Jot` is the admin panel.\n\nJot is a Mac app for capture and dictation. It's free for 3 days, then $9 once at the launch price. [sayjot.xyz](https://sayjot.xyz/?ref=blog)", "url": "https://wpnews.pro/news/my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server", "canonical_source": "https://sayjot.xyz/blog/no-database", "published_at": "2026-11-10 07:19:52+00:00", "updated_at": "2026-11-10 07:52:23.843287+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-tools", "developer-tools"], "entities": ["Jot", "Mohak Bajaj", "Claude Code", "Codex", "Cursor", "MCP"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server", "markdown": "https://wpnews.pro/news/my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server.md", "text": "https://wpnews.pro/news/my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server.txt", "jsonld": "https://wpnews.pro/news/my-notes-app-has-no-database-just-a-folder-of-markdown-and-an-mcp-server.jsonld"}}