Skip to main content
Glama
Fieldnote-Echo

Fieldnote MCP

Official
README.md
# Fieldnote MCP

Local‑first memory and a symmetrical knowledge graph you can clone, start, and use in minutes.

This repo gives any agent or app three superpowers:

* **Auto‑store memory** — drop text in, it’s embedded and saved locally.
* **Auto‑recall & inject** — retrieve relevant memories and assemble a ready‑to‑paste context block.
* **Symmetrical Knowledge Graph** — every memory can mirror into Neo4j with inverse edges for clean traversal.

It’s portable, version‑pinned, works on macOS/Linux/WSL/Windows, and never asks for root.

---

## What’s inside

* **Qdrant** (vector DB) + **Neo4j** (graph) via Docker Compose
* **Cross‑platform shims** so the same commands work everywhere:

  * `memory-store`, `memory-search`, `context-inject`, `mcp-health`, `qdrant-run`
* **Hybrid retrieval** (dense + optional sparse)

  * Dense: MiniLM (pinned)
  * Sparse (optional): BGE‑M3 if available, with hashing fallback so demos never block
* **Health gate** to verify services before use
* **.env overrides** to configure without touching code

---

## Requirements

* **Docker Desktop** (macOS/Windows) or Docker Engine (Linux)
* **Python 3.11+** (for local CLI tools)
* \~2GB free disk space for local data

> No sudo needed. Everything lives in `~/dev/mcp` by default.

---

## Quickstart (copy/paste)

### macOS / Linux / WSL

```bash
# 0) place the repo at the expected path
mkdir -p ~/dev && cd ~/dev
# if you downloaded an archive, extract it to ~/dev/mcp; if using git:
# git clone <your-repo-url> mcp
cd ~/dev/mcp

# 1) bootstrap local env & command shims (idempotent)
./mcp-init.sh

# 2) env config (optional; overrides defaults)
cp .env.example .env
# edit .env as needed

# 3) start services
docker compose up -d

# 4) verify
make health

# 5) try the demo
make demo
```

### Windows (PowerShell)

```powershell
cd $HOME\dev\mcp
.\mcp-init.ps1
Copy-Item .env.example .env
# Edit .env if you want to change ports/creds

docker compose up -d
make health
make demo
```

Expected demo output:

* `memory-store` responds with `{ "status": "ok", "id": "…" }`
* `memory-search` prints top hits (hybrid if enabled)
* `context-inject` prints a compact block of the highest‑scoring memories (ready to paste into an agent prompt)

---

## Everyday commands

* `make compose-up` / `make compose-down` / `make compose-logs` – manage services
* `make health` – confirm Qdrant + Neo4j are reachable (and collection exists)
* `make demo` – store → search → inject in one go
* `make clean-data` – wipe Qdrant storage; `make clean-compose` also wipes Neo4j
* `qdrant-run` – portable runner if you’re not using Compose (Linux/Docker fallback)

CLI shims installed to `~/dev/mcp/bin`:

* `memory-store` — embed + upsert to Qdrant, then mirror to KG
* `memory-search` — dense (and sparse if enabled) retrieval with optional KG symmetry expansion
* `context-inject` — assembles a ready‑to‑paste context block from top memories
* `mcp-health` — sanity check for Qdrant/Neo4j

Registered in `plugins.json` so orchestrators can discover them.

---

## Configure

All defaults live in `config/memory.config.json`. Anything in **.env** overrides it at runtime.

**.env keys** (see `.env.example`):

| Key                         | Meaning                       | Default                                  |
| --------------------------- | ----------------------------- | ---------------------------------------- |
| `QDRANT_URL`                | Qdrant HTTP endpoint          | `http://127.0.0.1:6333`                  |
| `QDRANT_COLLECTION`         | Collection name               | `fieldnote_memory`                       |
| `DENSE_MODEL`               | SentenceTransformer model     | `sentence-transformers/all-MiniLM-L6-v2` |
| `TOP_K`                     | Search results to return      | `8`                                      |
| `NEO4J_URI`                 | Bolt URI                      | `bolt://127.0.0.1:7687`                  |
| `NEO4J_USER` / `NEO4J_PASS` | Neo4j credentials             | `neo4j` / `password`                     |
| `INJ_MAX_TOKENS`            | Max tokens to inject          | `2000`                                   |
| `INJ_SCORE_THRESHOLD`       | Minimum similarity to include | `0.75` (recommended)                     |
| `SPARSE_ENABLED`            | Enable sparse lane            | `true`                                   |
| `SPARSE_MODEL`              | Sparse model                  | `bge-m3`                                 |
| `SPARSE_HASH_DIM`           | Hashing fallback dim          | `32768`                                  |

> Tip: If you enable sparse on an existing collection created without it, start fresh (rename the collection or run `make clean-compose`).

---

## How it works

```
Store text ──▶ memory-store ──▶ Qdrant (dense [+ sparse])
                      │
                      └─▶ GraphSync hook ──▶ Neo4j (symmetrical edges)

Query      ──▶ memory-search ──▶ Qdrant hybrid search
                                   │
                                   └─▶ optional KG symmetry expansion

Assemble   ──▶ context-inject  ──▶ compact, thresholded context block
```

* **Symmetry**: When a relation has a defined inverse (e.g., `depends_on ↔ supports`), both directions are stored so traversals stay consistent.
* **Hybrid**: If `SPARSE_ENABLED=true`, sparse vectors are stored alongside dense. If BGE‑M3 isn’t installed, a hashing fallback keeps hybrid functional.

Open Neo4j Browser at `http://localhost:7474` to explore the graph. Qdrant Console is available via the API (`:6333`).

---

## Data & paths

* Qdrant data: `qdrant/storage/`
* Neo4j data: `neo4j/data/`
* Local venvs: `venv/` (Linux/macOS/WSL), `win-venv/` (Windows)
* PATH shims: `~/dev/mcp/bin`

All are git‑ignored by default.

---

## Troubleshooting

**"connection refused" on health check**

* Ensure Docker is running and `docker compose up -d` completed.

**Ports already in use**

* Change ports in `.env` / `docker-compose.yml` or stop the conflicting service.

**Windows symlink errors**

* Enable Developer Mode, or replace symlinks with tiny `.cmd` wrappers that call `python`.

**KG looks empty**

* Run the demo (`make demo`) or start storing memories. Graph is populated by the post‑store hook.

**Sparse/hybrid isn’t kicking in**

* Confirm `SPARSE_ENABLED=true`. If BGE‑M3 isn’t available, the hashing fallback still enables hybrid queries.

---

## Extend

* **Typed relations**: Enrich `hooks/graphsync_post_store.py` with light keyword rules or your own IE pipeline.
* **Keep models hot**: Wrap store/search in a small FastAPI service (you already have `uvicorn` + `fastapi`).
* **Provenance**: Add `source_id`, `confidence` to edges for auditing.

---

## Security

* Don’t commit real credentials. `.env` is git‑ignored.
* Everything runs locally by default; expose ports only if you know why.

---

## License

Project Navi - Dual License

This software is dual-licensed:

Option A: GNU Affero General Public License v3.0 (AGPL-3.0)
- For open source use
- See https://www.gnu.org/licenses/agpl-3.0.html

Option B: Commercial License (PNEUL-D v2.2)
- For proprietary/closed-source use
- Contact legal@projectnavi.ai for licensing

Full license terms: /docs/legal/

---

## Support

If something feels off, run:

```bash
make health
```

Then check `docker compose logs` for `qdrant` and `neo4j`. Open an issue or ping your team with the logs.