kg-memory-mcp
An in-memory knowledge graph MCP server that gives coding agents structural and semantic recall over codebases by indexing Python source, ADR documents, and project configuration, exposing 7 tools for search, traversal, context retrieval, and natural-language Q&A.
README
kg-memory-mcp
An in-memory knowledge graph MCP server that gives coding agents structural and semantic recall over codebases. Indexes Python source, ADR documents, and project configuration via tree-sitter parsing and optional LLM extraction, then exposes 7 tools over the Model Context Protocol for search, traversal, context retrieval, and natural-language Q&A.
Key Features
- Structural indexing via tree-sitter -- extracts modules, classes, functions, imports, call graphs, and inheritance hierarchies from Python source
- ADR indexing -- parses architectural decision records into first-class graph nodes with GOVERNS edges linking decisions to the code they affect
- LLM semantic extraction -- enriches the graph with concepts, trade-offs, design principles, and cross-references that only exist in prose
- 3-tier entity reconciliation -- deduplicates nodes via exact match, fuzzy match, and LLM-based semantic similarity
- 7 MCP tools -- search, relate, context, path, ask, reindex, status
- Interactive graph visualization -- React + Sigma.js explorer with filtering, search, and node navigation
- Fast restarts -- persists the graph to
.kg-index.json; cold start loads from cache in milliseconds - Per-project configuration -- drop a
.mcp.jsonin any project root to enable
Architecture
Codebase Files
|
v
+------------------+ +------------------+
| tree-sitter | | LLM Extraction |
| (Python, MD) | | (litellm) |
| Structural parse | | Semantic parse |
+--------+---------+ +--------+---------+
| |
v v
+----+------------------------+----+
| In-Memory Knowledge Graph |
| 9 node types, 14 edge types |
| 5 O(1) indexes |
+----+-------------------+---------+
| |
v v
+------+------+ +------+------+
| 7 MCP Tools | | Viz Server |
| (stdio) | | (HTTP) |
+-------------+ +-------------+
Quick Start
1. Install
cd kg-memory-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e .
# Optional: file watcher for auto-reindex on save
pip install -e ".[watcher]"
2. Configure for a project
Create .mcp.json in your project root:
{
"mcpServers": {
"kg-memory": {
"command": "/path/to/kg-memory-mcp/.venv/bin/kg-memory-mcp",
"env": {
"KG_PROJECT_ROOT": "/path/to/your/project"
}
}
}
}
3. Start Claude Code
cd /path/to/your/project
claude
The MCP server launches automatically, indexes the codebase, and the 7 tools become available.
4. (Optional) Enable LLM extraction
Add to the env section of .mcp.json:
{
"KG_LLM_ENABLED": "true",
"KG_LLM_MODEL": "openai/gpt-4o-mini",
"OPENAI_API_KEY": "sk-..."
}
This adds concepts, decisions, and trade-offs extracted from ADRs and documentation.
5. (Optional) Graph visualization
cd viz && npm install && npm run build && cd ..
kg-memory-viz --project-root /path/to/your/project
# Open http://localhost:8765
Indexing Pipeline
The pipeline has four phases, orchestrated by server.py:reindex().
Phase 1: Structural Indexing (tree-sitter)
Three indexers run without any LLM calls.
Python Indexer
Parses all .py files using tree-sitter-python. Extracts:
| Node Type | Source | Example ID |
|---|---|---|
file |
Each .py file |
file:src/myapp/scoring.py |
module |
Directories with __init__.py |
module:src.myapp.domain |
class |
class definitions |
class:src.myapp.scoring.Scorer |
function |
def definitions (top-level and methods) |
func:src.myapp.scoring.Scorer.compute |
Edges created from code structure:
| Edge Type | Meaning | Detection |
|---|---|---|
contains |
file/module/class contains child | CST parent-child nesting |
imports |
file imports another file | import / from...import statements |
calls |
function calls another function | CST call expressions with name resolution |
inherits |
class extends base class | class Foo(Bar) superclass list |
method_of |
method belongs to class | Method nested inside class body |
Properties captured per node: path, line, docstring, params, decorators, bases, return type.
ADR Indexer
Parses docs/adr/*.md files using tree-sitter-markdown. Uses a two-pass approach:
First pass -- for each ADR file:
- Creates an
adrnode with title, status, decision summary, and principles - Extracts
conceptnodes from Decision subsection headings - Creates
GOVERNSedges via two strategies:- Path-based: backtick code spans matching module paths are resolved against the graph's path index
- Identifier-based: PascalCase/snake_case identifiers in backticks are resolved against the graph's name index (prefers class nodes)
- Creates
DEFINESedges linking the ADR to its concepts
Second pass -- resolves REFERENCES edges between ADRs (cross-references like ADR-0003).
Config Indexer
Parses CLAUDE.md (or configured project instructions file). Creates config nodes from h2 sections and extracts concept nodes from markdown tables.
Phase 2: LLM Semantic Extraction (optional)
When KG_LLM_ENABLED=true, the LLMExtractor sends each ADR's full text to the LLM and extracts:
| Extracted Type | Node Type | Edge to ADR | What it captures |
|---|---|---|---|
| Decisions | decision |
decided_in |
Statement, rationale, confidence score |
| Concepts | concept |
defines |
Name, definition, category (algorithm/pattern/principle/term) |
| Trade-offs | trade_off |
considered |
Option chosen, option rejected, reasoning |
| Principles | (property) | -- | Stored on the ADR node |
| Module governance | -- | governs |
Additional file paths parsed from prose |
All ADR extractions run concurrently via asyncio.gather(). Per-item Pydantic validation ensures one bad extraction doesn't drop the entire batch. Node IDs use SHA-256 hashes for deterministic, idempotent re-extraction.
What LLM extraction adds that structural indexing misses:
Structural indexing sees code and heading text. LLM extraction reads prose -- the "why" behind architecture. It captures rationale ("We chose Redis over Kafka because..."), design constraints ("Must support at-least-once delivery"), and trade-off reasoning that only exists in natural language. For a project with 15 ADRs, this typically adds 50-100+ semantic nodes and 100-200+ edges.
Phase 3: Entity Reconciliation
Deduplicates nodes created by different indexers without destructive merging.
Tier 1 -- Exact match: Normalizes names (lowercase, collapse whitespace, strip separators). Applies an alias dictionary ("kg" -> "knowledge graph", "mcp" -> "model context protocol", etc.). Creates SAME_AS edges with confidence 1.0.
Tier 2 -- Fuzzy match: Uses difflib.SequenceMatcher across 4 name/canonical combinations. Thresholds: >= 0.85 -> SAME_AS, >= 0.70 -> RELATED_TO.
Tier 3 -- LLM semantic match (only with LLM enabled): Pre-filters to concept/decision pairs sharing significant words. Batches 10 pairs per LLM call, up to 5 concurrent calls, hard-capped at 200 pairs. Thresholds: >= 0.85 -> SAME_AS, >= 0.60 -> RELATED_TO.
Transitive closure via Union-Find groups all SAME_AS pairs into clusters. Both nodes are preserved -- linked, not merged.
Phase 4: Persistence
The graph serializes to .kg-index.json via orjson with atomic write (temp file + rename). On next startup, the cache loads in milliseconds, skipping the full indexing pipeline.
Graph Schema
9 Node Types
| Type | Source | Description |
|---|---|---|
module |
Python indexer | Python package (directory with __init__.py) |
class |
Python indexer | Class definition |
function |
Python indexer | Function or method definition |
file |
Python indexer | Source file |
adr |
ADR indexer | Architectural Decision Record |
decision |
LLM extraction | Architectural decision with rationale |
concept |
ADR indexer + LLM | Technical concept or term |
trade_off |
LLM extraction | Evaluated trade-off with chosen/rejected options |
config |
Config indexer | Project configuration section |
14 Edge Types
| Type | Direction | Source |
|---|---|---|
contains |
parent -> child | Structural |
imports |
file -> file | Structural |
calls |
function -> function | Structural |
inherits |
class -> base class | Structural |
method_of |
method -> class | Structural |
depends_on |
module -> module | Structural |
references |
ADR -> ADR | Structural |
governs |
ADR/config -> file/class/function | Structural + LLM |
decided_in |
decision -> ADR | LLM extraction |
defines |
ADR/config -> concept | Structural + LLM |
implements |
code -> decision | LLM extraction |
considered |
trade_off -> ADR | LLM extraction |
same_as |
node -> node | Reconciliation |
related_to |
node -> node | Reconciliation |
MCP Tools Deep-Dive
All tools return markdown-formatted text designed for LLM consumption.
kg_search
Search the graph by keyword or concept name.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | yes | -- | Search term |
node_types |
string[] | no | all | Filter by node type |
limit |
integer | no | 20 | Max results (1-100) |
Scoring algorithm -- each node is scored against the query on a 4-tier scale:
| Score | Condition |
|---|---|
| 1.0 | Exact name match (case-insensitive) |
| 0.8 | Name contains query string |
| 0.6 | Query words appear in name (proportional to overlap) |
| 0.4 | Query found in any property value |
Results are sorted by score descending. Type-specific details are included: file path for files, title for ADRs, definition for concepts, path and line number for classes/functions.
Example: kg_search("scoring", node_types=["class", "function"]) returns the Scorer class, compute_decay_score function, and other scoring-related symbols -- ranked by relevance.
kg_relate
Expand the neighborhood of a node via BFS traversal.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
node_id |
string | yes | -- | Starting node (e.g., file:src/scoring.py) |
edge_types |
string[] | no | all | Filter by edge type |
depth |
integer | no | 1 | Traversal depth (1-5) |
limit |
integer | no | 30 | Max nodes (1-100) |
Traverses both outgoing and incoming edges. Results are grouped by node type with edges shown as source --[TYPE]--> target.
Example: kg_relate("adr:0008", depth=2) returns the ADR's decisions, trade-offs, concepts, governed files, and the classes/functions in those files -- a 2-hop view of everything ADR-0008 touches.
kg_context
Get full structured context for a specific file.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file_path |
string | yes | -- | Relative file path |
Unlike generic BFS, this follows specific semantic paths:
- Structure: classes and functions contained in the file (
CONTAINS) - Imports: what this file imports (
IMPORTSoutgoing) - Dependents: who imports this file (
IMPORTSincoming) - Governing ADRs: which ADRs govern this file (
GOVERNSincoming) - Decisions: architectural decisions from those ADRs (
DECIDED_IN) - Related concepts: concepts defined by those ADRs (
DEFINES) - Entity links: reconciled duplicates (
SAME_AS)
Example: kg_context("src/context_graph/domain/scoring.py") returns the file's classes, functions, what ADRs govern it (ADR-0008), key decisions like "Use Ebbinghaus decay scoring", related concepts, and who depends on this file.
kg_path
Find the shortest path between two nodes.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
source |
string | yes | -- | Source node ID |
target |
string | yes | -- | Target node ID |
max_depth |
integer | no | 5 | Max hops (1-10) |
Uses BFS over both edge directions. Returns the path as an indented chain showing each node's name, type, and ID.
Example: kg_path("concept:ebbinghaus_decay", "file:src/scoring.py") might return: concept:ebbinghaus_decay -> adr:0008 -> file:src/scoring.py -- showing how the concept connects to the implementation through the ADR.
kg_ask
Natural-language Q&A grounded in the knowledge graph. Requires KG_LLM_ENABLED=true.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
question |
string | yes | -- | Question about the codebase |
How it works:
- Searches the graph for the 10 most relevant nodes
- Expands the top 5 results by 1 hop to gather surrounding context
- Formats node properties (docstrings, decisions, definitions) as context
- Sends to the LLM with a structured prompt: WHY (motivation) -> WHAT (how it works) -> WHERE (code references)
- Appends a Sources section with provenance
Example: kg_ask("How does memory consolidation work?") searches for consolidation-related functions, ADRs, and concepts, then synthesizes a narrative explanation citing specific files and decisions.
kg_reindex
Trigger a full rebuild of the knowledge graph.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
llm |
boolean | no | true | Run LLM extraction |
Executes all 4 pipeline phases: structural indexing -> LLM extraction -> reconciliation -> persistence. Returns node/edge counts and breakdown by type.
kg_status
Show current graph statistics and server state. Takes no parameters.
Returns: total nodes/edges, counts by type, file watcher status, LLM model/enabled state, last indexed timestamp, reconciliation cluster count.
Graph Visualization
The viz/ directory contains a React + Sigma.js interactive graph explorer.
Tech stack: Vite, React 18, TypeScript, Tailwind CSS, Sigma.js v3 (WebGL), graphology, ForceAtlas2 layout.
Features:
- ForceAtlas2 force-directed layout (handles 1000+ nodes via WebGL)
- Filter by node type and edge type with instant toggle (Sigma reducers, no re-render)
- 4 filter presets: Architecture, Call Graph, ADRs, Show All
- Full-text search with type-priority matching and camera auto-center
- Click any node to see properties, connections grouped by edge type, and navigate to neighbors
- Node drag-and-drop, zoom controls, keyboard shortcuts (Escape,
/to search) - Search-selected nodes reveal their neighbors even when filtered out
Running:
cd viz && npm install && npm run build && cd ..
kg-memory-viz --project-root /path/to/project
# Open http://localhost:8765
The viz server is a zero-dependency Python HTTP server that reads .kg-index.json and serves the React build.
Configuration Reference
| Environment Variable | Default | Description |
|---|---|---|
KG_PROJECT_ROOT |
cwd | Project root to index |
KG_SOURCE_DIRS |
src |
Comma-separated source directories |
KG_ADR_DIR |
docs/adr |
ADR directory (none to disable) |
KG_CONFIG_PATH |
CLAUDE.md |
Project config file (none to disable) |
KG_INDEX_FILE |
.kg-index.json |
Graph persistence file |
KG_ADR_PATTERN |
^\d{4}-.+\.md$ |
Regex for ADR filename matching |
KG_WATCH_ENABLED |
true |
Enable file watcher for live reindex |
KG_LLM_ENABLED |
false |
Enable LLM extraction |
KG_LLM_MODEL |
claude-sonnet-4-6 |
LLM model (any litellm-supported model) |
Configuration can also be set in kg-memory.toml at the project root, with optional [aliases] for entity reconciliation.
Project Structure
kg-memory-mcp/
src/kg_memory/
server.py MCP server entry point, startup, reindex orchestration
graph.py KnowledgeGraph, Node, Edge, 9 NodeTypes, 14 EdgeTypes
retrieval.py Search, BFS traversal, shortest path, file context
extraction.py LLMExtractor: ADR/config extraction, Q&A, reconciliation
reconciliation.py 3-tier entity reconciliation (exact, fuzzy, LLM)
persistence.py orjson serialize/deserialize to .kg-index.json
config.py ProjectConfig from env vars / kg-memory.toml
watcher.py Watchdog file watcher for incremental reindex
tools.py 7 MCP tool definitions and handlers
viz_server.py HTTP server for graph visualization
indexers/
__init__.py Orchestrates all indexers, incremental reindex routing
python_indexer.py tree-sitter Python: modules, classes, functions, edges
adr_indexer.py tree-sitter Markdown: ADRs, concepts, GOVERNS edges
config_indexer.py tree-sitter Markdown: config sections, table concepts
viz/
src/
App.tsx Main layout, state management, keyboard shortcuts
types.ts TypeScript types, node/edge color maps
hooks/useGraphData.ts Fetch API, build graphology instance
components/
GraphCanvas.tsx Sigma.js container, ForceAtlas2, reducers, drag
FilterPanel.tsx Node/edge type toggles, presets
SearchBar.tsx Debounced search, type-priority results
NodeDetail.tsx Selected node properties and connection browser
StatsBar.tsx Graph statistics bar
tests/
test_graph.py Graph data model tests
test_extraction.py LLM extraction tests
test_reconciliation.py Entity reconciliation tests
test_retrieval.py Search and traversal tests
test_persistence.py Serialization tests
test_config.py Configuration tests
pyproject.toml Package config, dependencies, CLI entry points
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.