Skip to main content
Glama
README.md
# MCP Knowledge Viz

A knowledge-base chatbot with semantic search and interactive embedding visualisation, built as a hybrid of **REST microservices** (browser UI) and a proper **MCP stdio server** (Claude Desktop / Cursor integration).

Store facts in natural language, ask questions, and explore the embedding space in 2D (matplotlib) or interactive 3D (Plotly) — all backed by ChromaDB and SentenceTransformers.

---

## Architecture Overview

![Service architecture](docs/architecture/images/architecture-overview.svg)

The system has two independent access paths that share the same business logic:

| Layer | Transport | Use case |
|---|---|---|
| **REST servers** (`run_all.sh`) | HTTP | Browser chatbot UI |
| **MCP stdio server** (`mcp_tools.py`) | stdin/stdout JSON-RPC | Claude Desktop, Cursor, any MCP client |

Both layers delegate to **`kb_core.py`** — the single module that owns the ChromaDB client and the SentenceTransformer embedder.  Neither layer duplicates data-access logic.

### Key Design Principles

- **Single source of truth for data access** — only `kb_core.py` talks to ChromaDB.  REST endpoints and MCP tools are thin wrappers.
- **No HTTP for MCP** — `mcp_tools.py` calls `kb_core` directly; the REST servers do not need to be running for an MCP client to use the tools.
- **SOLID / Pydantic structure** — the Visualization package uses typed Pydantic models at every boundary (`EmbeddingPayload`, `VisualizationRequest`, `ReducedEmbeddings`).

---

## Diagrams

### Module Structure

![Module structure](docs/architecture/images/module-structure.svg)

### QnA Request Flow (REST)

![QnA request flow](docs/architecture/images/qna-request-flow.svg)

### Visualization Flow (2D + 3D)

![Visualization flow](docs/architecture/images/visualization-flow.svg)

### MCP Tools Flow (stdio)

![MCP tools flow](docs/architecture/images/mcp-tools-flow.svg)

### Regenerating diagrams

```bash
plantuml -tsvg docs/architecture/uml/*.puml -o ../images
plantuml -tpng docs/architecture/uml/*.puml -o ../images
```

---

## REST API Reference

### Knowledge Base Server — port 8000

Central data service.  Also serves the chatbot browser UI.

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/chatbot` | Browser UI (two-column layout) |
| `POST` | `/add_fact` | Embed and store a fact in ChromaDB `facts` collection |
| `POST` | `/add_query` | Embed and store a query in ChromaDB `queries` collection |
| `POST` | `/search` | Semantic search — returns top-k facts + distances. Body: `{"query": "...", "n_results": 5}` |
| `GET` | `/get_all_embeddings` | Return all facts + queries with raw embeddings (used by Viz server) |

### QnA Server — port 8001

Thin HTTP wrapper.  Calls the KB server; no direct DB access.

| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/ask` | Stores query via `/add_query`, fetches matches via `/search`, returns ranked results |

### Visualization Server — port 8002

Generates embedding plots via PCA dimensionality reduction.

| Method | Endpoint | Query params | Returns |
|--------|----------|------|---------|
| `GET` | `/visualize_embeddings` | `dimensions` (2\|3), `show_radius`, `radius_neighbors`, `figure_width`, `figure_height`, `dpi` | `image/png` (matplotlib) |
| `GET` | `/visualize_embeddings_3d` | `show_radius`, `radius_neighbors`, `figure_width`, `figure_height`, `dpi` | `image/png` (matplotlib 3D) |
| `GET` | `/visualize_embeddings_interactive` | `show_radius`, `radius_neighbors` | `application/json` (Plotly figure) |

---

## MCP Tools Reference

`mcp_tools.py` is a **FastMCP stdio server**.  Configure it in your MCP client and the three tools below appear automatically — no REST servers needed.

| Tool | Arguments | Description |
|------|-----------|-------------|
| `add_fact` | `text: str` | Embed and persist a fact in ChromaDB |
| `ask` | `query: str`, `n_results: int = 5` | Semantic search; also records the query for visualisation |
| `visualize_embeddings` | `show_radius: bool = true`, `radius_neighbors: int = 3` | Returns a Plotly 3D figure as a JSON string |

