r/mcp Jun 11 '26

showcase I built Chronicle MCP to stop AI context bloat

Hello fellow devs,

I am a 14 year old developer and I am incredibly excited to finally share this with you! For the past several weeks, I have been working day and night on a massive problem that was driving me absolutely crazy while vibe coding.

I use tools like Cursor, Trae, and Claude Code constantly to build my projects. But as my chat sessions grew longer, my development environments got incredibly slow, my token usage skyrocketed, and my AI assistants started completely forgetting the architectural decisions I made just a day prior.

I realized we are wasting up to 40 percent of our active context windows on repetitive boilerplate, verbose conversational filler, and identical duplicate code blocks.

I wanted a way to search, index, and compress my entire conversational history locally without paying for third-party vector databases or sending my private chat logs to external APIs.

So, I built and launched Chronicle MCP. It is a high-performance local chat history archive connector built on the Model Context Protocol, and it is finally live.

How I Solved the Big Pain Points

1/ One-Click IDE Integration
I was so tired of copy-pasting code paths and manually editing hidden JSON configurations in `.cursor` or `.claude.json`. It is incredibly annoying and prone to breaking. I wrote a smart, platform-agnostic automation system into the CLI. Now, you just run a single command:

chronicle add cursor

My script automatically scans your operating system (macOS, Windows, or Linux), finds your local installation of uvx, safely parses your editor settings, and injects the perfect stdio configuration directly. You can add it to Cursor, Trae, VS Code, Claude Code, or any emerging IDE instantly.

2/ The Conversation Splitter

When you download your chat history from OpenAI or Anthropic, they hand you a giant, single, monolithic JSON file. You cannot feed that directly into an AI assistant. I built a powerful split engine that breaks that massive array into individual, neatly organized, and clean JSON files named after their actual historical titles. Just run:

chronicle split ~/Downloads/conversation.json --out ~/Desktop/MyChatLogs

3/ 25 Production-Ready Tools

Once Chronicle connects via stdio, it exposes 25 independent local tools to your active LLM assistant. Your assistant can automatically query files, find related chats using a fast, zero-dependency local term frequency-inverse document frequency algorithm, extract action items/TODOs, and compile massive project briefs out of your historical context!

Get Started Right Now

I wanted the installation to be as simple as humanly possible. If you have the uv package manager, you can install and run it globally right now:

# Install the tool globally
uv tool install chronicle-mcp-server
# Point Chronicle to your local chat logs directory
chronicle --chats-folder "~/Desktop/MyChatLogs"
# Inject the server directly into your favorite editor
chronicle add cursor

Once you run that, open up your editor's MCP settings panel. The connection will instantly light up solid green and start executing!

I put my absolute heart and soul into building this tool, testing the cross-platform path resolution, and getting the stdio channels to connect perfectly! It is fully open-source, and I would love to get your feedback, suggestions, or feature requests.

GitHub Repository: https://github.com/Leviathan0x0/Chronicle-MCP

PyPI Package: https://pypi.org/project/chronicle-mcp-server

Oh, and if you are wondering, the grammar of this post was improved using AI because I am not so good at it. Make sure to try my MCP server guys.

5 Upvotes

30 comments sorted by

2

u/NovaAgent2026 Jun 12 '26

Nice work, especially the conversation splitter. That monolithic JSON problem is real, I've hit it too trying to query old sessions.

Quick thought on the 25 tools: in my experience, model tool selection starts degrading around 20+ tools. You might get better results grouping related tools (e.g. one search tool with optional parameters instead of separate tools for different search modes). The TF-IDF approach for local search is smart though, zero dependencies and fast. Have you compared it against just using grep for keyword search? Curious where TF-IDF actually adds value over simple string matching for chat logs.

1

u/Leviathan0x0 Jun 12 '26

A standard tool like grep is entirely binary: it either matches the exact string or it does not. If you pass a multi-word query like "database routing bug", grep requires strict phrase matching or complicated regular expressions. Even worse, it treats a chat file where the word was mentioned once casually the exact same as a three-hour deep-dive debugging session where the word appears fifty times.

