Skip to main content
Glama
thenguyenyf

Hardware Manual RAG MCP Server

by thenguyenyf
README.md
# Hardware Manual RAG MCP Server

A Model Context Protocol (MCP) server that provides **Local RAG** (Retrieval-Augmented Generation) over hardware manuals (PDF & HTML). It indexes your manuals into ChromaDB using local embeddings and exposes a `query_hardware_manual` tool so Claude Code can look up pinouts, registers, schematics, and other hardware specifications — all running locally inside a Docker container.

## How It Works

```
Your PDF/HTML Manuals  →  Docker Container  →  ChromaDB (vectors)  →  Claude Code via MCP
```

- Files are parsed and chunked into 800-character overlapping segments
- Each chunk is embedded with `all-MiniLM-L6-v2` (local, no API key needed)
- Incremental indexing: only new or changed files are re-indexed on restart
- Vectors persist on a Docker named volume so 20+ MB of manuals aren't re-indexed every time

---

## Prerequisites

- **Docker** & **Docker Compose** installed
- **Claude Code** (or any MCP-compatible client)
- At least **~2 GB free disk space** (for Docker image + embedding model + vector store)

---

## Option 1: Pull from GitHub Container Registry (GHCR)

The Docker image is published to GHCR. You don't need to clone the repo.

```bash
# Pull the latest image
docker pull ghcr.io/YOUR_ORG/hum_mcp:latest
```

Then use the docker-compose override below to use the prebuilt image.

### docker-compose.prod.yml

Create a `docker-compose.prod.yml` file:

```yaml
services:
  hardware-mcp:
    image: ghcr.io/YOUR_ORG/hum_mcp:latest
    pull_policy: always
    container_name: hardware-mcp
    restart: unless-stopped
    init: true
    ports:
      - "8000:8000"
    volumes:
      - ./manuals_repo:/app/manuals:ro
      - chroma_data:/app/chroma_db
    environment:
      - PYTHONUNBUFFERED=1
      - MCP_HOST=0.0.0.0
      - MCP_PORT=8000

volumes:
  chroma_data:
```

> Replace `YOUR_ORG` with your GitHub username or organization name.

Start it:

```bash
docker compose -f docker-compose.prod.yml up -d
```

---

## Option 2: Build from Source

Clone and build locally:

```bash
git clone https://github.com/YOUR_ORG/hum_mcp.git
cd hum_mcp

# Build and start the container
docker compose up -d --build
```

---

## Setup

### 1. Place Your Hardware Manuals

Copy your PDF or HTML hardware manuals into the `manuals_repo/` directory:

```bash
# Linux / macOS
cp ~/Downloads/stm32f4-datasheet.pdf ./manuals_repo/
cp ~/Downloads/esp32-technical-reference.html ./manuals_repo/

# Windows (PowerShell)
Copy-Item ~\Downloads\stm32f4-datasheet.pdf .\manuals_repo\
```

Supported formats: `.pdf`, `.html`, `.htm`

### 2. Start the Container

```bash
docker compose up -d
```

On first start, the container will:
1. Download the embedding model (~80 MB, `all-MiniLM-L6-v2`) — one time only
2. Index all manuals in `manuals_repo/` into ChromaDB
3. Log progress to Docker logs

### 3. Verify It's Running

```bash
# Check container status
docker ps --filter name=hardware-mcp

# View indexing logs
docker logs hardware-mcp

# Test the HTTP endpoint
curl http://localhost:8000/mcp
```

Look for a line like:

```
Indexing complete: 2 file(s) indexed, 0 skipped, 45 total chunks in collection
Server ready — 45 total chunks available
```

---

## Runtime Usage

### Connect Claude Code

Add this to your MCP configuration file:

**macOS / Linux**: `~/.config/claude/config.json`  
**Windows**: `%APPDATA%\Claude\config.json`

```json
{
  "mcpServers": {
    "hardware-manual-server": {
      "type": "streamableHttp",
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

> **Prerequisite**: The container must be running before Claude Code connects. Start it with `docker compose up -d`.

Restart Claude Code after saving. You should see a tools icon appear indicating the MCP server is connected.

### Query Your Manuals

Once connected, Claude Code can answer hardware questions by calling `query_hardware_manual`. Simply ask questions like:

- "What is the pinout for the STM32F407 SPI1 interface?"
- "What are the electrical characteristics of GPIO pins at 3.3V?"
- "Show me the register map for the UART control registers"
- "What is the maximum clock frequency for the ESP32-S3?"

The tool returns the top 5 most relevant chunks with source filenames and relevance scores.

### Adding or Updating Manuals

1. Add/update files in `manuals_repo/`
2. Restart the container:

```bash
docker compose restart
```

Only new or changed files are re-indexed — existing chunks are preserved.

### Removing Manuals

1. Delete the file from `manuals_repo/`
2. Restart the container — orphaned chunks are automatically cleaned up:

```bash
docker compose restart
```

---

## Useful Commands

| Command | Description |
|---------|-------------|
| `docker compose up -d` | Start the container (detached) |
| `docker compose down` | Stop and remove the container (vector data persists) |
| `docker compose restart` | Restart to pick up new/changed manuals |
| `docker compose down -v` | **Destroy** everything including the vector database |
| `docker logs hardware-mcp` | View server logs |
| `docker logs hardware-mcp -f` | Follow logs in real time |
| `curl http://localhost:8000/mcp` | Verify the MCP HTTP endpoint is reachable |
| `docker compose build --no-cache` | Rebuild the image from scratch |

---

## Project Structure

```
hum_mcp/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── manuals_repo/          # ← Put your PDF/HTML manuals here
│   └── README.txt
├── src/
│   ├── __init__.py
│   └── server.py          # Main application
└── .github/
    └── workflows/
        └── docker-build.yml
```

---

## Troubleshooting

### "No hardware manuals have been indexed yet"

Place at least one `.pdf` or `.html` file in `manuals_repo/` and run `docker compose restart`.

### "Error querying hardware manuals: …"

Check the logs for details: `docker logs hardware-mcp`

### Container keeps restarting

This typically means the embedding model failed to download. Check your internet connection and retry:

```bash
docker compose down -v
docker compose up -d
```

### Scanned PDFs (image-only) don't produce results

`pypdf` cannot extract text from scanned/image-based PDFs. Use OCR software to create text-searchable PDFs first, or convert them to HTML.

### Slow first startup

The embedding model (~80 MB) is downloaded on first run. Subsequent starts are fast.