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

> Source: <https://dev.to/adibshaikh9922/slothvault-a-zero-effort-local-mcp-rag-agent-that-rewards-digital-lazinesspublished-true-k1d>
> Published: 2026-10-25 16:42:04+00:00

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`).

``` python
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

# 1. Load Local Open-Weight Models
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
)

# 2. In-Memory Vault & Seed Data
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)

# 3. Model Context Protocol (MCP) Tool Functions
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)}"

# 4. Agent Synthesis
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)
