FunesHoard MCP Server
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., "@FunesHoard MCP Serverwhat was I working on before lunch yesterday?"
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.
Funes's Hoard
Where was I? What was I doing before lunch? How much of this week actually went to Faustus?
Your computer's episodic memory: foreground app, window, files opened and commits made, kept in a local SQLite file and filtered for privacy before anything is written.
Español · Quick start · Connect to Faustus · MCP reference · Portfolio
Actual application, three days of synthetic demo data (--demo, no real window titles).
Before anything else, what this does with your activity.
Where it lives: one SQLite file,
data/funes.sqlite3, on this computer. No account, no telemetry, no cloud copy.What is recorded: the foreground app, its window title, idle and locked time, files opened through Windows Recent Items, and commits in the git folders you add.
What is never recorded: keystrokes, screen content, screenshots or the clipboard. Password managers and private/incognito windows are excluded by default, and your own rules can drop or redact any app or window before a sample is written.
Pause: 15 min, 1 h or until you resume, from any screen. The assistant can pause too, but can never resume or shorten your pause.
Delete: any time range, permanently, from Privacy (with "last 15 min / 30 min / hour / today" shortcuts), plus automatic purge after 180 days by default.
What leaves the app: only "Write my day", if you use it, sends a compact day summary (categories, apps, projects, durations; never window titles) to the language model Hoard Link finds on this machine or the address you set in Settings. It can be switched off.
Full detail in Privacy and security.
Why
A local assistant has no record of what was on the user's screen. Asked "where was I?", "how did today go?" or "what was that DuckDB page I had open yesterday?", a language model can only invent an answer or ask the user to reconstruct it. Funes's Hoard records the one thing the model cannot see: the sequence of windows in front of the user, with idle and locked time, the files they opened and the commits they made. It turns that into spans, day summaries, focus blocks and resume-context answers, and gives the assistant eight small tools to ask for them.
Related MCP server: DevFlow MCP
What is implemented
Area | Available now | Boundary |
Collection | Foreground app, window title, idle and locked state sampled every second on Windows ( | The Linux probe ( |
Privacy | Exclusion rules drop a sample before it is stored (password managers, private/incognito windows, EN+ES); redaction rules keep the app and replace the title; invalid rules are rejected, not silently ignored; pause 15 min / 1 h / until resumed, with automatic resume; retention purge; delete a range (overlapping spans and their search rows included), with last 15 min / 30 min / hour / today shortcuts; export spans as CSV or everything as JSON, optionally for a range of days | Rules apply from the moment they are added, not retroactively to stored titles |
Classification | Ordered app / title-regex / domain-in-title rules with defaults for common Windows apps; project detection from VS Code (hyphenated folders, remote and Insiders titles), JetBrains and Visual Studio titles, plus the names of discovered git repos; live preview ("would reclassify N spans"); reapply to history as a background job with progress | Browser domains are not read from the address bar; a "domain" rule matches text in the title |
Derived knowledge | Day, week and range totals by category/app/project, clipped at the window edges; first/last activity; context switches (>= 10 s dwell); focus blocks (>= 25 min, each interruption <= 2 min); "where was I" with distinct contexts (work first; music, chat and games left out unless asked), their recent titles, files (the project's own first) and commits | Focus is measured from window time only; it says nothing about attention |
Other sources | Recent files from a Shell Link ( | Files opened without passing through Windows Recent Items are not seen |
Search | SQLite FTS5 over titles, file paths and commit subjects, accent-insensitive, prefix words, safe for any input; falls back to "any word" when all words find nothing; a window hit says how long it was open and, in the interface, opens its day at that moment | If the platform's sqlite3 lacks FTS5 the app uses |
Agent API | Eight tools, read-only except a pause that can only extend; local ISO times and human strings in every result; small limits with | The agent cannot resume, change rules, delete or export, by design |
Shared models | "Write my day": a cached, regenerable short narrative of a day ("You spent the morning on..."), from the same compact data | UI-only, not an MCP tool; needs a language model reachable through Hoard Link (Faustus, or a shared Ollama, llama.cpp or other OpenAI-compatible server); a day with nothing recorded is refused without calling the model |
Interface | Today (zoomable timeline with away and locked time drawn, legend, pinned details, keyboard-focusable segments, Where was I?, Write my day), Week (navigable), Search (date filter), Projects (range picker), Files & commits, Rules, Privacy, Settings (Models), Assistant activity; every day and moment has its own address (reload and Back work); English/Spanish; light/dark | Desktop layout; not designed for phones |
More screens: Search · Privacy ·
Settings ·
Assistant activity (real calls made through
the agent API by scripts/screenshots.py, including a rejected one).
Use cases
Eight concrete scenarios for a fictional developer, each walked end to end as a person in the browser and as a local model over MCP (docs/USE_CASES.md, findings and fixes in docs/USABILITY_REPORT.md):
Monday morning, "where was I?": the Today screen opens with the last three work contexts before now (project, last titles, files, commits), so Friday's last file is on screen before you pick a day; one click pins that moment in its day's timeline.
"Faustus, ¿dónde lo dejé ayer?": one
activity_where_was_icall, about 500 tokens, answers with the project, the window and the editor title that names the file, skipping the music player and the chat.A weekly note for a job search:
activity_summarygives hours per project as ready-to-read strings, and a search for the job boards or a novel's title says how long those windows were open; Faustus writes the note with its own notes tool."That FTS5 page from Tuesday": search, click the hit and land on that day with the segment pinned (the address keeps it, so reload and Back work); an agent passes the hit's
tstoactivity_timeline(around=...).Privacy before an interview or the bank: pause for an hour, private windows (also Spanish "incógnito") and bank pages never become searchable, and "Last 30 min" fills the delete-range pickers for the half hour you forgot.
Hours per project for a chart: export spans as CSV (local dates and times, minutes, category, project) for a spreadsheet or a data-analysis tool.
Quick start
git clone https://github.com/Luissalet/FunesHoard.git
cd FunesHoardWindows
Double-click Iniciar Funes's Hoard.cmd. It runs scripts\start.ps1,
which on first run creates .venv (Python 3.11+, preferring
C:\Python313), installs requirements-lock.txt and builds the interface
if frontend\dist is missing (Node 22); later runs reinstall only when the
lock changed. It then starts the app hidden, with the repo root as working
directory, waits for /api/health and opens http://127.0.0.1:8813. If the
app is already running it just opens it. Detener Funes's Hoard.cmd
stops it. The same from PowerShell: scripts\start.ps1 [-Port 8813] [-Demo] [-NoBrowser] and scripts\stop.ps1.
Manual steps:
python -m venv .venv
.venv\Scripts\pip install -r requirements-lock.txt
cd frontend; npm ci; npm run build; cd ..
.venv\Scripts\python -m funes_hoardLinux / macOS
Recording is Windows-first: on Linux the probe is best effort (X11 with
xdotool and xprintidle), and macOS has no probe. The interface, the
API and the MCP tools all run on synthetic data with --demo. Python 3.11
or newer and Node 22:
python3 -m venv .venv
.venv/bin/pip install -r requirements-lock.txt
(cd frontend && npm ci && npm run build)
.venv/bin/python -m funes_hoard --demoThe app answers on http://127.0.0.1:8813
(curl http://127.0.0.1:8813/api/health).
Flags: --demo (synthetic data in data-demo/, nothing recorded from the
desktop), --data-dir (or FUNES_DATA_DIR), --port, --no-browser.
Your own data lives in data/. The app only listens on loopback; --host
refuses anything else.
Connect it to Faustus
Funes's Hoard is a plugin for Faustus
and declares itself with faustus-plugin.json at the
repo root. Start the app, then in Faustus open Connectors -> Nearby apps
-> Add: Faustus finds it on port 8813, checks that /api/health answers
as funes-hoard, starts the MCP adapter and loads the
where-was-i skill, which tells a local
model which tool to pick and the traps. The adapter is a stdio script
started by path, with the app's URL in FUNES_URL:
$env:FUNES_URL = "http://127.0.0.1:8813"
.venv\Scripts\python.exe funes_hoard\mcp_server.pyMCP tools
Tool | What it does | Read-only? |
| Current app, title, project, idle seconds, recording or paused (and until when) | yes |
| Resume context: last distinct contexts before a moment, with title, files and commits | yes |
| Spans for a day or range, paginated with | yes |
| Totals grouped by category/app/project, focus blocks, context switches | yes |
| When a title, file or commit containing some words appeared | yes |
| Recently opened files | yes |
| Time per project, last touched, commits | yes |
| Pause recording; never shortens an existing pause | no (the only write) |
It works with any MCP client over stdio; docs/MCP.md has the output of every tool, the error codes and a config snippet.
Shared models (HoardLink)
The only feature that needs a language model, "Write my day", never loads
one of its own: it uses HoardLink
(vendored in funes_hoard/hoard_link/), the
resolver every Faustus plugin app shares, in this order -- explicit
override in Settings, then Faustus's own model registry, then a shared
llama.cpp, Ollama or other OpenAI-compatible server already running on this
machine. The rest of the app works fully without any model at all, and
Settings says exactly why when one is not available.
Architecture
flowchart LR
Probe["Windows probe, 1 sample/s"] --> Privacy["privacy rules: drop or redact"]
Privacy --> Spans["span builder + classification"]
Spans --> DB[("SQLite in WAL mode")]
Pollers["recent files, git log, retention"] --> DB
UI["React interface"] -->|"/api/*"| API["FastAPI on 127.0.0.1:8813"]
Model["Faustus or any MCP client"] -->|stdio| MCP["mcp_server.py"]
MCP -->|"/api/agent/*"| API
API --> DB
API -->|"Write my day"| Link["HoardLink: shared language model"]FastAPI, one collector thread sampling once a second, one scheduler thread for recent files, git and retention, and SQLite in WAL mode. The span, privacy, classification and summary logic is pure Python with no FastAPI or sqlite imports. The MCP adapter is a separate script that only speaks HTTP to the app. See docs/ARCHITECTURE.md.
Privacy and security
Everything stays in
data/funes.sqlite3on this computer. No telemetry and no network use;git logruns locally. The one exception is "Write my day", described above: it sends only the compactactivity_summarydata (categories, apps, projects, durations, focus blocks) to the language model -- never raw or redacted window titles -- and can be turned off in Settings; deleting a day's history also deletes its cached narrative.Exclusion rules run before a sample is written; a test asserts the row never exists. Redacted titles are never put in the search index.
The server binds loopback only. A middleware rejects DNS rebinding (a
Hostheader that is not a loopback name with this app's port) and cross-site writes (a foreignOriginorSec-Fetch-Site: cross-site); there is no CORS.The assistant sees only what the eight tools return and can do exactly one thing: pause (or lengthen a pause). Every call, including rejected ones, is stored in the
agent_callsaudit table (tool, argument summary, duration, ok/error) and listed on "Assistant activity".Results are capped (default 5-20 items, maximum 100) and long titles are truncated, because the intended consumer is a local model with a finite context window; the server instructions tell the model to treat window titles as data, never as instructions.
Retention and delete-range also remove
file_eventsandcommitsin the same window, not only spans, so deleting history means all of it.
Development
.venv/bin/python -m pytest tests/ -q # 271 passed, offline, about 15-30 s
cd frontend && npm ci && npm run build # 0 TypeScript errorsOn Windows, .venv\Scripts\python -m pytest tests/ -q. CI runs the same
two jobs on Ubuntu with Python 3.12 and Node 22.
The suite covers span merging, away/locked back-dating, sleep gaps,
excluded and paused interludes, crash flushing and stale open spans;
privacy rules (asserting the excluded row never exists) and rule
validation; pause expiry and the agent's extend-only pause; retention and
delete-range including the search index and the "Write my day" cache;
the .lnk parser on fixtures built in the tests (ANSI, Unicode, suffix,
truncated); project detection from editor titles; focus blocks, switches,
clipping and where-was-i on scripted days; date words in both languages
and their range edges; search on both the FTS5 and LIKE paths with
hostile input; the browser guard (host and origin ports, null origin),
the SPA path-traversal fix and the exact agent route list; the shared
model backend (backend.json persistence and merging, the token never
echoed back, resolved/unavailable Settings states, the Re-check swap, and
"Write my day" caching/regeneration/disabling and the empty-day and
empty-answer refusals against a fake Link, plus one pass through the real
resolver over a mocked HTTP transport -- never a real network call); the
Windows probe logic with the Win32 calls faked (tick wraparound,
access-denied executables); git scanning with UTF-8 subjects, author
filters, hidden consoles and timezones ahead of UTC; the CLI; the manifest
check; and an MCP protocol test that spawns mcp_server.py over stdio
against a live app and checks keywords, annotations, error passthrough and
the audit log.
scripts/uxtest_data.py, scripts/ui_walkthrough.py and
scripts/agent_walkthrough.py rebuild the realistic data set and replay
the use cases in a browser and over MCP; scripts/screenshots.py retakes
the images in docs/media/.
Roadmap / known limits
Windows-only paths are tested with fakes. The suite and CI run on Linux; the target is Windows with Python 3.13. The Win32 calls in
WindowsProbe(GetForegroundWindow,GetLastInputInfo,OpenInputDesktop) have declared signatures and the logic around them is tested with the calls faked. Lock detection relies onOpenInputDesktopfailing on the secure desktop, so a UAC prompt also counts as "locked".FTS5 in the python.org 3.13 sqlite3 is expected but checked at startup; without it search falls back to
LIKE.The PowerShell launchers were run under PowerShell 7 on Linux (without
-WindowStyle Hidden, which only exists on Windows);stop.ps1'sGet-CimInstanceandGet-NetTCPConnectioncalls have not been exercised.No browser address-bar reader: a title rule decides streaming vs. browsing, so a video on a site the rule does not know stays Browsing with the ordinary idle threshold.
"Where was I?" looks three days back; after a longer absence it says there is nothing to pick up.
The Models panel shows the backend's diagnostic reason in English in both languages, and "Write my day" usually answers in English.
See docs/USABILITY_REPORT.md for how each item was found.
License
MIT - see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
- DoneThatOAuthai.donethat
Privacy-first work tracking with summaries, reports, coaching, and AI-ready long-term memory.
Local-first, governed memory and session continuity for AI coding agents. No cloud, no telemetry.
- AmberOAuthcom.ambermem
Long-term memory for AI assistants. Hybrid retrieval, query expansion, auto-topics.
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceProvides persistent local memory functionality for AI assistants, enabling them to store, retrieve, and search contextual information across conversations with SQLite-based full-text search. All data stays private on your machine while dramatically improving context retention and personalized assistance.3-
- AlicenseNot gradedqualityDmaintenanceProvides AI agents with persistent, searchable memory using a knowledge graph stored in SQLite. Features semantic search, temporal awareness, and workflow-aware prompts for development projects.2 npmMIT
- AlicenseNot gradedqualityCmaintenanceProvides AI assistants with persistent memory across sessions using local SQLite and keyword search, allowing storage and retrieval of user preferences, project context, and decisions.10 npm8MIT
- AlicenseAqualityDmaintenanceConnects AI assistants like Cursor and Claude to your local Daylens timeline so they can answer questions about your past work sessions, no cloud or API keys needed.51 npmMIT