ohmyself
Exposes a personal markdown-based second brain (Obsidian-style) as an MCP server, enabling agents to search, read, and write notes with privacy controls.
README
ohmyself!
Your second brain as loose markdown — exposed over MCP and a REST API, with privacy built in.
ohmyself! holds everything about a person (who they are, goals, projects, people,
journal, finances, secrets) as plain .md files (Obsidian style), not a typical
database. Those files are the source of truth; everything else is built on top:
- an MCP server so agents (your personal Claude, a public website agent) can search, read, and write your brain;
- a REST API for the web UI and a future iOS app;
- a web UI (light mode) to browse the brain and chat with an agent over it.
Privacy is per-note (public / private / secret). A public agent on
juandisanchez.com can answer about you using only public notes, while your personal
Claude (authenticated) can see everything. Multi-tenant from day one.
flowchart TD
subgraph clients [Clients]
Claude["Personal Claude (MCP stdio / HTTP)"]
Web["Web UI (Next.js)"]
Public["Public agent (scope: public)"]
iOS["iOS app (future)"]
end
subgraph server [server/ TypeScript]
MCP["MCP (Streamable HTTP + stdio)"]
API["REST API (Hono)"]
Core["core: vault + index + scope + config"]
end
subgraph sb [Supabase]
Auth["Auth (JWT -> user + scope)"]
DB["Postgres: profiles, user_config, note_index (RLS)"]
Store["Storage: brain/<userId>/*.md"]
end
Claude --> MCP
Web --> API
Public --> MCP
iOS --> API
MCP --> Core
API --> Core
Core --> Store
Core --> DB
API --> Auth
MCP --> Auth
Repo layout
server/ TypeScript: core lib + MCP server + REST API + connectors
web/ Next.js web UI (light mode; built with the `impeccable` design skill)
supabase/ config.toml + versioned migrations (tables, RLS, storage bucket)
templates/ default brain taxonomy + seed notes (used for onboarding new users)
Prerequisites
- Node 20+ and pnpm (
corepack enable && corepack prepare pnpm@9.15.9 --activate) - A Supabase project (the migrations under
supabase/migrations/define the schema) ghandsupabaseCLIs if you want to reproduce provisioning
Setup
pnpm install
cp .env.example .env.local # fill with your Supabase values — never commit it
cp .env.example web/.env.local # only the NEXT_PUBLIC_* values matter for web
.env.local (server) needs at least:
SUPABASE_URL=... # https://<ref>.supabase.co
SUPABASE_ANON_KEY=...
SUPABASE_SERVICE_ROLE=... # server-only, never in the browser
PUBLIC_AGENT_TOKEN=<random> # token the public website agent presents
PUBLIC_AGENT_USER_ID=<your uuid> # set after you sign up (see below)
Apply the database schema (already done if you provisioned with the CLI):
supabase link --project-ref <ref>
supabase db push
Run locally
pnpm dev:server # http://localhost:8787 — REST at /v1/*, MCP at POST /mcp
pnpm dev:web # http://localhost:3000 — sign up, get a seeded brain, browse + chat
Create an account in the web UI; on first login your brain is seeded from
templates/brain automatically (idempotent). To point the public agent at your
brain, copy your user id (/v1/me returns it) into PUBLIC_AGENT_USER_ID.
Seed any user manually:
pnpm seed --user <userId>
Connect your personal Claude (MCP)
Local, over stdio
Add to your Claude Desktop / MCP client config. Use VAULT_BACKEND=supabase with your
real user id, or VAULT_BACKEND=fs for a purely local markdown folder.
{
"mcpServers": {
"ohmyself": {
"command": "pnpm",
"args": ["--filter", "@ohmyself/server", "mcp"],
"env": {
"VAULT_BACKEND": "supabase",
"OHMYSELF_USER_ID": "<your-supabase-user-id>",
"OHMYSELF_SCOPE": "secret",
"SUPABASE_URL": "https://<ref>.supabase.co",
"SUPABASE_SERVICE_ROLE": "<service-role-key>",
"BRAIN_BUCKET": "brain"
}
}
}
}
Tools exposed: search_brain, list_notes, read_note, create_note,
update_note, append_to_note, link_notes, get_context.
Remote, over Streamable HTTP
Point an MCP client at POST https://<your-host>/mcp with an Authorization: Bearer <supabase-jwt> header. Add X-Brain-Scope: private to keep secret notes out of a
given connection. The public website agent uses Authorization: Bearer <PUBLIC_AGENT_TOKEN> and only ever sees public notes.
Official connector (OAuth 2.1)
ohmyself! ships a self-hosted OAuth 2.1 authorization server so it can be added as a
one-click connector in Claude and ChatGPT — no manual token. It implements the MCP auth
spec: a 401 with WWW-Authenticate on /mcp, Protected Resource Metadata
(/.well-known/oauth-protected-resource, RFC 9728), Authorization Server Metadata
(/.well-known/oauth-authorization-server, RFC 8414), Dynamic Client Registration
(/oauth/register, RFC 7591), Authorization Code + PKCE (S256) via the web consent page
at /authorize, and a token endpoint (/oauth/token) with refresh-token rotation.
- Access tokens are opaque (
oma_…, stored only as SHA-256 hashes) and resolve to the consented scope; refresh tokens areomr_…. Tables:oauth_clients,oauth_auth_codes,oauth_tokens(service-role only). - Single-domain prod: the web project rewrites
/mcp,/oauth/*, and/.well-known/*to the API project so everything lives under one origin (e.g.https://www.ohmyself.ai). SetOMS_ISSUER,PUBLIC_API_URL, andPUBLIC_WEB_URLaccordingly on both projects. - Connect: in Claude, Settings → Connectors → add the
/mcpURL; in ChatGPT, Settings → Connectors → Create. You sign in, pick a scope (public/private/secret), and approve.
Privacy model
Each note's frontmatter has visibility: public | private | secret. A request carries
a scope; it can read everything at or below its level (public ⊂ private ⊂ secret). Reads above scope return 404 (existence is hidden). Writes require a non-public
scope. See templates/CONVENTIONS.md.
Per-user structure (config-driven)
The taxonomy (folders, note types, default visibilities) is per user, stored in
user_config and editable via GET/PUT /v1/config. Defaults live in
templates/default-config.json / server/src/core/config.ts. New notes are validated
against the user's config, not a global schema.
Add a connector
Connectors ingest data into (and optionally out of) the brain. Implement the
Connector interface (server/src/connectors/types.ts) and register it in
server/src/connectors/index.ts. Run one via POST /v1/connectors/:id/pull. A
Google Calendar → transcripts connector ships in server/src/connectors/.
Secrets / open source
This repo is public. Real keys live only in .env.local (gitignored) and your host's
env vars. Only .env.example (placeholders) is committed. The browser uses the anon
key only; the service role key is server-side.
Deploy
Live deployment (Vercel):
- Web app: https://ohmyself.vercel.app
- API + MCP: https://ohmyself-api.vercel.app (
/health, REST/v1/*, MCPPOST /mcp)
Both are deployed as two Vercel projects that share the same Supabase project, so the brain is reachable from web, iOS, and your agents.
Vercel layout
server/→ a Vercel project serving REST + MCP. The build runstsctodist/, andapi/index.js(a serverless function) reuses the same request dispatcher as the local Node server (src/http.ts). All routes are rewritten to that function viavercel.json. The default brain is embedded (src/templates.generated.ts) so onboarding works without filesystem access. Set these env vars on the project:SUPABASE_URL,SUPABASE_SERVICE_ROLE,SUPABASE_ANON_KEY,BRAIN_BUCKET,VAULT_BACKEND=supabase(and optionallyPUBLIC_AGENT_TOKEN/PUBLIC_AGENT_USER_IDfor the public agent). For the OAuth connector also setOMS_ISSUER,PUBLIC_API_URL, andPUBLIC_WEB_URL(in single-domain setups all = your web origin, e.g.https://www.ohmyself.ai).web/→ a Next.js Vercel project. SetNEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY, andNEXT_PUBLIC_API_URL(in single-domain prod this is your own web origin, since/mcp+/oauth/*are rewritten to the API project).
Deploy from each package directory:
cd server && vercel deploy --prod
cd ../web && vercel deploy --prod
If a Vercel build hits pnpm's
ERR_INVALID_THISon the build image, the configs here forcenpm installfor the standalone packages, which sidesteps it.
The server is also a single Node HTTP process (REST + MCP), so server/ can alternatively
run on any Node host (Fly.io / Railway / Render) with the env vars above.
License
MIT — see LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。