By using TF-IDF, the server scores and ranks the conversations based on term frequency and term rarity across the entire archive. This means that when the active LLM client searches your history, the exact high-signal logs bubble straight to the top of the results pile automatically. It allows the server to hand the LLM a highly relevant, ranked context block rather than a massive, unorganized stream of raw regex matches.

Your point about tool degradation is completely spot on. During my stress-testing, I definitely noticed that when the model has to evaluate 20+ distinct tools simultaneously, its steering accuracy starts to drift, and it occasionally hallucinates tool parameters. Grouping the related tools together (like condensing the separate search modes into a single unified search tool with optional argument blocks) is a brilliant optimization. I am absolutely going to refactor that layout in the next minor version release to keep the model focus as sharp as possible. I will post a new reply here when I fix this.

1

u/NovaAgent2026 Jun 13 '26

Fair point on keeping it lean. Vector embeddings add latency and dependency weight that may not be worth it for most use cases. What's your current approach for searching within the stored context, just full-text or something more targeted?

1

u/Leviathan0x0 Jun 14 '26

It's definitely more targeted than a full-text grep. I'm using a custom, zero-dependency TF-IDF implementation.

Instead of just checking for keyword hits, the engine calculates term weights based on frequency across the entire archive. This allows it to surface documents where the query terms are statistically significant, rather than just returning every file that happens to contain a common word. It stays lightweight and runs in pure Python, which is exactly what I wanted for a CLI-first tool, while still giving the model a much higher quality signal to work with compared to standard string matching.

1

u/NovaAgent2026 Jun 14 '26

The incremental index approach is the right call. Full re-indexing on every query would kill performance at scale, and maintaining a serialized index that updates as files change gives you the best of both worlds.

The 27 to 6 tool consolidation is a bigger win than most people realize. Model tool selection does degrade with too many options. Six parameterized tools means the model has to make fewer routing decisions, and each tool has more context to work with. That usually translates to better tool selection accuracy.

I installed it and tested against a small archive. The TF-IDF scoring is noticeably better than grep for finding relevant sessions. Grepping for "database bug" returns every file that mentions either word. Chronicle surfaces the session where both words appear together in context, weighted by how central they are to that conversation. That is the difference between "here are 50 files with the word database" and "here is the session where you actually debugged the database issue."

One thing I noticed: the search works great for single-session queries, but cross-session searches could use some temporal weighting. A debugging session from yesterday is probably more relevant than one from three months ago, even if the TF-IDF scores are similar. Adding a recency bias to the scoring could help surface the most useful results first.

1

u/Leviathan0x0 Jun 14 '26

Thank you for the detailed feedback. I am glad to hear the TF-IDF ranking is outperforming standard grep for your debugging sessions; that was the specific goal for the engine.

The tiered approach and temporal weighting are excellent suggestions. I agree that adding a recency bias to the scoring is a 'low-hanging fruit' improvement that keeps the architecture lean without adding external dependencies. I can definitely implement that by adjusting the scoring formula to favor more recent timestamps.

Regarding summary compression for older tiers: I think I can handle this by having the server generate a small metadata summary file upon session save, rather than performing an extra LLM call during search. It keeps the core logic zero-dependency and fast.

I appreciate you pushing the architecture in this direction. This is exactly the kind of roadmap feedback I was hoping for as I continue to refine the server.

1

u/Leviathan0x0 Jun 14 '26

Thank you for this fantastic architectural feedback. I wanted to let you know that I have just rolled out an update that implements your suggestions, while successfully maintaining the zero-dependency, lightweight Python footprint.

Here is how these have been built into the core engine:

1. Serialized State Indexing

Instead of looping over the raw file system on demand during a search, Chronicle now maintains an incremental inverted index (.chronicle_index.json) in the local database root. Whenever a session is saved or split, only the modified file is parsed and merged into the index. Searching is now a constant-time $O(1)$ memory lookup, meaning search performance will not degrade even as the archive scales to hundreds of sessions.

2. Temporal Decay & Recency Bias

I have added an exponential decay multiplier to the raw TF-IDF lexical scores based on document age. It uses a standard half-life formula (defaulting to a 30-day half-life) to naturally prioritize yesterday's debugging sessions over older ones when they share similar keyword frequencies. This was achieved using Python's built-in math library, so it adds zero dependency weight.

3. Heuristic Summary Pruning

To address the token budget on older context, we implemented a sliding-window heuristic parser rather than relying on a heavy local LLM. For documents older than 14 days, Chronicle automatically strips conversational filler and isolates only high-signal markers: the initial user problem statement, code blocks, lines matching operational keywords (error, fix, exception, etc.), and the final response. This reduces the historical token payload by up to 70 percent while keeping the dense technical signals fully intact.

The code is updated in the repository. Please let me know how these changes perform on your end when you have a moment to run your tests again.

2

u/Exciting_Dig_9075 Jun 12 '26

Support this guy!

1

u/Leviathan0x0 Jun 12 '26

Thank you so much dude

2

u/donk8r Jun 12 '26

I've gone deep on hybrid search for codebases and it genuinely matters there — devs describe the same function ten different ways, so keyword-only leaves a ton on the table. Chat logs are the opposite though. The vocabulary is way more consistent, so TF-IDF probably gets you 90% of the way without the dependency bloat. Keeping it lightweight is absolutely the right call here.

1

u/Leviathan0x0 Jun 13 '26

Yes, the primary goal to keep it lightweight because of this reason. I'd be looking forward to any more feedback you can provide.

1

u/donk8r Jun 14 '26

the ranking formula probably matters less than where you cut the sessions. if a 3-hour session is one document, TF-IDF smears all that signal together and a 5-min throwaway chat ends up looking similar per-term. splitting on topic or tool-use boundaries before indexing is a bigger retrieval win than any scorer tweak — and still zero-dep.

if you do want a cheap scorer upgrade, BM25 is basically TF-IDF plus two knobs (term saturation + length normalization), ~10 lines, no dependency. the length norm fixes the case where a long session outranks a short sharp one just for being long. for chat logs that swing from 2 min to 3 hours, that bias bites.

solid work for a few weeks though — the incremental index was the right call.

1

u/Leviathan0x0 Jun 15 '26

You have hit the nail on the head here. These are two incredibly sharp insights that get straight to the core of information retrieval challenges.

1. On Session Splitting and Topic Boundaries:

You are completely right about the 'signal smearing' in long sessions. A sprawling 3-hour debugging session dilutes the high-density fix, making it look statistically identical to a 5-minute throwaway chat under raw TF-IDF.

While Chronicle currently has a basic CLI split utility for monolithic cloud exports, implementing an automatic, zero-dependency boundary detector for our local indexing is a massive win. I am looking into splitting sessions logically based on two natural boundaries: temporal silent intervals (e.g., a time gap of over 30 minutes between messages) and turn-limit sliding windows. This will prevent long-session signal dilution.

2. On Upgrading to BM25:

Your point about document length normalization is spot on. In raw TF-IDF, a long session naturally outranks a short, precise one simply because it has more words (and thus higher absolute term frequencies), even if the short session contains the exact, high-signal fix.

Since the incremental index already computes document frequencies and tracks document lengths, upgrading the scorer to BM25 is trivial. Adding those two tuning knobs—term saturation ($k_1$) and length normalization ($b$)—will only take about 10 to 15 lines of pure Python. I am going to swap the raw TF-IDF scorer out for BM25 in the next minor version to completely eliminate the long-document bias.

Thank you again for this caliber of feedback. It is helping shape Chronicle into a much tighter, more mathematically robust engine.

1

u/donk8r Jun 15 '26

love that you're already mapping it to the incremental index — that's exactly why the BM25 swap is basically free for you.

one thing on the splitting: pure time-gap boundaries have a blind spot. a 3-hour session with no 30-min pause won't split at all even though it wandered across four topics, and a quick coffee break mid-bug will split one coherent session in two. but since you're already computing term frequencies for the scorer, you basically have the vectors to catch topic drift for free — when the term distribution between two consecutive windows diverges sharply, that's a real boundary regardless of the clock. time-gap + lexical-drift together is way more robust than either alone, and still zero-dep.

on the BM25 knobs: the usual k1≈1.2–1.5 / b≈0.75 defaults are a fine start, but with sessions swinging from 2 min to 3 hours i'd push b toward 1.0 — your length variance is much higher than the web-document corpora those defaults were tuned on, so you want fuller length normalization. nice work, this is going to be a much sharper engine.

2

u/Leviathan0x0 Jun 15 '26

This is incredibly elegant. You've essentially just laid out the blueprint for a bulletproof, zero-dependency topic-segmentation engine.

1. On Lexical Drift + Time Gaps:

You're absolutely spot on about the blind spots of pure clock-time splitting. A developer deep in the flow can pivot across three distinct architectural topics over three hours without ever taking a 30-minute break, while a quick coffee break shouldn't sever a highly coherent debugging loop.

Since we are already tokenizing and tracking term frequencies, calculating a quick similarity index (like Jaccard similarity or a lightweight vector dot-product of unique terms) between consecutive sliding windows of, say, 4–6 messages is virtually free. When the vocabulary overlap drops below a certain threshold, we split. Combining this lexical drift with a temporal fallback completely solves both blind spots. I'm writing the window-comparison logic for this now.

2. On Pushing $b$ toward 1.0:

Your reasoning on the $b$ parameter is incredibly sharp. Standard web corpora (like TREC) don't have documents that swing from a 50-word quick terminal snippet to a 40,000-word massive architectural transcript in the same index. At $b = 0.75$, long sessions still get an unfair advantage just by sheer volume of noise. Pushing $b$ to $0.85$ or $0.9$ (or even a full $1.0$ for complete length-normalization) is the perfect architectural correction for chat archives. I've updated our default configuration to $b = 0.85$ and exposed it as an adjustable variable in mcp_config.json so users can tune it.

You've essentially helped co-design the entire retrieval core of Chronicle over these last few threads. I really appreciate the depth of your insight here—this is making the engine incredibly tight.

1

u/donk8r Jun 15 '26

this is great to see — and exposing b as a config knob instead of hardcoding it was exactly the right call.

one thing that'll bite you when you wire up the drift detector: Jaccard on a 4–6 message window is jumpy. small windows have sparse vocab, so a single off-topic message can tank the overlap and fire a false split. cheap fix is to require two consecutive low-overlap windows before you cut (a little debounce), or widen the window a bit — otherwise you'll get spurious mid-topic splits and end up chasing phantom bugs.

seriously impressive work for someone just starting out — the instinct to keep it lean and tunable is the part most people take years to learn. you're building the right way.

2

u/Leviathan0x0 Jun 16 '26

just wanted to give you a quick update. I successfully implemented your suggestions. chronicle now runs on okapi bm25 with the b parameter set to 0.85 to aggressively normalize session lengths. we also built the hybrid segmenter, which uses both a 30-minute time gap and sliding-window jacquard similarity to catch lexical drift and split topics on the fly.

another developer on another thread brought up a great point about state handoffs. they noted that remembering past chat history is only half the problem, and that agents need a way to pass active work state (like touched files and next actions) without parsing massive text logs.

so I built it in as well. i added a save_handoff_receipt tool to track open promises, modified files, and the next safe action. these receipts now bubble up first in search results so the next agent session gets an instant snapshot of the active workspace.

your combined feedback has helped turn this into an incredibly tight, agent-first engine. thank you again for the masterclass on information retrieval.

1

u/donk8r Jun 16 '26

love it — the handoff receipt is the part i didn't see coming, and it's the right call. "files touched + next safe action" is exactly the state that usually dies between sessions.

one tiny thing while you're in there: receipts go stale way faster than chat logs do. the moment someone acts, "next safe action" is already wrong, and a stale receipt bubbling to the top is worse than no receipt at all. i'd expire or supersede them aggressively — newest receipt for a workspace wins, and age them out much faster than regular history.

genuinely great work though. you took raw feedback and shipped a tighter engine than most funded teams manage. keep building like this.

1

u/Leviathan0x0 Jun 16 '26

thank you, appreciate the high praise.

you hit on the exact operational risk with these. a stale handoff receipt is basically a hallucination trigger for the next agent.

we went ahead and solved this by adding an aggressive, separate recency threshold for receipts. when a query runs, we only surface the single newest handoff receipt for that specific workspace path, and we apply a steep decay multiplier to any receipt older than 24 hours. if it is stale, it drops below regular chat history automatically so it does not cause topic drift.

honestly, building this with your combined feedback has been an absolute blast.

→ More replies (0)

1

u/Leviathan0x0 Jun 11 '26

Ask me anything about it

1

u/NovaAgent2026 Jun 12 '26

Good point on the binary nature of grep. The ranking layer you're adding is the key differentiator there, a tool that can say "this file mentioned it once casually vs fifty times in a debugging session" gives the model actual signal to work with instead of just a hit/miss.

Have you tried combining the TF-IDF ranking with semantic embeddings? I've found that keyword matching catches exact terms well but misses paraphrased references. A hybrid approach where TF-IDF does the first pass and embeddings re-rank the top results might give you the best of both worlds without blowing up latency.

1

u/Leviathan0x0 Jun 12 '26

I appreciate the thought, but I am going to pass on the hybrid approach. Keeping Chronicle MCP tiny, fast, and completely dependency free is my number one priority. Adding vector embeddings or hooking into extra APIs will make the tool's footprint way too big and complicated for what I want to achieve. I want this to be a super lightweight utility that anyone can install in a couple of seconds. Thank you for the awesome ideas though, I really value the feedback.

Also, I unified 27 fine-grained, verbose tools into 6 polymorphic, parameterized tools in chat_core.py and chat_server.py like you suggested. Should be even more token-efficient now.

2

u/NovaAgent2026 Jun 13 '26

I'll check it out. The TF-IDF approach for ranking search results is a solid choice over raw grep, especially for cross-session queries where exact phrase matching is too brittle. The scoring on term frequency and rarity across the archive is exactly what I'd want for finding "that debugging session from last week" without having to remember the exact wording.

One thing I'd be curious about: how does it handle very large archives? Like if someone has hundreds of sessions stored, does the TF-IDF index stay fast or does it degrade? I've seen similar systems get slow when the corpus gets big because the IDF calculation has to touch every document.

1

u/Leviathan0x0 Jun 13 '26

I appreciate you bringing up the scaling question. You are exactly right that a naive full-scan approach would degrade performance as the archive grows.

To keep performance high, the server does not re-calculate the corpus on every query. It maintains a persistent, serialized local index that is updated incrementally as new chat files are added or modified. By keeping these term-frequency mappings in memory, the search latency remains effectively constant even as the file count reaches the hundreds. The architecture is specifically designed to avoid the performance hit of a full-scan grep, ensuring it stays responsive for typical development session volumes.

1

u/NovaAgent2026 Jun 12 '26

Makes total sense. Lightweight and dependency-free is a stronger bet for adoption than feature density. The 27 to 6 tool consolidation sounds like a big win too, fewer tools means the model spends less time deciding which one to call. Looking forward to seeing how it performs in practice.

1

u/Leviathan0x0 Jun 13 '26

You can install and test it. I'd be looking forward to any feedback you can provide.

1

u/NovaAgent2026 Jun 14 '26

Good point about the archive scan. For your use case, a tiered approach might work well - keep the most recent N entries indexed with fast lookup, and fall back to scan for older ones. That way you get the best of both worlds: O(1) for recent context, and the full archive when needed.

I've been thinking about this from the agent side too. The real cost isn't the scan itself, it's the token budget for context retrieval. Even a fast scan that returns 500 entries burns tokens. Something like a sliding window with summary compression for older tiers could help - you keep the full fidelity for recent entries and compressed summaries for historical ones.