cd /news/developer-tools/i-built-a-local-first-tab-manager-an… Β· home β€Ί topics β€Ί developer-tools β€Ί article
[ARTICLE Β· art-97474] src=dev.to β†— pub= topic=developer-tools verified=true sentiment=↑ positive

I built a local-first tab manager and gave it an MCP server so Claude can organize my tabs

Developer and designer built Mos Tab, a local-first tab manager for Chrome that overrides the new tab page and includes optional cloud sync via a Cloudflare Worker and R2, with a 3-way merge to handle conflicts. The extension also features a remote MCP server that lets Claude or ChatGPT search, summarize, and save tabs, notes, and to-dos directly from chat. The developer highlighted challenges with multi-window sync, solved by gating writes to the focused window, and demonstrated a use case where Claude created a curated stroller shortlist with a shareable link.

read4 min views1 publishedAug 14, 2026

I'm a designer and developer, and a hopeless tab hoarder. On a normal day I've got 70+ tabs open across a couple of windows, every favicon crushed into an unreadable sliver, and my "system" for finding anything is to just… open another tab. Bookmarks? A write-only graveyard I never revisit.

I bounced between tab managers for a while. Toby was the one that stuck β€” until it capped the free plan at 60 saved tabs and started asking for an account. For a tab hoarder, a 60-tab cap is like a notes app that locks after 60 words. That was the nudge.

So I did the reasonable thing and spent way too long building my own. It's called Mos Tab. This is the build story β€” the parts I'm proud of, the part that nearly broke me (multiple windows, I'm looking at you), and the weirdly fun part at the end where I let Claude reorganize my tabs.

Three non-negotiables: Mos Tab overrides chrome://newtab

(MV3). The data model is a boring normalized tree β€” Space β†’ Collection β†’ Section β†’ Tab β€” records plus ID arrays for ordering. It's a single Zustand store with a persist

middleware writing to chrome.storage.local

. Your currently-open tabs show in a live side panel (chrome.tabs

); one click saves them into a collection, drag to organize, and a cmdk

palette searches everything you've saved.

Stack, for the curious: React 18 + TypeScript + Vite + @crxjs/vite-plugin

, Tailwind, dnd-kit, zod, i18next (5 languages). Since the new tab is prime real estate, I threw in the stuff I open a tab for anyway β€” calendar, pomodoro, to-dos, sticky notes. All free.

So far, so normal. Then I wanted sync.

Local-first is lovely until you have two machines. I wanted optional cloud sync (the paid tier β€” more on money later) without turning this into a database migration.

The backend is deliberately dumb: a Cloudflare Worker + R2, one JSON blob per user (state.json

). No per-row DB. To save, you PUT the blob back with an ETag conditional request (If-Match

). On a 412

(someone wrote first), you pull, 3-way merge on the client, and push again.

The 3-way merge (base + local + remote) handles the real cases: both sides added a tab β†’ keep both; something in base

vanished on one side β†’ it was deleted, respect it; field conflicts β†’ local wins. Sticky-note text conflicts resolve to a symmetric content-addressed copy, so two machines converge instead of endlessly duplicating.

The part that actually broke me wasn't cross-device β€” it was multiple windows on the same machine. Every window wanted to push, each invalidating the others' ETag β†’ 412 β†’ merge β†’ push β†’ 412 β†’ forever. A beautiful infinite loop.

The fix: only the focused window pushes. Every window can pull (reads are idempotent), but writes are gated to the focused one, with a flush-on-blur so the last edit isn't lost when you switch away. Add adaptive polling backoff (15s active β†’ 2min idle) and an "away mode" that stops polling after 20 min of no activity, and it stops hammering the Worker.

Here's the part I'm actually excited about. I gave Mos Tab a remote MCP server so you can connect Claude or ChatGPT to it. Once connected, the assistant can search and summarize everything you've saved (tabs, notes, to-dos) and β€” the fun bit β€” save new things it finds into a brand-new space, add notes, or make a public share link. All from the chat.

Concrete example. I told Claude:

"Find the top-rated budget strollers on Amazon, save them to my tabs, and make a share link."

A few seconds later there was a new "Stroller shortlist" space on my dashboard, organized into categories, and a public link I sent straight to my wife β€” she opened it in her browser, nothing to install.

Two design decisions I'm happy with:

fetch

Worker β€” no Durable Objects, no McpAgent. Auth is a long-lived scoped token you mint in settings (JWTs expire, which is bad for a persistent connection). Reads filter the same per-user blob in memory; writes are read-modify-write with If-Match

/ 412 retry β€” so an AI-created space merges through the That last bit is the thing I like most: AI writes go through the same door as everything else. No special path, no separate store.

Because someone always asks: the whole local app is free β€” unlimited tabs, spaces, all the widgets, import/export. Local storage costs me nothing to run, so there's no reason to cap it. The paid tier is only the stuff that actually hits a server: multi-device sync, public sharing, and the AI/MCP integration. I can't give the server stuff away free β€” kind of wish I could. That's the whole pricing philosophy, and it keeps me honest.

Live on the Chrome Web Store (Chrome + Chromium β€” Edge, Brave, Arc, etc.):

I'm a solo dev, so I read everything β€” feedback on the sync merge model or the MCP design especially welcome.

── more in #developer-tools 4 stories Β· sorted by recency
── more on @mos tab 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/i-built-a-local-firs…] indexed:0 read:4min 2026-08-14 Β· β€”