nvim-markdown-notes-memgraph

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.

Category
Visit Server

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

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 ~/notes or $NOTES_ROOT environment 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 Memgraph
  • health_check: Check if connection is alive
  • update_note: Update a note and its relationships in the graph
  • delete_note: Remove a note from the graph
  • query: Execute a Cypher query
  • reindex: Rebuild the entire graph from scratch
  • stats: Get graph statistics

Docker Configuration

Services

The Docker Compose setup includes two services:

  1. memgraph: The Memgraph graph database (port 7687)
  2. 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 python3 is not available, or neither uv nor pip is found, the prompt is silently skipped and the plugin falls back to bundled scripts.
  • Run :MemgraphInstallCLI at 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:

  1. Check if CLI is installed: Verify that nvim-markdown-notes-memgraph is in PATH
  2. Start services: Run nvim-markdown-notes-memgraph start to ensure Memgraph and MCP server are running
  3. Start bridge: Launch the bridge command and connect to Memgraph
  4. 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:

  1. Check that Docker is running:

    docker ps
    
  2. Check that Docker Compose is installed:

    docker compose version
    
  3. Check for port conflicts (Memgraph uses port 7687):

    lsof -i :7687
    
  4. Check Docker logs:

    docker compose logs memgraph
    docker compose logs mcp-server
    
  5. 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:

  1. Check service logs:

    docker compose logs memgraph
    
  2. Wait longer - the healthcheck can take up to 60 seconds.

  3. Restart the Memgraph service:

    docker compose restart memgraph
    

Notes directory not found

Problem: Error about notes directory not existing.

Solutions:

  1. Verify the path exists:

    ls ~/notes
    # or
    ls /path/to/notes
    
  2. Create the directory:

    mkdir -p ~/notes
    
  3. 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:

  1. Run :MemgraphInstallCLI inside Neovim to trigger the auto-install prompt.

  2. Or install manually:

    pip install git+https://github.com/xpcoffee/nvim-markdown-notes-memgraph.git
    
  3. 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:

  1. Check that Memgraph is running:

    nvim-markdown-notes-memgraph status
    
  2. Check that the port is exposed:

    docker compose ps
    
  3. 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:

  1. Check server logs:

    docker compose logs mcp-server
    
  2. Restart the MCP server:

    docker compose restart mcp-server
    
  3. Verify environment variables are set correctly:

    docker compose config
    

Graph data lost after restart

Problem: Graph data disappears after stopping services.

Solutions:

  1. Make sure you're using stop instead of down:

    nvim-markdown-notes-memgraph stop  # Preserves data
    
  2. Avoid using docker compose down -v which deletes volumes.

  3. Check that the volume exists:

    docker volume ls | grep memgraph-data
    

Permission errors in Docker

Problem: Permission denied errors when mounting notes directory.

Solutions:

  1. Check file permissions on your notes directory:

    ls -la ~/notes
    
  2. Make sure Docker has permission to access the directory (especially on macOS - check Docker Desktop settings).

  3. 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured