exo
Imports your Goodreads bookshelves, ratings, and reviews into your personal record.
Imports your Last.fm listening history and scrobbles into your personal record.
Imports your Letterboxd movie ratings, reviews, and watchlist into your personal record.
Imports your Trakt watched history for movies and TV shows into your personal record.
Imports your Untappd beer check-ins and ratings into your personal record.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@exoWhat did I listen to most last month?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Exo
A personal context layer for agentic life systems.
Exo — short for exocortex, the part of your thinking that lives outside your head — is one record of a life, in a shape you own. Everything you consume, everything you write, and everything a machine concluded from the two, in one place with one SQL surface across it.
A filtered copy of that record is published to a read-only MCP server, so whatever assistant is in front of you can use it as context — without that assistant's vendor coming to own the record.
loaders ─────────▶ the record ─────────▶ the surface
what reaches it what it holds what it exposes
(one per source, (tier zones, one (a fixed set of named
each writes one SQL surface, one questions, read-only
zone) wall) by construction)Why
You should own your personal context, your operational knowledge and your memory as far as you can. That is what makes them portable, and it is the only thing that makes fine-grained privacy possible at all.
You own the routine without owning the scheduler. Self-hosting everything is admirable and not pain-free; sometimes someone else's infrastructure is the right answer. What should not move is the record.
No platform lock-in, no model lock-in. The record is parquet and markdown on your disk. The surface is MCP, which every assistant speaks.
Meet you where you work. A centralised store reachable over MCP means the same context reaches your terminal agent, your editor and your phone.
This exists because the alternative is a dozen silos that each know a tenth of you and none of which will give it back.
Related MCP server: mcp-multi-db
What it actually does
Loaders pull your data out of the silos it is trapped in: Last.fm, Letterboxd, Goodreads, Untappd, Trakt, MyAnimeList, Raindrop, your Claude and ChatGPT exports, your markdown notes, your published writing, your git repos. Each loader writes exactly one zone and nothing else.
Notes get their own front door, because notes are the one thing that keeps
changing address. exo ingest-notes reads a note source — Apple Notes, a
Notion export, a directory of text files, a blob on standard input — and lands
each note as markdown you own, with the frontmatter the record reads (ADR-0017):
exo ingest-notes notion # the API, incremental, nightly-safe
exo ingest-notes notion --from Export.zip # or an export, offline
exo ingest-notes files --from ~/writing
pbpaste | exo ingest-notes files --from - # a blob; its first line is the titlefiles covers more than it sounds like: a directory of markdown is the format
the engine has read since ADR-0001, so an Obsidian vault needs no adapter —
its dot-directories, attachments, bare-date daily notes and tags: properties
are all handled. Adding a genuinely new source is one small module, and
everything downstream — atoms, vectors, both publication axes, the read surface —
never learns which one it was. docs/notes-sources.md is
the how-to.
The record keeps them separated by who may write, not by what the data is:
tier | what it is | written by |
T0 consumption | what the world recorded about you — scrobbles, ratings, saves | loaders only |
T1 authored | your words: notes, posts, verdicts, recipes, tasks | you, by hand |
T2 derived | what a machine concluded: atoms, vectors, affinities | derivation only |
Derivation reads T0 and T1 and physically cannot see T2 — the profile it
reads through has no T2 views at all. So T2 always regenerates from ground
truth, and exo verify proves it by deriving twice and comparing digests.
Machine output never becomes machine input.
The surface publishes a physically separate copy containing only rows you declared publishable. Held material is absent from the published files, not filtered at read time, so no bug downstream and no injected instruction can reach it. The policy is fail-closed: an undeclared zone fails the build rather than defaulting either way.
The surface is also modular. An instance offers a subset of the engine's
tools, resolved when you publish (ADR-0020). A tool whose zones you hold retires
itself rather than being advertised and then failing on a table that is not
there; [tools] in exo.toml switches off the rest by domain or by name. That
second lever is for when something else you connect answers the question better
— because Exo is not meant to be the only MCP server you run:
[tools]
domains = ["mind", "workshop"] # specialise this instance
disable = ["recipes"] # a peer answers this one better
[peers]
sources = { notion = "Notion" } # these notes are also live over thereA peer is a server you also connect that holds the same material live. Exo keeps serving it — the filed, indexed, publication-graded copy is the half it is good at — and says on the row which peer holds the current one, so an assistant reading both can tell one note from two instead of quoting the same paragraph twice. What to do about it is the agent's call, not ours (ADR-0013).
The engine and your instance
This repository is the engine. It holds no data and never will.
Your data, your config and your own loaders live in an instance — a
separate, private directory (usually its own private repo) that the engine
finds through $EXO_HOME:
your-instance/
exo.toml who you are, where your inputs live
serve-manifest.json what may leave this machine
raw/ your exports and mirrors
notes/ notes you own, landed by `exo ingest-notes`
zones/ the record itself
plugins/ loaders only you could have
items/ your tasks, habits, slots
procedures/ how you do a recurring thing, by handA loader ships in the engine if its input is a format — a Last.fm export, a folder of markdown, a directory of git repos. Anyone can hold one of those. A loader belongs in your instance if its input is a place: your city's venue calendars, your sibling repos, your blog. The test is not how specific the code is; it is whether a stranger could hold that input at all.
Start
uv sync
uv run exo init ~/my-exo # scaffold an instance
export EXO_HOME=~/my-exo
# drop your exports into $EXO_HOME/raw/exports/, then:
uv run exo rebuild # ingest -> index -> derive -> catalog
uv run exo query "SELECT artist, count(*) FROM t0_music GROUP BY 1 ORDER BY 2 DESC LIMIT 10"
uv run exo publish --dry-run # what would leave, and what is held backThe templates exo init copies are exo/templates/ — read
them before you edit the copies.
Reach it from your phone
The point of the read surface is that the record answers when you are nowhere near the machine holding it. worker/ is a Cloudflare Worker speaking MCP over HTTP — read-only permanently, serving only the publication bundle — and worker/README.md walks through standing it up and connecting it to Poke, the iMessage assistant:
cd worker
cp wrangler.example.toml wrangler.toml # your database id, your buckets, your name
npx wrangler d1 create exo # + r2 bucket create exo-vectors
npx wrangler deploy
npx wrangler secret put AUTH_TOKEN # openssl rand -hex 32then publish a bundle into it (exo publish --cf, then import.sh), and add
the Worker's URL and that token at
poke.com/integrations/new. Any MCP client
works the same way — Poke is just the one that reaches you by text message.
Then read CONTEXT.md — it is the vocabulary, and the rest of the repo assumes it.
Teach the assistant to read it
skills/ holds instructions for the assistant at the other end — markdown you copy into your client. They are not part of the record and not part of a bundle; they exist because a surface that returns true rows still affords a short list of false statements, and the facets on each tool predict exactly which ones (ADR-0015). A saved link read as something they consumed. A rating reported without its scale. A machine's conclusion quoted as the owner's sentence.
A skill is the engine's half of that and holds nothing about any particular owner. The half that is about you — your Sunday, your other MCP server, your checklist — is a procedure, written by hand in your instance and published as a resource (ADR-0016). Same test as loaders: format here, place there (ADR-0027).
Honest limits
The startup cost is real. This is a tool for someone who already keeps notes, already exports their data, and already wanted this. It will not bootstrap the habit for you.
Loaders break. They read other people's export formats and scrape other people's pages. Each one keeps its last good file rather than overwriting it with a failure, but a rotted loader is a matter of when.
It is a second brain underneath. A personal wiki, loaders for consumption data and archives, some distillation on top. The novel part is not any one of those; it is that they share one record with one publication boundary.
The chat-export loader is a pocket knife. It normalises Claude and ChatGPT exports into one shape, which is useful whether or not you want the rest of this.
The decisions
Every non-obvious choice has an ADR in docs/adr. The load-bearing ones:
a DuckDB catalog over tier-native files, and the wall | |
split the ETL: the laptop ingests, the cloud rebuilds | |
the remote read surface is permanently read-only | |
bound the blast radius of an injected read | |
the code is public, the instance is private | |
a procedure is a resource, not a tool | |
a note source is an adapter, and the note file is the contract | |
the notes tree is the original; the bucket is a mirror | |
publicity is an axis, not an adjective | |
the surface is modular, and a peer is not a competitor | |
a denominator is a source, not a calculation | |
a skill ships with the engine; a procedure belongs to the owner |
Contributing
Read CONTRIBUTING.md first — particularly the part about never putting personal data in this repository, including your own, and the list of small-looking changes that re-mint every id in a running instance.
MIT.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Person-owned AI memory that learns, not just stores — portable context for any MCP client.
Agent-native MCP server over 49M+ US public and government records, privacy-first, always current.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceModel Context Protocol (MCP) server that gives AI assistants a safe, correct data-analyst capability over business metrics - without raw SQL improvisation.-
- AlicenseAqualityAmaintenanceRead-only MCP server for querying PostgreSQL, MySQL, and SQLite from AI agents — multi-database, safe by default.4181ISC
- AlicenseAqualityAmaintenanceA read-only MCP server that exposes SQL database access to LLMs, supporting multiple database types, compact columnar results, pagination, and file export.618MIT
- AlicenseBqualityBmaintenanceA local-first, model-agnostic MCP server that stores personal health data in a SQLite file and provides analysis-ready views for any AI client to log, retrieve, and reason over health records.79MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/reeswrites/exo'
If you have feedback or need assistance with the MCP directory API, please join our Discord server