Nexus MCP
by cheezcake
README.md
# Nexus MCP
Knowledge-graph task operating system, exposed as an MCP server for Claude Code.
Nexus maintains a temporal knowledge graph (nodes, directed edges, FTS5 search, recursive CTE traversal) in SQLite. This package provides:
1. **MCP server** (stdio) -- 24 tools for graph CRUD, view management, search, and traversal
2. **Graph context hook** -- Claude Code UserPromptSubmit hook that auto-resolves entity references in your prompts
3. **Web UI** (optional) -- Quart companion app for browsing the graph, D3 visualization, and desktop-metaphor view management
## Quick start
```bash
cd ~/Dropbox/code/python/nexus_mcp
# Create venv (check architecture first)
python3 -m venv venv # x86_64 (niviniel)
# python3 -m venv venv_laptop # arm64 (nivinielicus)
# Install
venv/bin/pip install -e .
```
## Installation
### 1. MCP server
Add to your Claude Code settings (`~/.claude/settings.json` or project `.claude/settings.json`):
```json
{
"mcpServers": {
"nexus-mcp": {
"type": "stdio",
"command": "/Users/cheezcake/Dropbox/code/python/nexus_mcp/venv/bin/python",
"args": ["-m", "nexus_mcp"]
}
}
}
```
For arm64 (nivinielicus), replace `venv` with `venv_laptop`.
**Environment variables** (optional):
| Variable | Default | Description |
|----------|---------|-------------|
| `NEXUS_DB_PATH` | `../nexus.db` (relative to package) | Path to the SQLite database |
| `NEXUS_WEB_URL` | `http://localhost:6969` | Quart web UI URL for HTTP notify |
### 2. Graph context hook
Add to your Claude Code settings alongside the MCP server:
```json
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/cheezcake/Dropbox/code/python/nexus_mcp/venv/bin/python -m nexus_mcp.hook"
}
]
}
]
}
}
```
For arm64 (nivinielicus), replace `venv` with `venv_laptop`.
The hook runs on every prompt (<500ms). It reads `nexus.db` in read-only mode (SQLite WAL concurrent reader). When your prompt mentions graph entities, a `<graph-context>` block is injected with matched nodes and their 1-hop neighborhoods.
**Reference syntax** the hook recognizes:
| Pattern | Example | Resolution |
|---------|---------|------------|
| `#concept` | `#SIP Registration` | FTS5 search, type=concept |
| `@person` | `@Kevin` | FTS5 search, type=person |
| `!ticket` | `!CT-931` | external_id lookup, type=ticket |
| `$system` | `$PIAB` | FTS5 search, type=system |
| `~document` | `~PRD` | FTS5 search, type=document |
| `XX-NNN` | `CT-931`, `AR-990` | Ticket ID regex, general search |
| keywords | `CTFaxSource` | 4+ char non-stopword tokens |
### 3. Stop hook (conscience)
A `Stop` hook that keeps the graph in sync with your work. After each turn it reads the current turn from the transcript and **blocks the stop** when the turn persisted something graph-worthy — a Total Recall `memory_set`, or a ticket ID with no node — while making **zero** Nexus writes (an entity was touched but never wired). The block names exactly what it caught and asks you to create/update the node(s) and wire edges, or dismiss in one line.
Add alongside the graph-context hook (same settings file):
```json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/Users/cheezcake/Dropbox/code/python/nexus_mcp/venv/bin/python -m nexus_mcp.hook_stop"
}
]
}
]
}
}
```
For arm64 (nivinielicus), replace `venv` with `venv_laptop`.
It blocks **at most once per turn** (honors the `stop_hook_active` loop guard, so it can never loop), reads `nexus.db` read-only, and tails only the last ~1500 transcript lines so it stays fast. A false positive — a prose-only `memory_set`, or a passing ticket mention — is dismissable in a single line.
| Aspect | Detail |
|--------|--------|
| **Triggers** | a `memory_set` tool call, or a `CT-NNN`/`AR-NNN`-style ticket ID in the turn text with no matching `ticket` node |
| **Suppressed by** | any `nexus_node_create*` / `nexus_node_update` / `nexus_edge_create` in the same turn |
| **Disable** | `NEXUS_STOP_HOOK=0` |
| **SubagentStop** | `--subagent` flag changes only the wording; wiring to subagents is optional, not recommended by default |
### 4. Web UI (optional)
The Quart web app provides a browser-based companion for browsing the graph. It reads/writes the same `nexus.db`.
```bash
./run.sh
# Starts on http://localhost:6969
```
The MCP server pushes real-time events to the web UI (view opens, label changes, etc.) via HTTP notify. The web UI does not need to be running for the MCP server to work.
## Tools
### Graph operations (11 tools)
| Tool | Description |
|------|-------------|
| `nexus_search` | Full-text search across node labels and properties |
| `nexus_traverse` | Bidirectional recursive walk (N hops, type/relation/temporal filters) |
| `nexus_get_edges` | Edges connected to a node (direction + relation filter) |
| `nexus_node_read` | Read a node by ULID |
| `nexus_node_create` | Create a node with duplicate detection |
| `nexus_node_create_linked` | Atomic create + link to existing node |
| `nexus_node_update` | Merge properties, optionally rename |
| `nexus_node_archive` | Soft delete with cascading edge expiry |
| `nexus_edge_create` | Create directed temporal edge |
| `nexus_edge_expire` | Logical edge delete (set valid_to) |
| `nexus_query_temporal` | Point-in-time subgraph snapshot |
### View operations (10 tools)
| Tool | Description |
|------|-------------|
| `nexus_view_open` | Create materialized view from query, open on desktop |
| `nexus_view_list` | List open views with cursor state |
| `nexus_view_read` | Read view contents |
| `nexus_view_iterate` | Advance keyset cursor, return node + 1-hop subgraph |
| `nexus_view_iterate_reset` | Reset cursor to beginning |
| `nexus_view_filter` | Derived child view with additional filters |
| `nexus_view_annotate` | Write findings to view annotations |
| `nexus_view_sort` | Change sort order (created_at, updated_at, label, id) |
| `nexus_view_snapshot` | Freeze membership (immune to cascading archive) |
| `nexus_view_close` | Archive view and close UI window |
### Context tools (3 tools)
| Tool | Description |
|------|-------------|
| `nexus_task_context` | 2-hop subgraph around a task (nodes + edges + summary) |
| `nexus_property_conventions` | Live property-key-per-type usage from graph |
| `nexus_well_known_nodes` | Nodes with `tr_keys` property (TR prefetch guidance) |
## Query language
Views accept a sigil-based query language:
```
type:task status:active # property filter
#SIP Registration # concept by label
@Kevin # person by label
!CT-931 # ticket by external_id
$PIAB # system by label
type:ticket from:2026-03-01 # temporal filter
01KM4HZ3DFJC1F3RVVRB3KTA3N # ULID traversal
```
## CLAUDE.md integration
Add the following to your CLAUDE.md (project or global) for Nexus-aware sessions:
```markdown
## Nexus Knowledge Graph
You have access to a knowledge graph via nexus-mcp tools (mcp__nexus-mcp__*).
**Graph tools**: nexus_search, nexus_traverse, nexus_get_edges, nexus_node_read,
nexus_node_create, nexus_node_create_linked, nexus_node_update, nexus_node_archive,
nexus_edge_create, nexus_edge_expire, nexus_query_temporal
**View tools**: nexus_view_open, nexus_view_list, nexus_view_read, nexus_view_iterate,
nexus_view_iterate_reset, nexus_view_filter, nexus_view_annotate, nexus_view_sort,
nexus_view_snapshot, nexus_view_close
**Context tools**: nexus_task_context (re-orient on a task), nexus_property_conventions
(learn existing property keys), nexus_well_known_nodes (systems with TR documentation)
### Workflow discipline
- **Search before creating** -- always nexus_search before nexus_node_create to avoid duplicates.
- **Be opportunistic** -- when you encounter entities (people, systems, tickets, concepts),
create or update nodes. When you see relationships, wire edges. The graph should grow
richer with every conversation.
- **Well-known nodes** -- if a graph entity has `tr_keys` in its properties, fetch those
Total Recall keys via memory_get before acting on that system. Do not guess paths or
commands for these systems.
- **After compaction** -- call nexus_task_context with your current task ID to re-orient
against the graph. The graph reflects all mutations you've made and survives compaction.
### Node types
task, ticket, concept, person, system, document
### Edge relations
relates_to, blocks, caused_by, assigned_to, references, tagged_with,
escalated_to, part_of, message, spawned, contains, has_window, derived_from
### Attribution
NEVER use Claude, Anthropic, or AI attribution in any public-facing operation --
git commits, Jira comments, Confluence edits, emails, or any external system.
```
## Architecture
```
Claude Code session (subscription)
|
+-- nexus-mcp (stdio, FastMCP)
| +-- GraphEngine (SQLite WAL)
| +-- ViewEngine
| +-- HTTP notify --> Quart web UI
|
+-- nexus.hook (UserPromptSubmit)
| +-- reads nexus.db (read-only)
| +-- injects <graph-context>
|
+-- nexus.hook_stop (Stop)
+-- reads nexus.db (read-only)
+-- blocks the stop if an entity was touched but not graphed
Quart web UI (:6969, optional)
+-- reads/writes nexus.db
+-- receives POST /notify from MCP
+-- pushes SSE to browser
```
## Database
`nexus.db` -- SQLite with WAL mode, FTS5, JSON1 extension.
Multiple concurrent readers (MCP server, web UI, hook) are safe under WAL. Writes serialize through SQLite's WAL lock. The MCP server runs a WAL checkpoint on shutdown.
## Keyboard shortcuts (web UI)
| Shortcut | Action |
|----------|--------|
| `Ctrl+N` | New task |
| `Ctrl+K` | Focus search bar |
| `Ctrl+G` | Open graph explorer |
| `Ctrl+T` | Open timeline view |
| `Ctrl+Shift+T` | Tile all windows |
| `Escape` | Close topmost window |
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessSyncing