Contributing¶
localmem-mcp is small on purpose, and contributions that keep it small are the most welcome kind. The whole project is about 700 lines — you can read it in one sitting.
By participating, you agree to the Code of Conduct.
The one rule¶
Nothing leaves the user's machine
No telemetry, no hosted services, no API keys, no update pings. The only network call in the whole project is fastembed's one-time model download. A PR that breaks this won't be merged, however good it is otherwise.
Beyond that: this is a memory tool, not an agent framework. Features that make storing and recalling memories better are in scope; features that turn it into something else are not. If you're unsure, open an issue before building — much nicer than having a finished PR turned down.
Setup¶
git clone https://github.com/OpenAgentHQ/localmem-mcp
cd localmem-mcp
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest -q
Python 3.10+. On Windows the venv binaries live in .venv\Scripts\.
The suite runs offline in about a second, because it uses a deterministic stub embedder instead of the real model. To exercise the real fastembed path (the first run downloads ~90 MB):
Working on the docs¶
Live-reloads at http://127.0.0.1:8000. The API reference is generated from
docstrings by mkdocstrings, so improving a docstring improves the site.
Where things are¶
src/localmem_mcp/
store.py MemoryStore — SQLite schema, embeddings, hybrid search. The core.
server.py FastMCP server. Tool docstrings are the agent-facing UX.
cli.py argparse entry point. No args = run the server.
tests/
test_store.py store behaviour, against a stub embedder
test_server.py MCP tools end-to-end via fastmcp's in-memory Client
docs/ this site
Architecture explains how the pieces fit and why.
Making a change¶
- Branch off
main. - Make the change, with a test.
- Run
pytest -qandruff check .. - Open a PR.
CI runs ruff, the suite across Python 3.10–3.13 on Linux/macOS/Windows, a job against real fastembed embeddings, and a packaging check. All green to merge.
Some changes need extra care, and the PR template asks about each:
MCP tool signatures and docstrings
Models read these to decide when to call a tool. A wording change is a behaviour change — quote the before/after in your PR.
Schema changes
Describe the migration story. People have real memories in these files, and losing them is unforgivable in a memory tool.
Ranking changes
Rarely free. Say what got better and what got worse.
New dependencies
Install-to-working under 30 seconds is a project goal. Justify the weight.
Testing¶
Keep new tests offline — use StubEmbedder from tests/test_store.py. It's
built so "sqlite" scores nearer "database" than "coffee", which is enough
structure to assert real ranking behaviour without a model.
Anything genuinely needing the real model goes behind LOCALMEM_TEST_FASTEMBED,
like test_fastembed_roundtrip does. CI runs that job for you.
For MCP-level tests, drive the tools through fastmcp.Client(server) as
tests/test_server.py does — that's the path a real client takes, so it catches
problems that calling the functions directly would miss.
Style¶
- Type hints throughout, with
from __future__ import annotationsat the top. - Comments explain why, not what. Match the density around them.
ruffis the arbiter; line length 100.
Good first contributions¶
- More client setup recipes for Connect your client
forget/prune tooling: delete by tag, by age, or by id- Export/import to JSONL, so a memory store is portable
- An
update_memorytool — the schema already carriesupdated_at - Benchmarks: how does search hold up at 10k / 100k memories?
- Docs fixes and typos — genuinely useful, always welcome
Issues labelled good first issue
are scoped to be approachable without deep context.
Reporting bugs¶
Use the issue template.
Include your OS, Python version, localmem-mcp --version, which client you used,
and the output of localmem-mcp stats.
Please don't paste the contents of your memory database — it's yours, and we don't want to see it.
For security issues, report privately via the security policy rather than a public issue.
Releasing¶
Maintainers only: bump version in pyproject.toml, tag vX.Y.Z, push the tag.
The release workflow builds and publishes to PyPI via Trusted Publishing (OIDC)
— no tokens or secrets to manage.