memo
memo is a local MCP server that provides offline, private, and unlimited access to library documentation for coding agents.
Tools:
resolve_library_id: Resolve a library name (e.g., "flask") into candidate IDs with trust scores and latest version, optionally disambiguating with a query.get_docs: Retrieve relevant documentation chunks using hybrid BM25 + vector search. Cache hits are sub-millisecond; first-time misses trigger a one-time fetch and index (~5–60s). Supports version filtering.versions: List the known version history for a library, sourced from npm/PyPI.
Key features:
🏠 100% local – no API key, billing, or rate limits.
📴 Offline-first – after downloading the pre-built index (~16 MB, 65 libraries).
🔒 Private – queries and data never leave your machine (except for a first-ever cache miss).
🔍 Hybrid search – combines BM25 (SQLite FTS5) and cosine similarity over embeddings.
🧩 Extensible – easily add new libraries; self-service roadmap planned.
🤖 Compatible with Claude Desktop, Cursor, opencode, and any MCP-supporting agent.
Provides documentation lookup for the Flask web framework, indexing its official docs for search.
Searches GitHub repositories to resolve unknown library IDs and identify candidate documentation sources.
Resolves JavaScript/TypeScript libraries by querying the npm registry for metadata and download counts to locate official documentation.
Resolves Python libraries by querying PyPI for metadata and download counts to locate official documentation.
Provides documentation lookup for Python standard library modules.
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., "@memoHow to use Flask blueprints?"
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.
memo
Context7-style docs for your coding agent — free, unlimited, offline, private.
memo is a local MCP server that gives your agent up-to-date library documentation — the same idea as Context7, minus the strings attached: no billing meter, no API key, no rate limit, and your queries never leave your machine.
Why memo?
LLMs hallucinate APIs. They answer from stale training data — and most "docs tools" fix that by sending your queries to someone else's server. memo fixes it on your machine:
memo | Context7 | |
Price | $0, forever | Free tier is 1,000 API calls/month, then you're blocked (20 bonus calls/day); Pro is $10/seat/month, $10 per extra 1,000 calls (context7.com/plans) |
API key | None. Works out of the box | OAuth setup that generates an API key, sent as a |
Offline | Yes — one pre-built index (~16 MB) and you never touch the network again | Online only |
Rate limit | None. Unlimited, always | 1,000 calls/month on free tier |
Privacy | Queries resolved locally from | Every query + library name is sent to Upstash's servers |
Run anywhere | Python 3.10+, works on ARM (Raspberry Pi / Android-ish devices) | CLI needs Node.js 18+; backend runs on their infra |
Honest caveat: nothing here beats a curated docs provider in coverage. memo ships with 65 pre-built libraries today, and adding one is a one-line PR (see Contributing).
Related MCP server: docs-mcp
Quickstart (60 seconds)
Requires Python 3.10+ and uv:
# 1) install
uv tool install git+https://github.com/ngabzar02/memo-server
# 2) optional but recommended: download the pre-built index (65 libraries, ~16 MB)
bash tools/fetch-cache.sh
# 3) register the server, then ask your agent about any libraryopencode (opencode.json)
{
"mcp": {
"memo": {
"type": "local",
"command": ["memo"],
"enabled": true
}
}
}Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"memo": {
"command": "memo"
}
}
}Cursor (.cursor/mcp.json)
{
"mcpServers": {
"memo": {
"command": "memo"
}
}
}Make sure the
memobinary is on yourPATH(uv installs it into~/.local/bin). First call on a never-indexed library takes ~5–60 s (fetch + index once); every call after that is sub-millisecond.
How it works
One SQLite file, no services, no secrets:
resolve_library_id— turns"flask"into candidate library IDs with trust scores: curated aliases → built-in stdlib (py:json,node:fs) →directory.llmstxt.cloud→ npm/PyPI (trust = download counts) → GitHub search.get_docs— cache hit is sub-ms; on miss it crawls the docs (llms.txt → sitemap → README), extracts clean text with trafilatura, and chunks it (256 tokens, 50 overlap).Hybrid search — BM25 (SQLite FTS5) always, plus cosine similarity over embeddings (
bge-small-en-v1.5via fastembed/ONNX, stored in sqlite-vec) when vectors exist; normalized score fusion, top hits trimmed to a token budget. On-device the MCP path is FTS-first; full vectors come from the pre-built cache ormemo --warmup.versions— version history from npm/PyPI when available.Pre-built cache — a GitHub Actions workflow ingests all 65 libraries on every push and publishes the resulting
docs.db(~16 MB) as a release asset. One download, and you're fully offline.
registry → ingest (llms.txt/sitemap/crawl) → SQLite FTS5 + sqlite-vec
→ hybrid BM25+vector fusion → token-budget trim → MCP stdio → your agentData lives at ~/.local/share/memo/docs.db. Query it with any SQLite client.
Benchmark
20 real-world queries (frozen in bench/queries.md: 8 Python, 6 Node/TS, 3 web/frontend,
3 Go/other) scored binary hit/miss against Context7's public API:
# | Query | Target | memo | Context7 |
1 | how to create a route with a path parameter | flask | TBD | TBD |
2 | how to use async tasks and queues | celery | TBD | TBD |
3 | how to make a HTTP request with a timeout | requests | TBD | TBD |
4 | how to paginate results in the sqlalchemy ORM | sqlalchemy | TBD | TBD |
5 | how to define a custom logger | logging | TBD | TBD |
6 | how to read a CSV file into a DataFrame | pandas | TBD | TBD |
7 | how to seed random numbers for reproducibility | numpy | TBD | TBD |
8 | how to send multipart file upload | httpx | TBD | TBD |
9 | how to use environment variables in a script | python-dotenv | TBD | TBD |
10 | how to handle websocket connections | websockets | TBD | TBD |
11 | how to write a custom middleware | express | TBD | TBD |
12 | how to validate an email address | validator | TBD | TBD |
13 | how to use async fs read in a script | fs-extra | TBD | TBD |
14 | how to emit typed events | node:events | TBD | TBD |
15 | how to parse a query string | qs | TBD | TBD |
16 | how to read environment variables | dotenv | TBD | TBD |
17 | how to render a list with keys | react | TBD | TBD |
18 | how to add global CSS | nextjs | TBD | TBD |
19 | how to create a custom hook | react | TBD | TBD |
20 | how to run a goroutine | go | TBD | TBD |
TBD — the benchmark suite lives in bench/bench.py; results will be published to
bench/report.md when it runs.
memo vs Context7 vs mcpdoc
memo | Context7 | mcpdoc | |
Price | $0 | Free 1,000 calls/mo, then Pro $10/seat (plans) | $0 |
API key / OAuth | No | Yes | No |
Server | Local (stdio) | Remote ( | Local (stdio/SSE) |
Offline-capable | Yes, pre-built index | No | No persistent index |
Pre-built library index | Yes — 65 libs, ~16 MB | Yes (server-side) | No |
Library registry / name resolution | Yes — aliases, stdlib, npm/PyPI, GitHub | Yes | No — you configure each |
Search | Hybrid BM25 + vector embeddings | Server-side retrieval | None — fetches and parses on every call |
Version history | Yes (npm/PyPI) | Yes | No |
Rate limit | None | Yes (free tier) | None |
Your query leaves your device | No | Yes | Only to the docs sites you configured |
Language | Python 3.10+ | CLI needs Node 18+ | Python |
Roadmap
MCP server:
resolve_library_id/get_docs/versions(Context7-compatible API shape)Hybrid retrieval: FTS5 BM25 + embeddings, one-file SQLite
Pre-built cache pipeline (65 libraries, GitHub Actions → release asset)
Publish
bench/report.md— 20-query benchmark vs Context7Publish memo to PyPI (currently install via git)
Self-service: add a library at runtime without a PR
More libraries every week — the list is
cache-libs.txt, one line each
Contributing
One-line library additions, bugs, benchmarks — see CONTRIBUTING.md.
Short version: add the library name to cache-libs.txt in a PR; CI builds and
ships the new index automatically.
License
MIT — see LICENSE. Use it, fork it, ship it.
Available Tools
3 toolsget_docsA
Get relevant documentation chunks for a library and query. Cache hit: sub-ms. Cache miss: fetch+ingest+index once (~5-60s first time).
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| version | No | ||
| library_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals a non-obvious behavioral trait: caching performance (sub-ms on hit, 5-60s on miss first time, with fetch+ingest+index). Since no annotations are provided, this adds valuable transparency about potential delays and internal caching side effects, though it does not fully detail side effects or permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no redundant wording. It front-loads the core purpose and uses the second sentence for performance details, making it efficiently concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 3 parameters and an output schema, the description covers purpose and performance but misses key contextual details like version semantics and usage guidance. It is not fully complete for correct invocation, though output schema likely explains return structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It refers to 'library and query', mapping to library_id and query, but entirely omits the optional 'version' parameter, leaving the agent without clarity on its purpose or when to provide it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Get' with a clear resource 'relevant documentation chunks' and scope 'for a library and query'. It distinguishes from sibling tools 'versions' and 'resolve_library_id' by focusing on retrieving content rather than metadata or ID resolution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. Sibling tools exist, but the description does not mention them or any exclusions, leaving the agent without explicit usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_library_idA
Resolve a library name (e.g. 'flask', 'nextjs') to candidate library IDs with trust scores and latest version. query is optional context to disambiguate.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | ||
| library_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and reveals the output includes 'candidate library IDs with trust scores and latest version', which goes beyond schema. It also notes that 'query' can disambiguate. It doesn't discuss side effects or error handling, but for a lookup-style tool this is reasonable behavior disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, well-structured sentence conveys the core purpose and both parameters without padding. The examples are front-loaded and every clause adds value, making it easily scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the essential purpose, parameter roles, and high-level output (trust scores, latest version). With an output schema present and only two simple parameters, this is adequate. It lacks explicit guidance on when to use vs. siblings, but that is partially covered by purpose clarity, so a 4 is appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It defines library_name with examples and explains query as optional disambiguating context. This adds meaningful semantics beyond the empty schema, though it could be more detailed (e.g., constraints on query).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Resolve' and identifies the resource: library name to candidate library IDs. It also gives concrete examples ('flask', 'nextjs') and distinguishes from sibling tools by clearly stating the mapping from name to IDs, which get_docs and versions do not do.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by stating the tool resolves library names and mentions optional query context for disambiguation. However, it does not explicitly state when to prefer this tool over siblings like get_docs or versions, nor does it provide exclusion criteria or alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
versionsA
List known versions for a library (history dari npm/PyPI bila tersedia).
| Name | Required | Description | Default |
|---|---|---|---|
| library_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the transparency burden. It discloses that data comes from npm/PyPI and may be unavailable, which is useful. However, it does not mention behavior for unknown library_id or provide details beyond the output schema, leaving some gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence, front-loaded with the action and resource. It contains no unnecessary words, making it highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter list tool with an output schema, the description covers the core action and a data availability caveat. However, it lacks explicit usage guidance and parameter details, and with no annotations, the overall context remains somewhat incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. 'for a library' indicates library_id identifies a library, but it does not specify the format, range, or how to obtain the ID (e.g., via resolve_library_id). This adds minimal semantic value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'List known versions for a library' uses a specific verb and resource, and further specifies the data source (npm/PyPI). It clearly distinguishes from sibling tools get_docs and resolve_library_id, which serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'bila tersedia' (if available) implies when the tool might return no results, but it does not explicitly compare with alternatives or state when to prefer this tool over siblings. Usage context is only partially implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v1.0.0- First observed
get_docs - First observed
resolve_library_id - First observed
versions
TDQS
Each tool has a clearly distinct purpose: resolve_library_id maps names to IDs, versions lists available versions, and get_docs retrieves documentation chunks. There is no overlap or ambiguity between them.
Tool names mostly follow a verb_noun pattern (get_docs, resolve_library_id), but 'versions' is a standalone noun, which is a minor deviation. Overall the names remain clear and predictable.
With only 3 tools, the set is tightly scoped to the core documentation lookup workflow. No unnecessary tools, and all are essential to the purpose.
The tool set forms a complete pipeline: resolve a library name to an ID, check available versions, and fetch documentation chunks. There are no obvious gaps for the intended use case.
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
MCP server for querying Forkast documentation
MCP server for accessing curated awesome list documentation
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceLocal-first MCP server for querying multi-repo engineering documentation artifacts from a SQLite corpus.10AGPL 3.0
- AlicenseNot gradedqualityAmaintenanceProvides a local MCP server for searching and retrieving documentation from 22+ open-source projects, enabling AI coding assistants to access up-to-date docs without network dependency.112MIT
- AlicenseAqualityBmaintenanceA local MCP server that fetches official library documentation (llms.txt-first), caches it to disk, and serves relevant sections to coding agents offline with deterministic retrieval.34MIT
- FlicenseNot gradedqualityBmaintenanceLocal MCP server that indexes documentation from URLs/files into a vector database, enabling coding agents to search and use up-to-date library and API documentation.-
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/ngabzar02/memo-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server