Manent

Manent

MCP server that turns a git-versioned Markdown vault into a queryable memory for AI agents, providing tools like brain_search, brain_read, and brain_neighbors.

Category
访问服务器

README

Manent

Verba volant, scripta manent. — Spoken words fly away, written words remain.

File-first, git-versioned memory for AI agents. A specification plus a toolchain that turns a plain Markdown vault (Obsidian-compatible) into a queryable, lintable, MCP-served brain that any agent can mount.

Context windows evaporate — verba volant. Manent is the written memory that remains: plain files you can read, diff, and own.

Why

Agent memory today is either a proprietary vector-DB dump (lock-in, no audit trail, no human curation) or an unstructured pile of notes (no schema, no retrieval quality, no guarantees). Manent takes a third path:

  • Markdown files are the source of truth. Everything else — search indexes, graphs, embeddings — is derived and rebuildable from scratch.
  • Git is the sync and audit backbone. Every memory write is a commit: who, when, why.
  • A closed, versioned schema (JSON Schema 2020-12) for note types and typed edges. Linted in CI — a malformed note never lands.
  • MCP is the access layer. Any MCP client (Claude, ChatGPT, VS Code, Cursor, your own agent) mounts the brain with a URL — no custom SDK.

Packages

Package What
@manent/spec The vault specification: note types, frontmatter schemas, typed edges, layout
@manent/core Parser (frontmatter + wikilinks), vault loader, graph builder
@manent/retrieval Ranking: BM25 lexical, local dense embeddings, graph expansion, RRF fusion
@manent/eval Eval harness: golden sets, recall@k / MRR / nDCG, regression gate
@manent/lint Rule engine: schema-lint, link-lint, duplicate/orphan detection
@manent/server MCP server over a vault: brain_search, brain_read, brain_neighbors — see Protocol eras
@manent/cli `manent init

Quickstart

npm install
npm run build

# scaffold a new vault
node packages/cli/dist/index.js init my-vault

# lint it
node packages/cli/dist/index.js lint my-vault

# serve it over MCP (stdio)
node packages/cli/dist/index.js serve my-vault

# or over Streamable HTTP with bearer auth (for remote clients / claude.ai)
node packages/cli/dist/index.js serve my-vault --http 3939 --token <long-random-token>

Register with Claude Code:

claude mcp add mybrain -- node <repo>/packages/cli/dist/index.js serve <vault>

Use from claude.ai (web)

Verified working. claude.ai will not connect to a remote MCP server that has no discoverable OAuth metadata, so the HTTP server ships its own single-owner authorization server: your vault token is the login password.

  1. Serve over HTTP and expose it — a tunnel (cloudflared tunnel --url http://127.0.0.1:3939) or a reverse proxy. HTTPS is required by OAuth for non-localhost redirects.
  2. claude.ai → Settings → Connectors → Add custom connector → URL https://<your-host>/mcp. Leave the OAuth Client ID empty; discovery and registration are automatic.
  3. claude.ai opens the consent page. Paste your vault token, approve, done.

Access tokens are HMAC-derived from the vault token rather than stored, so a connected client survives server restarts. Rotating the vault token invalidates every issued token.

Three details worth knowing:

  • The endpoint binds 127.0.0.1 by default and refuses to start without a token — a vault never reaches the network unauthenticated by accident.
  • Redirect URIs are restricted to an allowlist (claude.ai, claude.com, localhost) and must be HTTPS. PKCE S256 is mandatory; authorization codes are single-use and expire in five minutes.
  • /t/<token>/mcp also works for clients that can neither set headers nor do OAuth. That URL is a credential — treat it like a password.

Run npm run test:oauth to exercise the whole flow, including wrong token, failed PKCE, code replay, forged token and disallowed redirect.

Retrieval, measured

Ranking changes are decided by an eval harness, not by intuition. manent eval scores a retriever against three kinds of query, and each kind answers a different question:

Source How it's built What it measures
curated hand written, wording close to the note lexical recall
oblique asks for the concept without the note's words semantic recall — the hard case
auto derived from each note's own description broad regression signal, no labelling
manent eval <vault> --golden eval/golden-aios.json          # bm25 vs hybrid side by side
manent eval <vault> --golden ... --save baseline.json       # record a baseline
manent eval <vault> --golden ... --baseline baseline.json   # exits 1 if a metric dropped

Results on a real 305-note vault (298 queries), in the order they were measured:

Ranker curated hit@1 curated MRR oblique MRR auto hit@1
BM25, naive tokenizer 45.0% 0.621 — 97.8%
BM25 + stopwords, length-gated prefix/fuzzy 75.0% 0.863 0.099 97.8%
Hybrid (graph expansion + recency + centrality) 75.0% 0.863 0.104 93.0%
Dense only (multilingual-e5-small, local) 95.0% 0.975 0.131 94.4%
Fused, lexical 1 : dense 2 (RRF) 100.0% 1.000 0.208 95.9%

Four findings worth keeping:

  1. Tokenization was the first big win. Dropping stopwords and allowing prefix/fuzzy matching only on longer terms moved curated hit@1 by 30 points. With prefix matching on, di matches diritto, disposizione, documento — long notes then win on accumulated noise.
  2. Graph expansion did not pay. Once retrieval is lexically sound, Personalized PageRank over wikilinks adds nothing measurable and the recency/centrality multipliers cost ~5 points on the auto set. hybrid stays available for vaults with a much denser link structure. PPR amplifies a good seed — it cannot create one.
  3. Lexical and dense fail in opposite directions, so fusing them beats both. Dense alone found the notes BM25 missed but blurred exact slugs and identifiers; at equal RRF weights the lexical list pulled correct answers off the top spot. Weighting dense twice reached 100% hit@1 on hand-written queries, trading ~2 points on the synthetic set.
  4. Vocabulary mismatch is improved, not solved: oblique MRR went 0.099 → 0.208 and recall@5 25% → 37.5%. A question whose wording shares nothing with its note is still often unreachable.
  5. Chunking made it worse here, and that is informative. Splitting notes into passages was the obvious next step; measured, it cost 10–15 points of curated hit@1. With ~2400 passages instead of 307 notes, max-scoring gives a long note one chance per passage to match by luck, so retros and legal texts float up — the same length bias BM25 normalizes away. Damping by passage count (max-norm) recovers oblique recall (MRR 0.221) but still trades away curated and auto accuracy.
Passages curated hit@1 oblique MRR auto hit@1 Configuration
307 95.0% 0.133 95.9% one passage per note, full body
2419 90.0% 0.096 96.3% 1000-char passages, best-passage scoring
2419 85.0% 0.221 91.9% 1000-char passages, length-damped
1181 75.0% 0.013 95.9% 2000-char passages, best-passage
1181 55–75% ≤0.19 73–79% any size, without the contextual prefix

Two things to keep from that: the contextual prefix is not optional — a passage stripped of its note's name and description loses the subject and everything collapses; and truncation beats completeness on this corpus (1400-char single passage scored 100%, full body 95%). Notes here are atomic and front-loaded — one fact each, stated at the top — so the tail is elaboration that only blurs the vector. Raise maxPassages for vaults of long, multi-topic documents, where the answer can sit in the middle of a note.

Reproduce any sweep: scripts/tune-retrieval.mjs (graph/scoring params), scripts/tune-fusion.mjs (lexical/dense balance), scripts/tune-chunking.mjs (passage size, prefix, aggregation).

Dense retrieval setup

Embeddings run locally — no API key, nothing leaves the machine, and query time needs no network. The model is an optional dependency, so bm25 keeps working without it:

npm install @huggingface/transformers      # ~120 MB model, downloaded on first use
manent serve <vault> --retriever fused     # or --retriever dense
manent eval <vault> --golden ... --retriever all

Vectors are cached in <vault>/.manent/embeddings.json, keyed by content hash: editing one note re-embeds one note. Changing the model invalidates the cache. manent init gitignores that directory — it is derived data, rebuildable from the notes.

Protocol eras

MCP revision 2026-07-28 removed the initialize handshake and sessions; every shipping client still speaks the older, handshake-based revisions. Manent serves both, as two separate implementations rather than one blended path:

Era Revisions How File
legacy 2025-11-25, 2025-06-18, 2025-03-26 official SDK, initialize handshake src/legacy.ts
modern 2026-07-28 native: no handshake, resultType, caching hints, server/discover src/modern.ts

Both adapters expose the same tools because the tool definitions live in one place (src/tools.ts); the eras cannot drift in capability. src/http.ts only routes.

manent serve <vault> --http 3939            # auto: routes each request to its era
manent serve <vault> --http 3939 --era legacy   # pin: modern requests get the fallback signal
manent serve <vault> --http 3939 --era modern   # pin: 2026-07-28 only

Auto-detection keys on the RPC itself (server/discover, subscriptions/listen) or a declared 2026+ protocol version — never on the Mcp-Method transport header alone, since dual-era clients send it with a legacy initialize too. npm run test:era exercises all three modes.

Vault layout (see packages/spec/SPEC.md)

vault/
├─ MEMORY.md          # global index, loaded every session (type: index)
├─ HOME.md            # human navigation hub (type: moc)
├─ memory/            # global lessons: feedback_*.md, reference_*.md
├─ projects/<p>/      # per-project knowledge, handoffs, retros
├─ moc/               # one map-of-content per branch
├─ people/            # person notes (type: persona)
├─ library/           # raw dated sources: YYYY-MM-DD-<slug>.md
├─ wiki/              # compounding wiki: entities/ concepts/ queries/
├─ knowledge/         # read-only mirrors from external repos
└─ secrets/           # NEVER synced, NEVER indexed (enforced)

Roadmap

  • [x] Spec v0.1 + lint + graph + BM25 search + MCP stdio server
  • [x] Eval harness: three query kinds, recall@k / MRR / nDCG, regression gate
  • [x] Lexical retrieval done properly (stopwords, length-gated prefix/fuzzy): +30 pts hit@1
  • [x] Graph expansion (Personalized PageRank) + RRF fusion — built, measured, not default
  • [x] Local dense embeddings + RRF fusion: curated hit@1 75% → 100%, oblique MRR 0.10 → 0.21
  • [x] Chunk-level embeddings — implemented, measured, not default: worse on atomic notes
  • [ ] Curation: embedding-cluster dedup, contradiction detection, Leiden community → MOC suggestions
  • [x] Streamable HTTP transport, stateless, bearer-token auth
  • [x] OAuth 2.1 (RFC 9728 metadata, dynamic registration, PKCE) — connects from claude.ai
  • [x] Two protocol eras as separate implementations: legacy handshake (SDK) and native 2026-07-28
  • [ ] Vault hot-reload — the server currently indexes at startup
  • [ ] Tasks extension (io.modelcontextprotocol/tasks) on the modern path — long-running skills
  • [ ] MCP Apps (ui://): skill launcher, review queue, graph explorer
  • [ ] MCP spec 2026-07-28 wire upgrade (no-handshake core, server/discover, cacheable results, Tasks extension) — when the official SDK ships it
  • [ ] Write path: brain_write behind MRTR approval (input_required)
  • [ ] MCP Apps: skill launcher, review queue, graph explorer (ui:// templates)

License

Apache-2.0 — see LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选