2026-06-06 12:26:42 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-06 00:48:21 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00
2026-06-05 23:02:55 +01:00

Context7-style Docs MCP System

A self-hosted, local-compatible documentation retrieval and search system using Docker. This project uses Qdrant for vector embeddings and SQLite for metadata storage, exposing a FastAPI docs backend and an MCP server for IDE/tool integration.

🏠 Home Server / Production Use

This section covers hardening recommendations for running this system on a home server or in production.

Environment Variables (.env)

Copy .env.example to .env and configure:

cp .env.example .env
Variable Description Example
HOST_PORT Docs API host port (default: 8787) 8787
MCP_HOST_PORT MCP server host port (default: 8788) 8788
DOCS_API_KEY API key for docs-api authentication (optional) my-secret-key-123
MCP_API_KEY API key for MCP server authentication (optional, FastMCP handles via --key flag conceptually) mcp-secret-key
DOCS_PATH Path to documentation files inside container /docs
DB_PATH SQLite database path inside container /data/db.sqlite
LOG_LEVEL Logging level: DEBUG, INFO, WARNING, ERROR INFO

Security Note: API keys are optional. Leave empty in .env if you don't need authentication (backward compatible with existing setups). If set, the docs-api requires an X-API-Key header matching DOCS_API_KEY for protected endpoints.

Port Configuration

For firewall or network setup:

# Example: Run docs-api on port 9000 instead of 8787
HOST_PORT=9000 MCP_HOST_PORT=9001 docker compose up -d --build

Backup Instructions

SQLite Database (data/db.sqlite)

Regular SQLite backups prevent data loss. Example cron job:

# Add to crontab (run daily at 2am)
0 2 * * * docker compose exec docs-api sqlite3 /data/db.sqlite ".backup '/backups/db_$(date +%Y%m%d).sqlite'"

Or one-off backup:

docker compose exec docs-api sh -c "sqlite3 /data/db.sqlite '.dump' | gzip > /backups/db-$(date +%Y%m%d-%H%M%S).sql.gz"

Qdrant Vector Store

Qdrant stores vectors in ./data/qdrant. For backup:

# Backup entire Qdrant data directory
docker compose exec qdrant sh -c "tar czf /backups/qdrant-backup-$(date +%Y%m%d).tar.gz /qdrant/storage"

# Or pull full export to host (requires volume mount)
docker run --rm -v local-context7_data:/data -v $(pwd)/backups:/backups qdrant/qdrant:latest tar czf /backups/qdrant-backup-$(date +%Y%m%d).tar.gz /qdrant/storage

Safe Reset Command

To reset both SQLite and Qdrant cleanly:

docker compose down -v  # Removes volumes and stops services
rm ./data/db.sqlite     # Remove database file
rm -rf ./data/qdrant    # Remove Qdrant data
docker compose up -d --build

Or use the make reset command below.

Makefile Commands

The included Makefile provides convenient commands:

# Start services
make up

# Stop services
make down

# Rebuild and restart
make restart

# Backup database
make backup-db BACKUP_PATH=/backups/db-$(date +%Y%m%d).sqlite.gz

# Reset everything (delete volumes)
make reset

Architecture

Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Client    │────▶│ docs-api    │◀────│ docs-mcp    │
│ (IDE/Tool)  │     │ (FastAPI)   │     │ (MCP Server)│
└─────────────┘     └─────────────┘     └─────────────┘
                          │
                          ▼
                    ┌─────────────┐
                    │   Qdrant    │
                    │ (Vector DB) │
                    └─────────────┘

Components:

  • qdrant — Vector database storing document embeddings
  • docs-api — FastAPI backend exposing ingestion, search, and library endpoints
  • docs-mcp — MCP server providing tools for Context7-style AI interactions

Prerequisites

  • Docker Engine v20.10+
  • Docker Compose
  • ~500MB free disk space (Qdrant + embedding model)

Setup

  1. Download the project and change into its directory:

    cd local-context7
    
  2. Copy environment file:

    cp .env.example .env
    
  3. (Optional) Create sample docs:

    mkdir -p docs/foundryvtt docs/fastapi docs/my-msfs-copilot
    
  4. Start services:

    docker compose up -d --build
    
  5. Verify they're running:

    docker compose ps
    

    You should see all three services (qdrant, docs-api, docs-mcp) in "Up" status.

  6. Wait for startup completion (embedding model loads on first API call):

    docker compose logs -f docs-api  # Watch for "Initialization complete."
    

Add Docs

Place your documentation folders under the root directory:

mkdir -p docs/foundryvtt/docs
cp /path/to/foundryvtt/*.md docs/foundryvtt/docs/
mkdir -p docs/fastapi

Supported file types: .md, .txt, .py, .js, .ts, .json, .yaml, .yml, .html, .css, .pdf (via pypdf).

To add new documents to the vector store after adding them, run:

docker compose exec docs-api python -c "from app.ingest import ingest_all; import asyncio; asyncio.run(ingest_all())"

Or from another terminal:

curl -X POST http://localhost:8787/api/v1/ingest/all \
  -H "Content-Type: application/json"

Index Docs (Run Ingestion)

After adding documents, index them into the vector store:

docker compose exec docs-api python -c "from app.ingest import ingest_all; import asyncio; asyncio.run(ingest_all())"

Expected output shows progress like:

[Detection] Scanning for libraries in: /docs
[Detection] Found 3 library(ies)
[Library] Processing: foundryvtt
[Library] Scanning for files in: /docs/foundryvtt
[Library] Found 5 document(s)
...

Search Docs

Via API (POST to /search)

Request body:

{
  "query": "how do hooks work",
  "library_id": "foundryvtt",
  "limit": 10
}

Response example:

{
  "query": "hooks",
  "library_id": "foundryvtt",
  "results": [
    {
      "id": "...",
      "score": 0.854,
      "library_id": "foundryvtt",
      "path": "core-docs.md",
      "title": "Core Hooks",
      "chunk_index": 2
    }
  ],
  "count": 1
}

Via MCP (resolve-library-id, search-docs tools)

Connect MCP Clients

To use this system with an MCP-enabled client (e.g., Claude Desktop), configure the MCP server endpoint.

Example: Claude Desktop Config

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "context7": {
      "command": "npx",
      "args": [
        "@modelcontextprotocol/server-local-context7",
        "--url", "http://localhost:8788"
      ],
      "env": {
        "DOCS_API_URL": "http://localhost:8787"
      }
    }
  }
}

If the client runs outside Docker and can't reach the API, expose them on host ports or run the MCP server outside Docker (see below).

Example: Cline/Cursor MCP Config

For Cursor or similar editors using Cline:

// ~/.cursor/mcp.json
{
  "context7": {
    "type": "stdio",
    "command": "docker",
    "args": [
      "exec",
      "-it",
      "docs-mcp",
      "uvicorn",
      "server:app",
      "--host",
      "0.0.0.0",
      "--port",
      "8788"
    ]
  }
}

Or if exposing MCP on host port:

{
  "context7": {
    "type": "stdio",
    "command": "docker",
    "args": [
      "run",
      "-it",
      "--rm",
      "-p",
      "8788:8788",
      "--name",
      "context7-mcp-standalone",
      "-e",
      "DOCS_API_URL=http://host.docker.internal:8787",
      "local-context7/docs-mcp"
    ]
  }
}

Troubleshooting

Services won't start or restart loops

Check logs:

docker compose logs -f

Common issues:

  • Port already in use on host → adjust mapping or free the port
  • Embedding model failing to load → verify disk space, check for GPU constraints if applicable

Vector search returns empty results

Ensure you've run ingestion after adding docs:

docker compose exec docs-api python -c "from app.ingest import ingest_all; import asyncio; asyncio.run(ingest_all())"

Can't connect to docs-api from client outside Docker

Set environment variable for host access in docker-compose.yml or .env:

docs-api:
  environment:
    - DOCS_API_URL=http://host.docker.internal:8787

For MCP server specifically:

docs-mcp:
  environment:
    - DOCS_API_URL=http://host.docker.internal:8787

Reset Qdrant and SQLite

To clear all data (vector store and database):

# Stop services
docker compose down

# Remove volumes (delete Qdrant and db.sqlite)
rm -rf ./data/qdrant ./data/db.sqlite

# Restart fresh
docker compose up -d --build

Expose Through Caddy Reverse Proxy

To add HTTPS and serve under a subdomain, configure Caddy:

Example Caddyfile:

docs.yourdomain.com {
    reverse_proxy docs-api:8787
    handle_path /mcp/* {
        reverse_proxy docs-mcp:8788
    }
    
    # Enable basic auth (optional, see below)
}

api.yourdomain.com {
    reverse_proxy docs-api:8787
}

mcp.yourdomain.com {
    reverse_proxy docs-mcp:8788
}

Protect It with Basic Auth

Add authentication using Caddy's built-in auth_handler module or caddy-dedupe-auth:

Caddy example with basic auth:

docs.yourdomain.com {
    reverse_proxy docs-api:8787
    auth_token YOUR_API_TOKEN
    response_header_accessor path
}

Or using the caddy basic module from scratch in a reverse proxy setup.

For Docker-based deployment, consider using an authentication middleware or a dedicated reverse proxy with JWT/HTTP Basic configured externally.

Future Improvements

  • Add rate limiting to API endpoints
  • Support for streaming responses for large document retrieval
  • Chunk overlap configuration via environment variables
  • Batch index endpoint improvements
  • Metrics/logging aggregation (e.g., Prometheus + Grafana)
  • Plugin system for additional data sources
S
Description
No description provided
Readme 237 KiB
Languages
Python 83%
HTML 9.5%
CSS 3.6%
JavaScript 1.7%
Makefile 1.3%
Other 0.9%