### Connecting to Claude Desktop / Cursor

Copy `mcp.json.example` to `mcp.json`, fill in your absolute paths, then copy the `mcpServers` block into your client's config file:

- **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Cursor**: `~/.cursor/mcp.json`

```jsonc
// mcp.json.example — fill in your local paths
{
  "mcpServers": {
    "knowledge-viz": {
      "command": "/path/to/your/project/.venv/bin/python",
      "args": ["-m", "mcp_servers.mcp_tools"],
      "cwd": "/path/to/your/project"
    }
  }
}
```

> `mcp.json` is gitignored because it contains absolute local paths.  Always edit `mcp.json.example` for committed changes.

---

## Getting Started

### Prerequisites

- Python 3.11+
- [PlantUML](https://plantuml.com/) (optional, only to regenerate diagrams)

### Setup

```bash
git clone <repository-url>
cd mcp-knowledge-viz

python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

pip install -r requirements.txt
```

### Run the REST + browser UI stack

```bash
chmod +x run_all.sh
./run_all.sh
```

Starts three servers:

| Server | Port | Role |
|--------|------|------|
| Knowledge Base | 8000 | Data + chatbot UI |
| QnA | 8001 | Question answering |
| Visualization | 8002 | Embedding plots |

Open **http://127.0.0.1:8000/chatbot** in your browser.

### Visualisation tuning parameters

| Parameter | Default | Range | Effect |
|-----------|---------|-------|--------|
| `dimensions` | `2` | `2` or `3` | PCA target dimensions |
| `show_radius` | `true` | bool | Draw search-radius circle / sphere around latest query |
| `radius_neighbors` | `5` | 1–50 | Neighbour count used to compute the radius |
| `figure_width` | `16` | float | Matplotlib figure width (inches) |
| `figure_height` | `10` | float | Matplotlib figure height (inches) |
| `dpi` | `160` | int | Matplotlib output resolution |
| `n_results` | `5` | 1–50 | Facts returned per search |

---

## Project Structure

```
mcp-knowledge-viz/
├── app/
│   ├── static/
│   │   ├── chatbot.css        # Two-column layout, vis viewport
│   │   └── chatbot.js         # Fetch facts/QnA, Plotly 3D, spinner
│   └── templates/
│       └── chatbot.html       # Bootstrap 5 two-column UI
├── docs/
│   └── architecture/
│       ├── images/            # Generated SVG + PNG diagrams
│       └── uml/               # PlantUML sources
├── mcp_servers/
│   ├── kb_core.py             # ★ Shared ChromaDB + embedder logic
│   ├── knowledge_base_server.py  # REST :8000 — delegates to kb_core
│   ├── qna_server.py             # REST :8001 — HTTP wrapper
│   ├── visualization_server.py   # REST :8002 — delegates to visualization/
│   ├── mcp_tools.py           # ★ MCP stdio server (add_fact, ask, visualize)
│   └── visualization/
│       ├── models.py          # Pydantic models
│       ├── kb_client.py       # HTTP client → KB server
│       ├── reducer.py         # PCA 2D/3D
│       ├── renderer.py        # matplotlib (2D/3D static PNG)
│       ├── plotly_renderer.py # Plotly interactive 3D JSON
│       └── service.py         # Orchestrator
├── chroma_db/                 # Persistent vector store (gitignored)
├── mcp.json                   # Local MCP config (gitignored)
├── mcp.json.example           # Template — commit this, not mcp.json
├── run_all.sh                 # Start all three REST servers
└── requirements.txt
```

---

## Tech Stack

| Concern | Library |
|---------|---------|
| REST framework | FastAPI + uvicorn |
| Vector store | ChromaDB (persistent) |
| Embeddings | SentenceTransformers `all-MiniLM-L6-v2` |
| Dimensionality reduction | scikit-learn PCA |
| 2D/3D static plots | matplotlib |
| Interactive 3D plots | Plotly (JS CDN + Python) |
| MCP server | `mcp[cli]` FastMCP |
| HTTP client | httpx |
| Frontend | Bootstrap 5, vanilla JS |