@ounie/mcp
v0.7.1
Published
Model Context Protocol server exposing your Ounie AI Second Brain to AI clients (Claude, Cursor, ChatGPT).
Readme
@ounie/mcp
A Model Context Protocol (MCP) server that exposes your Ounie AI Second Brain (https://ounie.com) to AI clients like Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, and other MCP-capable apps.
It speaks MCP over stdio and calls the Ounie REST API on your behalf using a Bearer API key.
Full setup guide (all clients, including remote/ChatGPT): https://ounie.com/docs/mcp
Tools
| Tool | Arguments | Description |
|---|---|---|
| ounie_list_brains | — | List your brains (id, name, emoji, source count). |
| ounie_explore_brains | q?, filter?, sort?, limit? | Discover other people's public brains — including paid marketplace listings — from the public Explore feed. Filter all\|free\|paid\|forkable, sort new\|popular\|price. Returns each brain's id, public URL, and pricing; any result's brainId works with the ask/search tools. |
| ounie_ask_brain | brainId, question, payWithCredits? | Ask a grounded question; returns an answer + citations. Works on your own brains, public brains (your normal question allowance), and paid listings — a paid brain returns a payment_required quote first; retry with payWithCredits: true after the user confirms. |
| ounie_ask_brain_set | setId, question | Ask a brain set — a primary brain blended with advisor brains — in one answer that tags each citation by source brain. |
| ounie_create_brain_set | primaryBrainId, advisorBrainIds, name? | Create a brain set: your primary brain + 1-4 advisor brains — your own, or public brains found with ounie_explore_brains. Returns the set_… id for ounie_ask_brain_set. |
| ounie_add_to_brain | brainId, content, title?, mode?, sourceUrl?, externalId? | Save a chat result (or any text). mode:'synthesize' (default) connects it into the wiki+graph and makes it citable; mode:'note' stores it verbatim. |
| ounie_add_note | brainId, title, body | Save a text note as a new source (verbatim). |
| ounie_add_link | brainId, url | Save a web link as a new source. |
| ounie_save_asset | brainId, title, description?, type?, status?, links?, tags?, client? | File an output made with the brain (carousel, article, ad…) into its Assets library. The opposite of ounie_add_to_brain: knowledge IN vs output OUT — assets are never ingested, never cited, cost nothing. Owner/editor only. |
| ounie_search | brainId, query, payWithCredits? | Retrieve & summarize relevant saved sources. |
| ounie_get_context | brainId, query | Retrieve the raw matching wiki pages without generating an answer — your assistant reasons over them and cites by slug. Cheaper/faster than ounie_ask_brain. Not available on paid brains over REST — use ounie_ask_brain with payWithCredits instead. |
| ounie_list_pending_synthesis | brainId, limit? | External synthesis (BYO model): list the sources parked for your model to synthesize (when the brain's synthesis mode is External via MCP). |
| ounie_get_source_text | sourceId | External synthesis: atomically claim a parked source and get its raw text + the synthesis contract (system prompt + JSON shape). First-writer-wins. |
| ounie_submit_synthesis | sourceId, title, markdown, entities? | External synthesis: submit the page you produced; validated against the same contract every house synthesis passes, then woven into the brain (ready, citable). |
Use a public brain as an advisor on your brain
A brain set blends your primary brain (authoritative facts) with up to 4 advisor brains (expert guidance) into one answer, every citation tagged by source brain — and advisors can be public brains you don't own. All from your assistant:
ounie_explore_brains— find the advisor (e.g.{ q: "sales", filter: "free" }).ounie_create_brain_set—{ primaryBrainId: <yours>, advisorBrainIds: [<public brain>] }→set_…id.ounie_ask_brain_set—{ setId, question }→ one blended, dual-cited answer.
Costs one normal question; free public advisors add nothing. Sets also appear in Brain Lab (https://ounie.com/dashboard/lab) and vice versa.
Paid brains (payWithCredits)
Some public brains are paid marketplace listings (priced in Ounie credits per question).
Asking one without the flag returns a payment_required notice with the price and any free
previews; your assistant should confirm the charge with you, then retry the same call with
payWithCredits: true to spend your prepaid credits. Free previews never need the flag, and
a non-answer ("I don't have info on this") is never charged. Top up credits at
Settings → Billing (https://ounie.com/dashboard/settings/billing).
Prefer ounie_get_context for answering
ounie_ask_brain runs Ounie's own LLM to write the answer; ounie_get_context returns just
the retrieved pages so your assistant writes the answer. When the assistant is already a
capable model (Claude, ChatGPT), prefer ounie_get_context — it's faster and avoids a
redundant second model call. Add a standing instruction to your client so it routes there by
default:
When answering from my Ounie brains, prefer
ounie_get_contextoverounie_ask_brain: callounie_get_context, read the returned pages, and write the answer yourself, citing pages inline as[[slug]]. Only useounie_ask_brainif I explicitly ask Ounie to answer.
External synthesis (bring your own model)
A brain owner can set a brain's synthesis mode to "External via MCP" (Settings → Synthesis model). When they do, Ounie still extracts each new source's text and embeds it house-side, but it does not run its own model to write the wiki page — it parks the source and waits for your model (e.g. Opus inside your own Claude Code / Claude.ai session) to do the synthesis. Ounie never holds your model credentials; your client does the work and pushes the result back through the same contract every house synthesis passes. Embeddings always stay house-side (one vector space), so retrieval quality is unchanged.
The loop, run from your assistant:
ounie_list_pending_synthesis{ brainId }— the sources waiting for synthesis. (Notes and verbatim sources never appear — they're never synthesized on any rail.)ounie_get_source_text{ sourceId }— claims the source (atomic, first-writer-wins within the brain's TTL) and returns its raw text plus the synthesis contract: the exact system prompt to follow and the JSON shape to return.- Synthesize the raw text with your own model, following the returned
contract.systemPromptexactly — produce{ title, markdown (with [[wikilinks]]), entities }. ounie_submit_synthesis{ sourceId, title, markdown, entities }— Ounie validates against the same contract, weaves the page into the brain, embeds it, and rebuilds the graph. The source becomesreadyand citable.
Error semantics:
- 409 (claim conflict) — another client claimed the source first (or it's no longer awaiting synthesis). Re-list and pick another. A claim older than the brain's TTL (default 24h) is reclaimable.
- 422 (invalid synthesis) — your payload failed the contract (e.g. missing
markdown, a too-long title, >20 entities). The response carries the validation issues; fix and resubmit.
A standing instruction for your client:
When I ask you to "synthesize my Ounie queue" for a brain, loop:
ounie_list_pending_synthesis→ for each,ounie_get_source_text, write the wiki page following the returned contract exactly, thenounie_submit_synthesis. Skip any source that returns a 409 and move on.
In Claude Code / Claude.ai, this loop ships as a packaged skill —
skills/ounie-synthesize/SKILL.md in the Ounie repo. It carries the full operational loop plus the
exact house synthesis contract (generated from SYNTH_CONTRACT, drift-gated in CI), so you can just
say "synthesize my Ounie queue" and the model drains the brain end-to-end against the same gate.
UI templates (ChatGPT app / MCP Apps)
Beyond tools, the server advertises the resources capability and serves a small set of
self-contained HTML UI templates (ui://ounie/<name>.html) so Apps-SDK hosts (ChatGPT,
MCP Inspector) render interactive cards inline. Non-Apps clients (Claude.ai, Claude Desktop,
Cursor) ignore resources and just use the text in each tool result — no behaviour change.
| Template | Tool(s) | What it shows |
|---|---|---|
| ui://ounie/brain-picker.html | ounie_list_brains | Grid of brains; tap to select. |
| ui://ounie/source-list.html | ounie_search | Ranked matching sources with links. |
| ui://ounie/saved-toast.html | ounie_add_note, ounie_add_link | Save confirmation. |
ounie_get_context and ounie_ask_brain are text-only by design (no card): the host model
writes the answer from the returned pages. (get_context briefly had an answer card; it was
dropped because the card sat above the streamed answer as an empty frame — the text answer is the
output.) Tool descriptors also carry MCP annotations (readOnlyHint/destructiveHint/
openWorldHint) so hosts label reads correctly.
The templates are defined once in web/ and vendored here as src/ui-resources.ts
(hand-synced copy, like the tool list) since this package can't import from web/. The hosted
POST /api/mcp is also a submitted ChatGPT app (OpenAI Apps directory); domain verification
is served from web/src/app/.well-known/openai-apps-challenge.
Get an API key
Generate a personal key (ounie_live_…) at Settings → API keys
(https://ounie.com/dashboard/settings/api-keys). You'll see the full key once — copy it
into the OUNIE_API_KEY field below.
Environment variables
| Var | Required | Default | Notes |
|---|---|---|---|
| OUNIE_API_KEY | ✅ | — | Bearer key from Settings → API keys. |
| OUNIE_BASE_URL | ❌ | https://ounie.com | Override for local/staging. |
The server exits with a clear error on stderr if OUNIE_API_KEY is missing.
(All protocol traffic uses stdout; logs go to stderr.)
Configure in Claude Desktop
Edit your claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"ounie": {
"command": "npx",
"args": ["-y", "@ounie/mcp"],
"env": { "OUNIE_API_KEY": "ounie_live_…" }
}
}
}Configure in Claude Code
claude mcp add ounie --env OUNIE_API_KEY=ounie_live_… -- npx -y @ounie/mcpConfigure in Cursor / Windsurf
~/.cursor/mcp.json (or the in-app MCP settings) uses the same shape as Claude Desktop.
Remote (HTTP) clients
Web clients connect to the hosted endpoint instead of running this package:
URL: https://ounie.com/api/mcp- Claude.ai / ChatGPT custom connectors sign in with OAuth — paste the URL, click Connect, and approve on Ounie. No API key needed; the server is a full OAuth 2.1 authorization server (dynamic client registration + PKCE). Manage/revoke connections at Settings → API keys → Connected apps.
- Header-capable clients (e.g. Cursor remote) can instead send
Authorization: Bearer ounie_live_…with a personal API key.
See https://ounie.com/docs/mcp for per-client steps.
Local development
Run from source without publishing:
cd mcp
npm install
npm run build # tsc -> dist/
npm run dev # or: tsx src/index.ts (no build step)Then point a client at the built file:
{
"mcpServers": {
"ounie": {
"command": "node",
"args": ["/absolute/path/to/ounie/mcp/dist/index.js"],
"env": {
"OUNIE_API_KEY": "ounie_live_…",
"OUNIE_BASE_URL": "http://localhost:3000"
}
}
}
}Files
mcp/
├── package.json # @ounie/mcp, type:module, bin, SDK dep
├── tsconfig.json # NodeNext, strict, outDir dist
├── README.md
└── src/
├── index.ts # MCP stdio server: tools (+ annotations) & resources
├── ui-resources.ts # vendored UI templates (ui://ounie/*) — sync w/ web
└── api.ts # typed fetch client for the Ounie REST APIWhen you change a UI template or the tool spec, update both web/ and this package
(src/index.ts tools, src/ui-resources.ts templates) — they're hand-synced.
ounie_search currently maps onto ounie_ask_brain with a retrieval-oriented prompt; it
will repoint to a dedicated search endpoint when one ships.
