nvim-markdown-notes-memgraph
Enables AI assistants to query and interact with a graph database of markdown notes, extracting entities like wikilinks, mentions, and hashtags.
README
nvim-markdown-notes-memgraph
Standalone CLI for Memgraph + MCP server with Docker Compose orchestration.
Extracts the Memgraph graph database functionality from nvim-markdown-notes into a reusable, independently installable package.
Features
- Docker Compose orchestration for Memgraph and MCP server
- CLI commands for managing services (start, stop, status)
- MCP server for AI assistant integration
- Neovim bridge for editor integration
- Automatic entity extraction (wikilinks, mentions, hashtags)
Requirements
- Python 3.10+
- Docker
- Docker Compose
- Build tools (needed to compile the Memgraph client):
- Ubuntu/Debian:
sudo apt install cmake build-essential libssl-dev - macOS:
brew install cmake openssl - Arch:
sudo pacman -S cmake base-devel openssl
- Ubuntu/Debian:
Docker and Docker Compose must be installed and running before using this package. The CLI manages Docker Compose services, so these are hard prerequisites.
To verify Docker is installed:
docker --version
docker compose version
Installation
Using pip
pip install nvim-markdown-notes-memgraph
Using uv
uv pip install nvim-markdown-notes-memgraph
From source
git clone https://github.com/username/nvim-markdown-notes-memgraph.git
cd nvim-markdown-notes-memgraph
pip install -e .
Auto-install from Neovim
If you use the nvim-markdown-notes plugin with memgraph.enabled = true, the plugin will detect the missing CLI and offer to install it for you automatically. See Auto-install from Neovim for details.
Verify installation
nvim-markdown-notes-memgraph --help
Updating
To update to the latest version:
uv tool install --force git+https://github.com/xpcoffee/nvim-markdown-notes-memgraph.git
Or if installed via pip:
pip install --upgrade git+https://github.com/xpcoffee/nvim-markdown-notes-memgraph.git
Usage
The CLI provides several commands for managing the Memgraph database and MCP server.
Global Options
All commands support the following global option:
--notes-root PATH: Root directory for markdown notes (defaults to~/notesor$NOTES_ROOTenvironment variable)
Example:
nvim-markdown-notes-memgraph --notes-root /path/to/notes start
Or set the environment variable:
export NOTES_ROOT=/path/to/notes
nvim-markdown-notes-memgraph start
Commands
start
Start Docker Compose services (Memgraph + MCP server).
nvim-markdown-notes-memgraph start
With custom notes directory:
nvim-markdown-notes-memgraph --notes-root ~/Documents/notes start
This command:
- Starts the Memgraph database container
- Starts the MCP server container
- Waits for services to be healthy (up to 60 seconds)
- Mounts your notes directory read-only into the MCP server container
Output:
Starting services with notes root: /home/user/notes
Services are healthy and ready!
Memgraph is running on localhost:7687
MCP server is connected and monitoring: /home/user/notes
stop
Stop Docker Compose services (Memgraph + MCP server).
nvim-markdown-notes-memgraph stop
This command stops all running containers but preserves the Memgraph data volume.
Output:
Stopping services...
Services stopped successfully.
status
Show status of Docker Compose services (Memgraph + MCP server).
nvim-markdown-notes-memgraph status
Output:
Service Status:
--------------------------------------------------------------------------------
Service: memgraph
Name: nvim-markdown-notes-memgraph-memgraph-1
State: running
Health: healthy
Ports: 7687:7687
--------------------------------------------------------------------------------
Service: mcp-server
Name: nvim-markdown-notes-memgraph-mcp-server-1
State: running
Health: N/A
Ports: N/A
--------------------------------------------------------------------------------
If no services are running:
No services are running.
Run 'nvim-markdown-notes-memgraph start' to start services.
config
Output MCP JSON configuration for use with MCP clients.
nvim-markdown-notes-memgraph config
With custom Memgraph host/port:
nvim-markdown-notes-memgraph config --memgraph-host localhost --memgraph-port 7687
Output (example):
{
"mcpServers": {
"nvim-markdown-notes-memgraph": {
"command": "nvim-markdown-notes-memgraph",
"args": ["serve"],
"env": {
"MEMGRAPH_HOST": "localhost",
"MEMGRAPH_PORT": "7687",
"NOTES_ROOT": "/home/user/notes"
}
}
}
}
This configuration can be added to MCP client config files (e.g., Claude Desktop, Continue, etc.).
serve
Run the MCP server directly (for container use or direct MCP client connections).
nvim-markdown-notes-memgraph serve
With custom configuration:
nvim-markdown-notes-memgraph --notes-root ~/notes serve --memgraph-host localhost --memgraph-port 7687
Or using environment variables:
export MEMGRAPH_HOST=localhost
export MEMGRAPH_PORT=7687
export NOTES_ROOT=~/notes
nvim-markdown-notes-memgraph serve
This command starts the MCP server over stdio. It's intended for use as a Docker container entrypoint or for direct MCP client connections.
bridge
Run the Neovim bridge (stdin/stdout JSON).
nvim-markdown-notes-memgraph bridge
With custom configuration:
nvim-markdown-notes-memgraph --notes-root ~/notes bridge --memgraph-host localhost --memgraph-port 7687
Or using environment variables:
export MEMGRAPH_HOST=localhost
export MEMGRAPH_PORT=7687
export NOTES_ROOT=~/notes
nvim-markdown-notes-memgraph bridge
This command starts the Memgraph bridge for Neovim integration. It communicates via JSON over stdin/stdout and uses the Bolt protocol to connect to Memgraph.
The bridge supports actions like:
connect: Establish connection to Memgraphhealth_check: Check if connection is aliveupdate_note: Update a note and its relationships in the graphdelete_note: Remove a note from the graphquery: Execute a Cypher queryreindex: Rebuild the entire graph from scratchstats: Get graph statistics
Docker Configuration
Services
The Docker Compose setup includes two services:
- memgraph: The Memgraph graph database (port 7687)
- mcp-server: The MCP server that connects to Memgraph and monitors your notes
Volumes
The Docker Compose setup uses two types of volumes for data persistence:
Memgraph Data Volume (Named Volume)
A named volume memgraph-data is automatically created to persist the Memgraph database across container restarts. This ensures your graph data is not lost when stopping services.
The volume is mounted at /var/lib/memgraph inside the Memgraph container.
Notes Directory (Bind Mount)
Your markdown notes directory is mounted read-only into the MCP server container at /notes.
Default location: ~/notes
Custom location: Use the --notes-root option or set the NOTES_ROOT environment variable:
# Using environment variable
export NOTES_ROOT=/path/to/my/notes
nvim-markdown-notes-memgraph start
# Or with CLI option
nvim-markdown-notes-memgraph --notes-root /path/to/my/notes start
The bind mount is read-only (:ro) to prevent accidental modifications to your notes from within the container.
Managing Volumes
# List volumes
docker volume ls
# Inspect the Memgraph data volume
docker volume inspect nvim-markdown-notes-memgraph_memgraph-data
# Remove volume (WARNING: deletes all graph data)
docker compose down -v
Graph Schema
The system extracts entities from your markdown notes and stores them in Memgraph with the following schema:
Nodes
(:Note {path, title, filename, last_modified, content_hash})- Markdown notes(:Person {name, display_name})- People mentioned with@username(:Tag {name})- Hashtags like#project
Relationships
(:Note)-[:LINKS_TO {line_number}]->(:Note)- Wikilinks between notes(:Note)-[:MENTIONS {line_number}]->(:Person)- Mentions of people(:Note)-[:HAS_TAG {line_number}]->(:Tag)- Tags in notes(:Person)-[:HAS_NOTE]->(:Note)- Person nodes link to notes about them
Entity Extraction
The system uses regex patterns to extract entities:
- Wikilinks:
[[note-name]]or[[note-name|display text]] - Mentions:
@username(alphanumeric with hyphens/underscores) - Hashtags:
#tagname(alphanumeric with hyphens/underscores)
MCP Integration
The MCP (Model Context Protocol) server provides tools for AI assistants to query and interact with your note graph.
Available MCP Tools
The server exposes several tools that AI assistants can call:
- find_notes_by_tag: Find all notes containing a specific tag
- find_notes_mentioning_person: Find notes that mention a person
- find_linked_notes: Find notes linked to/from a specific note
- search_notes_content: Full-text search across note content
- get_note_stats: Get statistics about a note (links, mentions, tags)
- list_all_tags: List all tags used across all notes
- list_all_people: List all people mentioned in notes
Using with Claude Desktop
Add the configuration to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
# Generate the config
nvim-markdown-notes-memgraph config >> claude_desktop_config.json
Then restart Claude Desktop.
Using with Continue
Add to your Continue configuration file:
nvim-markdown-notes-memgraph config
Copy the output to your Continue MCP servers configuration.
Neovim Integration
The CLI provides a bridge command that enables Neovim plugins to communicate with Memgraph via a JSON-over-stdin/stdout protocol.
Auto-install from Neovim
When memgraph.enabled = true in your plugin config and the CLI is not on PATH, the plugin will prompt you to install it. The install uses whichever tool is available: uv tool install (preferred), pip3 install, or pip install.
Configuration options (passed via opts.memgraph):
| Option | Default | Description |
|---|---|---|
install_prompt |
true |
Set to false to never prompt for installation |
install_source |
"git+https://github.com/xpcoffee/nvim-markdown-notes-memgraph.git" |
Package specifier passed to pip/uv. Override with a PyPI name or local path. |
Example configuration:
require("nvim-markdown-notes").setup({
notes_root_path = "~/notes",
memgraph = {
enabled = true,
-- Disable auto-install prompt
install_prompt = false,
-- Or point to a local checkout
install_source = "/path/to/nvim-markdown-notes-memgraph",
},
})
Behaviour:
- If the CLI is already on PATH, no prompt is shown.
- If the user declines the prompt, it won't appear again until Neovim restarts.
- If
python3is not available, or neitheruvnorpipis found, the prompt is silently skipped and the plugin falls back to bundled scripts. - Run
:MemgraphInstallCLIat any time to trigger the install prompt manually (resets any prior decline).
Bridge Protocol
The bridge command runs a persistent process that reads JSON requests from stdin and writes JSON responses to stdout. Each request/response is a single line of JSON.
Request format:
{
"action": "action_name",
"params": {
"key": "value"
}
}
Response format:
{
"success": true,
"data": {},
"error": null
}
Supported Actions
The bridge supports the following actions:
-
connect: Establish connection to Memgraph
{ "action": "connect", "params": { "host": "localhost", "port": 7687 } } -
health_check: Check if connection is alive
{ "action": "health_check", "params": {} } -
update_note: Update a note and its relationships in the graph
{ "action": "update_note", "params": { "path": "/path/to/note.md", "title": "Note Title", "content": "Note content...", "wikilinks": [{ "target_path": "/path/to/other.md", "line_number": 5 }], "mentions": [{ "name": "username", "line_number": 10 }], "hashtags": [{ "name": "tagname", "line_number": 15 }] } } -
delete_note: Remove a note from the graph
{ "action": "delete_note", "params": { "path": "/path/to/note.md" } } -
query: Execute a Cypher query
{ "action": "query", "params": { "cypher": "MATCH (n:Note) RETURN n.title LIMIT 5", "params": {} } } -
reindex: Rebuild the entire graph from scratch
{ "action": "reindex", "params": { "notes": [ { "path": "/path/to/note.md", "title": "Note Title", "content": "Content...", "wikilinks": [], "mentions": [], "hashtags": [] } ] } } -
stats: Get graph statistics
{ "action": "stats", "params": {} } -
quit: Gracefully shut down the bridge
{ "action": "quit", "params": {} }
Example: Neovim Lua Integration
Here's an example of how to integrate the CLI bridge into a Neovim plugin:
local M = {}
-- Job ID for the bridge process
local job_id = nil
local is_connected = false
-- Callback management
local pending_callbacks = {}
local callback_counter = 0
local response_buffer = ""
-- Parse JSON response
local function parse_response(line)
local ok, result = pcall(vim.json.decode, line)
if ok then
return result
end
return nil
end
-- Send a request to the bridge
local function send_request(action, params, callback)
if not job_id then
if callback then
callback(false, nil, "Bridge not started")
end
return
end
local request = vim.json.encode({
action = action,
params = params or {}
})
if callback then
callback_counter = callback_counter + 1
pending_callbacks[callback_counter] = callback
end
vim.fn.chansend(job_id, request .. "\n")
end
-- Handle stdout from bridge
local function on_stdout(_, data, _)
for _, line in ipairs(data) do
if line and line ~= "" then
response_buffer = response_buffer .. line
local response = parse_response(response_buffer)
if response then
response_buffer = ""
-- Find oldest pending callback
local oldest_key = nil
for key, _ in pairs(pending_callbacks) do
if oldest_key == nil or key < oldest_key then
oldest_key = key
end
end
if oldest_key and pending_callbacks[oldest_key] then
local cb = pending_callbacks[oldest_key]
pending_callbacks[oldest_key] = nil
cb(response.success, response.data, response.error)
end
-- Update connection state
if type(response.data) == "table" then
if response.data.status == "healthy" then
is_connected = true
elseif response.data.message and response.data.message:match("^Connected") then
is_connected = true
end
end
end
end
end
end
-- Start the bridge process
function M.start_bridge(callback)
if job_id then
if callback then
callback(true, "Bridge already running")
end
return
end
-- Start the bridge command
local cmd = { "nvim-markdown-notes-memgraph", "bridge" }
job_id = vim.fn.jobstart(cmd, {
on_stdout = on_stdout,
on_exit = function(_, exit_code, _)
job_id = nil
is_connected = false
for key, cb in pairs(pending_callbacks) do
cb(false, nil, "Bridge exited with code " .. exit_code)
pending_callbacks[key] = nil
end
end,
stdout_buffered = false,
})
if job_id <= 0 then
job_id = nil
if callback then
callback(false, "Failed to start bridge")
end
return
end
-- Connect to Memgraph
vim.defer_fn(function()
send_request("connect", { host = "localhost", port = 7687 }, callback)
end, 100)
end
-- Ensure services are running and connected
function M.ensure_services(callback)
-- Check if CLI is installed
if vim.fn.executable("nvim-markdown-notes-memgraph") == 0 then
if callback then
callback(false, nil, "nvim-markdown-notes-memgraph CLI not installed")
end
return
end
-- Start services if not running
vim.fn.jobstart(
{ "nvim-markdown-notes-memgraph", "start" },
{
on_exit = function(_, exit_code, _)
if exit_code == 0 then
-- Services started, now start bridge
M.start_bridge(callback)
else
if callback then
callback(false, nil, "Failed to start services")
end
end
end
}
)
end
-- Update a note in the graph
function M.update_note(path, title, content, entities, callback)
send_request("update_note", {
path = path,
title = title,
content = content,
wikilinks = entities.wikilinks or {},
mentions = entities.mentions or {},
hashtags = entities.hashtags or {}
}, callback)
end
-- Get graph statistics
function M.get_stats(callback)
send_request("stats", {}, callback)
end
return M
Usage in Your Plugin
local graph = require("your_plugin.graph")
-- Ensure services are running and connect
graph.ensure_services(function(success, data, err)
if success then
print("Connected to Memgraph!")
-- Update a note
graph.update_note(
"/home/user/notes/example.md",
"Example Note",
"This is the content...",
{
wikilinks = {
{ target_path = "/home/user/notes/other.md", line_number = 5 }
},
mentions = {
{ name = "alice", line_number = 10 }
},
hashtags = {
{ name = "project", line_number = 15 }
}
},
function(success, data, err)
if success then
print("Note updated!")
else
print("Error: " .. (err or "unknown"))
end
end
)
else
print("Failed to connect: " .. (err or "unknown"))
end
end)
ensure_services() Pattern
The ensure_services() pattern is the recommended way to integrate the CLI with your Neovim plugin:
- Check if CLI is installed: Verify that
nvim-markdown-notes-memgraphis in PATH - Start services: Run
nvim-markdown-notes-memgraph startto ensure Memgraph and MCP server are running - Start bridge: Launch the bridge command and connect to Memgraph
- Handle errors gracefully: Provide helpful error messages if any step fails
This pattern ensures that:
- Services are automatically started when needed
- Users don't need to manually start Docker containers
- The plugin works out of the box after installing the CLI
- Service management is transparent to the user
Environment Variables
The bridge command respects the following environment variables:
NOTES_ROOT: Root directory for markdown notes (default:~/notes)MEMGRAPH_HOST: Memgraph host (default:localhost)MEMGRAPH_PORT: Memgraph port (default:7687)
You can set these in your Neovim configuration:
vim.env.NOTES_ROOT = vim.fn.expand("~/Documents/notes")
vim.env.MEMGRAPH_HOST = "localhost"
vim.env.MEMGRAPH_PORT = "7687"
Or pass them when starting the bridge:
NOTES_ROOT=~/Documents/notes nvim-markdown-notes-memgraph bridge
Troubleshooting
Services won't start
Problem: docker compose command fails or services won't start.
Solutions:
-
Check that Docker is running:
docker ps -
Check that Docker Compose is installed:
docker compose version -
Check for port conflicts (Memgraph uses port 7687):
lsof -i :7687 -
Check Docker logs:
docker compose logs memgraph docker compose logs mcp-server -
Try stopping and removing all containers:
docker compose down nvim-markdown-notes-memgraph start
Services are unhealthy
Problem: start command times out waiting for services to be healthy.
Solutions:
-
Check service logs:
docker compose logs memgraph -
Wait longer - the healthcheck can take up to 60 seconds.
-
Restart the Memgraph service:
docker compose restart memgraph
Notes directory not found
Problem: Error about notes directory not existing.
Solutions:
-
Verify the path exists:
ls ~/notes # or ls /path/to/notes -
Create the directory:
mkdir -p ~/notes -
Set the correct path:
nvim-markdown-notes-memgraph --notes-root /correct/path start
CLI not installed
Problem: The plugin falls back to bundled scripts or reports the CLI is missing.
Solutions:
-
Run
:MemgraphInstallCLIinside Neovim to trigger the auto-install prompt. -
Or install manually:
pip install git+https://github.com/xpcoffee/nvim-markdown-notes-memgraph.git -
Verify the CLI is on PATH:
nvim-markdown-notes-memgraph --help
Installation fails with cmake error
Problem: pip install or uv tool install fails with a long error trace mentioning cmake or CMakeLists.txt.
Solution: The pymgclient dependency requires cmake and a C compiler to build from source. Install the build prerequisites:
Ubuntu/Debian: sudo apt install cmake build-essential libssl-dev
macOS: brew install cmake openssl
Then retry the installation.
Connection refused to Memgraph
Problem: Cannot connect to Memgraph on localhost:7687.
Solutions:
-
Check that Memgraph is running:
nvim-markdown-notes-memgraph status -
Check that the port is exposed:
docker compose ps -
Try connecting directly:
docker exec -it nvim-markdown-notes-memgraph-memgraph-1 mgconsole
MCP server not responding
Problem: MCP server doesn't respond to requests.
Solutions:
-
Check server logs:
docker compose logs mcp-server -
Restart the MCP server:
docker compose restart mcp-server -
Verify environment variables are set correctly:
docker compose config
Graph data lost after restart
Problem: Graph data disappears after stopping services.
Solutions:
-
Make sure you're using
stopinstead ofdown:nvim-markdown-notes-memgraph stop # Preserves data -
Avoid using
docker compose down -vwhich deletes volumes. -
Check that the volume exists:
docker volume ls | grep memgraph-data
Permission errors in Docker
Problem: Permission denied errors when mounting notes directory.
Solutions:
-
Check file permissions on your notes directory:
ls -la ~/notes -
Make sure Docker has permission to access the directory (especially on macOS - check Docker Desktop settings).
-
On Linux, check SELinux/AppArmor settings if applicable.
Development
Running tests
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=src/nvim_markdown_notes_memgraph
Building from source
# Install in development mode
pip install -e .
# Build wheel
pip install build
python -m build
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.