Guaipeca
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Guaipecasearch my epm-docs corpus for HFM data audit findings"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Guaipeca š§
Lightweight configurable RAG MCP server ā FAISS + fastembed + markitdown
Why "Guaipeca"? ā Guaipeca is southern Brazilian slang (Tupi-Guarani origin) for a scrappy mutt ā a cusco, no pedigree, no frills, but loyal and gets the job done. Seemed fitting for a lightweight RAG server with no API keys, no GPU, and no cloud dependencies.
Guaipeca is a self-hosted retrieval-augmented generation (RAG) server that exposes semantic search over your document corpora via the Model Context Protocol (MCP). It uses a lightweight tech stack ā FAISS indexes, fastembed (ONNX Runtime) embeddings, structure-aware chunking ā and is fully configurable and decoupled from any specific memory system.
Features
Multi-corpus ā define multiple document folders, each with its own weight and topic label
MCP-native ā exposes
search,get_chunk,get_document,list_documents,index,status,list_folders, anduploadtools via MCPDual transport ā stdio (for local LLM integration) + HTTP (for remote/network access)
Hybrid search ā optional BM25 sparse keyword search fused with FAISS dense vectors via Reciprocal Rank Fusion (RRF)
Any document format ā pymupdf (PDFs with font-based heading detection) + markitdown (DOCX, PPTX, XLSX, HTML ā markdown)
Structure-aware chunking ā splits on headings, treats tables as atomic units, zero LLM calls
Local embeddings ā fastembed (ONNX Runtime) on CPU, no GPU or API keys needed
Incremental indexing ā SHA256 file hashing, only re-indexes changed files
FAISS backup + recovery ā automatic
.fai.bakbackup before writes, fallback chain on load (primary ā backup ā fresh)Embedding cache (LRU + TTL) ā 10K-entry LRU cache with 1hr TTL, memory-pressure aware eviction via psutil
Content preprocessing ā heading + first 500 chars sent to embedder for better semantic signal; full text stored in metadata
Concurrent ā read-write lock allows multiple simultaneous searches, exclusive indexing
Runs on Pi 5 ā ARM64, CPU-only, ~90MB model + ~20MB FAISS
Optional auth ā Bearer token authentication for HTTP transport
Related MCP server: ragi
Quick Start
# Clone and install
git clone https://github.com/LuisEduardoAvila/guaipeca.git
cd guaipeca
pip install -e ".[all]"
# pymupdf is included as a core dependency for PDF heading detection
# Create config
cp config/guaipeca.yaml ~/.guaipeca/guaipeca.yaml
# Edit config to point to your document folders
# Check/download embedding model
guaipeca --check-model
# Index your corpora
guaipeca index
# Search from CLI
guaipeca search "HFM data audit"
# Start MCP server (stdio + HTTP on port 8090)
guaipeca serveConfiguration
Create ~/.guaipeca/guaipeca.yaml:
corpora:
- name: epm-docs
path: /path/to/your/docs
topic: "EPM & Oracle HFM/ARCS"
weight: 1.5
extensions: [.md, .txt, .pdf, .docx]
- name: finance-reference
path: /path/to/your/finance-docs
topic: "Finance & Accounting Standards"
weight: 1.3
extensions: [.md, .txt, .pdf]
embedding:
model: all-MiniLM-L6-v2
dimensions: 384
preprocess: true # heading + first 500 chars for better embeddings
cache_ttl_seconds: 3600 # embedding cache entry TTL (1 hour)
cache_max_entries: 10000 # max cached embeddings (LRU eviction)
chunking:
max_size: 2000
overlap: 200
table_aware: true
split_on_headings: true
server:
transport: both # stdio | http | both
port: 8090
host: 127.0.0.1 # Use 0.0.0.0 for network access
# auth_token: "your-secret-token" # Optional: require Bearer token auth
upload:
allow: ["epm-docs"] # corpora that accept file uploads
max_file_size: 52428800 # 50MB
allowed_extensions: [.md, .txt, .pdf, .docx]
auto_index: true # index after upload
# Search configuration (optional ā all values have safe defaults)
search:
hybrid: false # Enable BM25 + FAISS hybrid search (default: false)
bm25_weight: 1.0 # BM25 contribution weight in RRF fusion
dense_weight: 1.0 # Dense (FAISS) contribution weight in RRF fusion
rrf_k: 60 # RRF constant (higher = smoother ranking)
max_chars: 8000 # Threshold for auto return_mode (total result chars)Embedding Models
Guaipeca uses FastEmbed (ONNX Runtime) for local embeddings ā no torch, no GPU, no API keys. Models are downloaded automatically on first use and cached locally.
Content preprocessing is enabled by default (embedding.preprocess: true): before embedding, each chunk is preprocessed to its heading + first 500 characters, giving the model better semantic signal. The full text is still stored in metadata for retrieval. Disable with preprocess: false if you want raw chunk text sent to the embedder.
Choosing a Model
Pick based on your use case and hardware:
Speed-optimized (384-dim, <100MB) ā Pi 5, resource-constrained
Model | Dimensions | Size | Best for |
| 384 | 90MB | General use, fast (default) |
| 384 | 67MB | Better quality, same speed |
| 384 | 90MB | General use, compact |
Balanced (512ā768 dim, 120ā520MB) ā desktop, small VM
Model | Dimensions | Size | Best for |
| 512 | 120MB | Long documents (8192 tokens) |
| 768 | 210MB | Higher quality, moderate speed |
| 768 | 130MB | Quantized, good balance |
| 384 | 130MB | Good quality, compact |
Quality-optimized (768ā1024 dim, 420MB+) ā server, dedicated hardware
Model | Dimensions | Size | Best for |
| 1024 | 1.2GB | Best quality, slowest |
| 1024 | 640MB | High quality |
| 768 | 520MB | Long context (8192 tokens) |
Multilingual
Model | Dimensions | Size | Best for |
| 384 | 220MB | ~50 languages, fast |
| 768 | 1.0GB | ~50 languages, better quality |
| 1024 | 2.2GB | ~100 languages, best quality |
Code
Model | Dimensions | Size | Best for |
| 768 | 640MB | Code + docs, 30+ programming languages |
Switching Models
Update
embedding.modelandembedding.dimensionsin your configReindex with
--force(FAISS vectors must match the new dimensions):
guaipeca index --forceā ļø Changing dimensions (e.g. 384 ā 768) requires a full reindex. The old index is incompatible with the new model's vectors.
Recommendations
Use case | Recommended model | Why |
Pi 5 / ARM64 SBC |
| Fast, 90MB, good enough quality |
Small VM (2GB RAM) |
| Better quality, still 384-dim |
Dedicated server |
| 768-dim, noticeable quality gain |
Long documents |
| 8192 token context |
Multilingual |
| 50+ languages, 384-dim |
Code search |
| Code + docs, 30+ languages |
MCP Tools
search
Search across indexed corpora. Returns summary + location + score.
search(query="HFM data audit", top_k=5, corpora=["epm-docs"], hybrid=true, return_mode="chunks")return_mode controls result granularity:
chunks(default) ā returns individual chunks with summary, location, and scoredocumentsā returns full source documents, deduplicated by path, with best chunk score as document scoreautoā returns chunks if total result size <search.max_chars(default 8000), otherwise collapses to documents
get_chunk
Retrieve full chunk text by chunk_id from search results.
get_chunk(chunk_id="epm-docs:a1b2c3d4e5f67890")get_document
Retrieve the full converted text (markdown) of a document by corpus and source_path. Returns text content plus metadata (filename, file size, chunk count).
get_document(corpus="epm-docs", source_path="/path/to/docs/report.pdf")list_documents
List all indexed documents in a corpus (or all corpora if no corpus specified). Returns source_path, filename, chunk count, file size, and last_indexed timestamp.
list_documents(corpus="epm-docs")
list_documents() # all corporaindex
Trigger indexing for a corpus or all corpora.
index(corpus="all", force=false)status
Get corpus statistics: chunk counts, indexed files.
status()list_folders
List corpora that accept file uploads via the upload tool. Returns corpus name, path, topic, and allowed extensions.
list_folders()upload
Upload a file to a corpus for conversion and indexing. File content must be base64-encoded. Only corpora listed in upload.allow can receive files.
upload(corpus="epm-docs", filename="report.pdf", content="<base64>", index=true)CLI
guaipeca --check-model # Check/download embedding model
guaipeca index [corpus] [--force] # Index corpora
guaipeca search "query" [--top-k N] # Search
guaipeca search "query" --hybrid # Hybrid search (BM25 + FAISS)
guaipeca status # Show stats
guaipeca serve [--transport both] [--port 8090] # Start MCP serverRunning as a systemd Service
For always-on deployment on Linux (e.g. Pi 5), install Guaipeca as a systemd service.
1. Create the service file
# Copy the service file (or create manually ā see below)
sudo cp guaipeca.service /etc/systemd/system/guaipeca.serviceOr create it manually at /etc/systemd/system/guaipeca.service:
[Unit]
Description=Guaipeca RAG MCP Server
After=network.target
[Service]
Type=simple
User=<your-user>
Group=<your-group>
WorkingDirectory=/path/to/guaipeca
ExecStart=/path/to/guaipeca --config /home/<user>/.guaipeca/guaipeca.yaml serve --transport both --port 8090
Restart=on-failure
RestartSec=10
Environment=PYTHONUNBUFFERED=1
Environment=HOME=/home/<user>
# Optional resource limits (prevent starving other services)
MemoryMax=1G
CPUQuota=200%
[Install]
WantedBy=multi-user.target2. Enable and start
sudo systemctl daemon-reload
sudo systemctl enable guaipeca # start on boot
sudo systemctl start guaipeca # start now3. Verify
systemctl status guaipeca
curl http://127.0.0.1:8090/health
# ā {"status": "ok", "server": "guaipeca", "version": "0.1.0"}4. Check logs
journalctl -u guaipeca -f # follow logs
journalctl -u guaipeca --since "1 hour ago"Management
sudo systemctl stop guaipeca # stop
sudo systemctl restart guaipeca # restart
sudo systemctl disable guaipeca # stop starting on bootNotes
The service runs
guaipeca servewith--transport both(stdio + HTTP/SSE)Port 8090 is bound to
127.0.0.1by default (configserver.host). Use0.0.0.0for network accessResource limits (
MemoryMax,CPUQuota) prevent Guaipeca from starving other services on resource-constrained hosts like Pi 5The embedding model loads at startup (~1s with fastembed/ONNX). First search/index may take slightly longer if the model needs to download
Config changes require a restart:
sudo systemctl restart guaipecaRe-index after adding files:
guaipeca --config ~/.guaipeca/guaipeca.yaml index
Architecture
guaipeca.yaml (config)
ā
Config Loader
ā
āāāāāāāāāāāāāā¬āāāāāāāāāāāāā
ā ā ā
Indexer Searcher MCP Server
ā ā ā
ā ā āāā stdio transport
ā ā āāā HTTP/SSE transport (port 8090)
ā ā
ā āāā FAISS per-corpus + weighted merge
ā
āāā pymupdf (PDF) āā
āāā markitdown (other) āā¤
ā ā
chunk ā embed ā FAISS
(read-write lock: concurrent readers, exclusive writer)Data Layout
~/.guaipeca/
āāā guaipeca.yaml # Config
āāā data/
ā āāā corpora/
ā ā āāā epm-docs/
ā ā ā āāā faiss_index.fai
ā ā ā āāā faiss_index.fai.bak # backup (auto-generated)
ā ā ā āāā metadata.json
ā ā ā āāā file_hashes.json
ā ā ā āāā bm25_index/ # BM25 sparse keyword index
ā ā āāā finance-reference/
ā ā āāā faiss_index.fai
ā ā āāā faiss_index.fai.bak # backup (auto-generated)
ā ā āāā metadata.json
ā ā āāā file_hashes.json
ā ā āāā bm25_index/ # BM25 sparse keyword index
ā āāā converted/ # conversion cache (pymupdf + markitdown)
āāā models/
āāā all-MiniLM-L6-v2/ # cached embedding modelDependencies
Package | Purpose | Size |
fastembed | Local embeddings (ONNX Runtime) | ~46MB (onnxruntime) + ~90MB (model) |
faiss-cpu | Vector index | ~20MB |
pymupdf | PDF heading detection | ~25MB |
markitdown | Document conversion (DOCX, PPTX, XLSX, HTML) | ~30MB |
bm25s | BM25 sparse keyword search | <1MB |
pyyaml | Config parsing | <1MB |
numpy | Array operations | ~15MB |
ARM64 / Pi 5 System Dependencies
markitdown relies on libraries that require system-level packages on ARM64 (Pi 5).
Install these before pip install:
# Debian/Ubuntu/Raspberry Pi OS
sudo apt install libxml2-dev libxslt-dev libffi-dev libjpeg-dev
# If using PDF conversion:
sudo apt install poppler-utils
# If using DOCX conversion:
sudo apt install antiwordIf you encounter build errors with lxml or charset-normalizer on ARM64,
ensure you have build-essential and python3-dev installed:
sudo apt install build-essential python3-devContainer Deployment (Docker)
Guaipeca can run in a Docker container for VM deployment (ARM64 or x86_64). The Pi 5 stays bare-metal; containers are for VMs.
Quick Start
# 1. Prepare data directory
mkdir -p data/{config,corpora,index,models}
cp config/guaipeca.container.yaml data/config/guaipeca.yaml
# Edit data/config/guaipeca.yaml as needed
# Copy your documents to data/corpora/
# 2. Start the container
docker compose up -d
# 3. Check health
curl http://localhost:8090/health
# 4. Index corpora (first time)
docker compose exec guaipeca guaipeca --config /data/config/guaipeca.yaml indexBuilding from Source
docker build -t guaipeca .
docker run -d --name guaipeca \
-p 8090:8090 \
-v ./data:/data \
--restart unless-stopped \
guaipecaNote: Pre-built images will be available on ghcr.io after the first push to
maintriggers the CI/CD pipeline. Until then, build from source using the command above.
Container Data Layout
data/ ā /data (mounted volume)
āāā config/ ā /data/config (guaipeca.yaml)
āāā corpora/ ā /data/corpora (source documents)
āāā index/ ā /data/index (FAISS + BM25 + metadata)
āāā models/ ā /data/models (embedding model cache)The embedding model (~90MB) downloads to the volume on first run. Subsequent starts load from cache ā no network needed.
Automated Rebuilds
Push to main triggers a GitHub Actions workflow that:
Builds multi-arch images (arm64 + amd64)
Tags with
latestand commit SHAPushes to
ghcr.io/luis-eduardo-avila/guaipeca
See docs/container-deployment.md for detailed VM deployment instructions.
Security
Default binding: The HTTP server binds to
127.0.0.1(localhost) by default. Changehost: 0.0.0.0in config only if you need network access.Authentication: Set
auth_tokenin the server config to requireAuthorization: Bearer <token>headers on HTTP requests. When auth is enabled, CORS is restricted (no wildcard origin).HTTP endpoints:
GET /sseā SSE stream for MCP transportPOST /messagesā JSON-RPC messagesGET /healthā health checkGET /toolsā list available toolsGET /download/{corpus}/{filename}ā download original file (requires auth, path traversal protected)
Error messages: Client error responses are sanitized to avoid leaking internal file paths or library details.
License
MIT
Related MCP Connectors
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Personal knowledge base MCP server with semantic search, auto-categorization, metadata extraction
DocBase MCP server for AI agents
Related MCP Servers
- AlicenseBqualityDmaintenanceA complete MCP server for Retrieval-Augmented Generation with file management and vector memory for agents. Supports multiple document formats (PDF, DOCX, TXT, MD, CSV, JSON) with semantic search using Hugging Face embeddings and ChromaDB for efficient vector storage.116 npm1MIT
- AlicenseAqualityDmaintenanceLocal-first RAG indexing and semantic search MCP server. Enables document retrieval and context-aware queries using local embedding models.36 npmMIT
- FlicenseAqualityDmaintenanceMCP server that enables semantic search over local PDF collections using local RAG, with automatic indexing of new documents.5-
- AlicenseNot gradedqualityAmaintenanceMCP server for local RAG over personal notes, PDFs, and documents, enabling plain-English querying and hybrid search with multi-hop context expansion.MIT