cd /news/ai-agents/slothvault-a-zero-effort-local-mcp-r… · home › topics › ai-agents › article
[ARTICLE · art-157333] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

SlothVault: A Zero-Effort Local MCP + RAG Agent That Rewards Digital Laziness published: true

A developer built SlothVault, a local-first personal RAG utility that ingests unorganized notes into a vault and retrieves relevant entries via an open-weight agent. The project pairs the all-MiniLM-L6-v2 sentence-transformer embedding model with Qwen2.5-1.5B-Instruct for answer synthesis, exposing retrieve_from_vault and add_to_vault as Model Context Protocol tool functions behind a Gradio interface.

by read4 min views2 publishedOct 25, 2026

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

SlothVault is a local-first personal RAG utility built for anyone too tired or busy to manually sort, tag, and organize digital clutter.

Every day, developers and researchers accumulate messy context fragments:

Most productivity guides advise spending hours building complex databases in Notion or Obsidian. SlothVault takes the lazy approach: dump your unorganized notes into a local vault and let an open-weight agent fetch what you need in seconds.

.txt files on the fly.retrieve_from_vault and add_to_vault).

import json
import torch
import numpy as np
import gradio as gr
from transformers import pipeline
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

embed_model = SentenceTransformer("all-MiniLM-L6-v2")

device = "cuda" if torch.cuda.is_available() else "cpu"
llm_pipeline = pipeline(
    "text-generation",
    model="Qwen/Qwen2.5-1.5B-Instruct",
    torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
    device_map="auto" if torch.cuda.is_available() else None
)

vault_docs = [
    "WiFi Password for Home Lab is 'lazy_sloth_42'. Do not share externally.",
    "Invoice #8841 from Cloud hosting was $45.20, due on November 5th.",
    "Doctor appointment rescheduled to Friday at 4:30 PM with Dr. Sharma.",
    "Project roadmap milestone 2 requires TabPFN model benchmarking by next Tuesday."
]
vault_embeddings = embed_model.encode(vault_docs)

def mcp_retrieve_from_vault(query: str, top_k: int = 2):
    global vault_docs, vault_embeddings
    if not vault_docs:
        return []
    q_vec = embed_model.encode([query])
    scores = cosine_similarity(q_vec, vault_embeddings)[0]
    top_indices = np.argsort(scores)[::-1][:top_k]
    return [{"text": vault_docs[i], "similarity_score": round(float(scores[i]), 3)} for i in top_indices]

def mcp_add_to_vault(new_text: str):
    global vault_docs, vault_embeddings
    cleaned = new_text.strip()
    if not cleaned:
        return "Empty note."
    vault_docs.append(cleaned)
    new_embedding = embed_model.encode([cleaned])
    vault_embeddings = np.vstack([vault_embeddings, new_embedding])
    return f"Added to vault. Total items: {len(vault_docs)}"

SYSTEM_PROMPT = (
    "You are SlothVault. The user is exhausted. You have executed the MCP tool "
    "'retrieve_from_vault' and received matching records. "
    "Give the exact answer in 1-2 punchy sentences. "
    "End with a short sloth remark like 'Now go back to resting. 🦥'."
)

def sloth_agent_search(query: str):
    if not query.strip():
        return "Ask something you're too lazy to search for!"

    retrieved = mcp_retrieve_from_vault(query, top_k=2)
    context_str = "\n".join([f"- {r['text']} (Match: {r['similarity_score']})" for r in retrieved])

    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": f"Query: {query}\n\nContext:\n{context_str}"}
    ]

    res = llm_pipeline(messages, max_new_tokens=120, temperature=0.2)
    answer = res[0]["generated_text"][-1]["content"].strip()

    trace = (
        f"```
{% endraw %}
json\n"
        f"// MCP Tool Execution Trace\n"
        f'{{"tool": "retrieve_from_vault", "query": "{query}", "matches": {len(retrieved)}}}\n'
        f"
{% raw %}

\n\n"

    f"**Retrieved Context:**\n{context_str}\n\n"

    f"---\n"

    f"###  Sloth Answer\n{answer}"

)

return trace

def handle_upload(file_obj, raw_text):

count = 0

if file_obj is not None:

    with open(file_obj.name, "r", encoding="utf-8", errors="ignore") as f:

        for line in f.readlines():

            if line.strip():

                mcp_add_to_vault(line.strip())

                count += 1

if raw_text and raw_text.strip():

    mcp_add_to_vault(raw_text.strip())

    count += 1

return f"Successfully ingested {count} item(s) into vault."

with gr.Blocks(theme=gr.themes.Soft(), title="SlothVault") as demo:

gr.Markdown("#  SlothVault: Zero-Effort Local MCP + RAG Agent")

gr.Markdown("Stop organizing notes manually. Dump raw clutter and let an open-weight agent retrieve it.")
with gr.Tab(" Ask the Sloth Agent"):
    query_in = gr.Textbox(label="Ask anything:", value="What is my home lab wifi password and when is the cloud bill due?")
    search_btn = gr.Button(" Find It For Me", variant="primary")
    output_box = gr.Markdown()
    search_btn.click(fn=sloth_agent_search, inputs=query_in, outputs=output_box)

with gr.Tab(" Dump More Clutter (Add Notes)"):
    note_in = gr.Textbox(label="Paste note or snippet:", placeholder="e.g., Gate code is 8842")
    file_in = gr.File(label="Upload .txt file", file_types=[".txt"])
    add_btn = gr.Button(" Ingest Without Organizing")
    status_box = gr.Markdown()
    add_btn.click(fn=handle_upload, inputs=[file_in, note_in], outputs=status_box)

demo.launch(share=True)

How I Built It

SlothVault combines open-weight models, dense semantic retrieval, and the Model Context Protocol (MCP):

Standardized MCP Tool Contracts: Instead of building an ad-hoc search script, the data operations implement retrieve_from_vault and add_to_vault tool definitions, ensuring compatibility with standard agent frameworks.

Fast Local Vector Search: sentence-transformers/all-MiniLM-L6-v2 embeds text into 384-dimensional vectors. Cosine similarity matching retrieves the top-ranked context in milliseconds without a heavy external vector database.

Local Open-Weight Reasoning: Qwen/Qwen2.5-1.5B-Instruct synthesizes the retrieved chunks on-device, extracting precise facts and avoiding generative hallucinations.

Why Does Open Innovation Matter?

Absolute Privacy: Personal notes, Wi-Fi credentials, medical reminders, and invoices never leave the machine. Running inference locally keeps sensitive personal data off third-party servers.

Zero Operating Cost: Powered by open weights, the agent runs entirely free of token limits, monthly subscriptions, or cloud API paywalls.

Offline Reliability: Because the models run on-device, the agent functions normally on a laptop even without an internet connection.

Prize Categories

Top Prize: Slow and Steady ($250 USD)

── more in #ai-agents 4 stories · sorted by recency
── more on @slothvault 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/slothvault-a-zero-ef…] indexed:0 read:4min 2026-10-25 · —