<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mcp on WormBytes</title><link>https://www.wormbytes.ca/tags/mcp/</link><description>Recent content in Mcp on WormBytes</description><generator>Hugo -- gohugo.io</generator><language>en-ca</language><managingEditor>Robert James Kaes</managingEditor><copyright>Robert James Kaes. All Rights Reserved.</copyright><lastBuildDate>Fri, 06 Mar 2026 12:00:00 +0000</lastBuildDate><atom:link href="https://www.wormbytes.ca/tags/mcp/index.xml" rel="self" type="application/rss+xml"/><item><title>trueline-mcp v2: Now For Everyone, Not Just Claude Code</title><link>https://www.wormbytes.ca/2026/03/06/trueline-v2-announcement/</link><pubDate>Fri, 06 Mar 2026 12:00:00 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2026/03/06/trueline-v2-announcement/</guid><description>&lt;p&gt;Two days ago I &lt;a href="https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/"&gt;announced trueline-mcp&lt;/a&gt;, hash-verified, token-efficient file editing for Claude Code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using it to build new features and performance improvements. It
works great!&lt;/p&gt;
&lt;p&gt;But it only worked with Claude Code, and the MCP protocol doesn&amp;rsquo;t care which agent is on the other end of the pipe.&lt;/p&gt;
&lt;p&gt;So I made it work everywhere.&lt;/p&gt;
&lt;h2 id="five-platforms-one-tool"&gt;Five platforms, one tool&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline-mcp&lt;/a&gt; v2.0 supports &lt;strong&gt;Gemini CLI&lt;/strong&gt;, &lt;strong&gt;VS Code Copilot&lt;/strong&gt;, &lt;strong&gt;OpenCode&lt;/strong&gt;, and &lt;strong&gt;Codex CLI&lt;/strong&gt; alongside Claude Code. Same hash-verified edits, same token savings, regardless of which agent you&amp;rsquo;re running.&lt;/p&gt;
&lt;p&gt;The hook system got a complete refactoring to make this possible. Platform-specific logic (tool names, response shapes, event naming) is isolated into thin wrappers around a shared core. A universal CLI dispatcher normalizes everything:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;trueline-hook &amp;lt;platform&amp;gt; &amp;lt;event&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Gemini calls its pre-tool event &lt;code&gt;beforetool&lt;/code&gt;. Claude Code calls it &lt;code&gt;pretooluse&lt;/code&gt;. The dispatcher routes both to the same verification logic.&lt;/p&gt;
&lt;p&gt;Each platform gets its own instruction file tuned to that agent&amp;rsquo;s built-in tool names. The &lt;code&gt;read_file&lt;/code&gt; → &lt;code&gt;trueline_read&lt;/code&gt; redirect that makes sense for Gemini CLI would be nonsensical for Claude Code&amp;rsquo;s &lt;code&gt;Read&lt;/code&gt; tool. These details matter when you&amp;rsquo;re intercepting tool calls.&lt;/p&gt;
&lt;p&gt;You can also install it from npm now:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;npm install -g trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="trueline_outline-skip-reading-entirely"&gt;&lt;code&gt;trueline_outline&lt;/code&gt;: skip reading entirely!&lt;/h2&gt;
&lt;p&gt;v1.1 added a fourth tool: &lt;code&gt;trueline_outline&lt;/code&gt;. It uses tree-sitter (via WASM) to extract the structural skeleton of a file (functions, classes, types, interfaces) without reading the source. Think of it as a table of contents.&lt;/p&gt;
&lt;p&gt;For navigation and understanding, that&amp;rsquo;s usually &lt;em&gt;enough&lt;/em&gt;. The agent doesn&amp;rsquo;t need to read 400 lines of a file to find the function it wants to edit. It outlines the file, identifies the 15-line range, reads just those lines, and edits. That&amp;rsquo;s a ~95% token reduction on the read side for the common case.&lt;/p&gt;
&lt;p&gt;Supported languages: TypeScript, JavaScript, Python, Rust, Go, Java, C, C++, C#, Ruby, Swift, and more.&lt;/p&gt;
&lt;h2 id="smarter-hook-less-friction"&gt;Smarter hook, less friction&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;PreToolUse&lt;/code&gt; hook that blocks the built-in Edit tool used to be a blunt instrument. It blocked &lt;em&gt;every&lt;/em&gt; edit attempt and redirected to trueline. Problem is, trueline can&amp;rsquo;t access every file. If a file is outside the allowed directories or matches a deny pattern, the block just caused a confusing failure.&lt;/p&gt;
&lt;p&gt;Now the hook checks whether trueline actually has access to the target file before blocking. If it doesn&amp;rsquo;t, the built-in tool is allowed through. Same security boundary, fewer dead ends.&lt;/p&gt;
&lt;h2 id="performance"&gt;Performance&lt;/h2&gt;
&lt;p&gt;Two targeted optimizations in the hot paths:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read path&lt;/strong&gt; — Pre-computed a static lookup table for hash encoding (replacing per-line &lt;code&gt;String.fromCharCode&lt;/code&gt; calls) and switched to buffer-based output assembly. Lines stay as raw &lt;code&gt;Buffer&lt;/code&gt; bytes through the loop with a single decode at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit path&lt;/strong&gt; — Pass-through lines (the vast majority in any edit) were being hashed twice: once for checksum verification, once for the output file. Now they reuse the first hash.&lt;/p&gt;
&lt;p&gt;The diff engine also got replaced. The old &lt;code&gt;diff&lt;/code&gt; npm dependency compared two full file snapshots in memory. The new &lt;code&gt;DiffCollector&lt;/code&gt; builds unified diffs incrementally during the streaming edit pass. One fewer dependency, no full-file buffering.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re on Claude Code and already have trueline installed, update to the latest:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/plugin install trueline-mcp@trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you&amp;rsquo;re new, or on a different platform, setup instructions for all five platforms are in &lt;a href="https://github.com/rjkaes/trueline-mcp/blob/main/INSTALL.md"&gt;INSTALL.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The core is solid. The edit verification, streaming architecture, and token savings work the same across all platforms now. If you&amp;rsquo;re burning tokens on string-matched edits, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;give it a shot&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Claude Code's Edit Tool Wastes Your Most Expensive Tokens. Here's a Fix.</title><link>https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/</link><pubDate>Wed, 04 Mar 2026 15:32:47 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/</guid><description>&lt;p&gt;You&amp;rsquo;re deep into a Claude Code session. The agent is humming along, editing files, and making progress.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And quietly bleeding money on every single edit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why. The built-in &lt;code&gt;Edit&lt;/code&gt; tool uses string matching. To change five lines of code, the model has to echo back those exact five lines as &lt;code&gt;old_string&lt;/code&gt;, then provide the replacement as &lt;code&gt;new_string&lt;/code&gt;. That echoed text is pure overhead: it&amp;rsquo;s already in the file. The model is spending output tokens, the &lt;strong&gt;most expensive token class&lt;/strong&gt;, just to point at code and say &amp;ldquo;I mean &lt;em&gt;this&lt;/em&gt; part.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For a typical 15-line edit, that&amp;rsquo;s &lt;strong&gt;~200 wasted output tokens&lt;/strong&gt;. Do a few dozen edits in a session (not unusual for any real feature work) and you&amp;rsquo;re burning serious money on text the model already knows is there.&lt;/p&gt;
&lt;p&gt;It gets worse when something goes wrong. If the file changed since the agent last read it (maybe you saved in your editor, maybe another tool touched it) the string match fails. The model hallucinating a character or two has the same effect. Either way, the edit errors out, the agent re-reads the whole file to get back in sync, and you&amp;rsquo;ve just paid for all that content &lt;em&gt;again&lt;/em&gt;. In longer sessions, these re-reads compound.&lt;/p&gt;
&lt;p&gt;I got tired of watching this happen, so I built &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline-mcp&lt;/a&gt; to fix both problems.&lt;/p&gt;
&lt;h2 id="the-token-tax-on-every-edit"&gt;The token tax on every edit&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at what&amp;rsquo;s actually happening. Here&amp;rsquo;s the built-in &lt;code&gt;Edit&lt;/code&gt; under the hood. The model has to echo the old text just to locate the change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;src/server.ts&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;old_string&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n validate(body);\n return process(body);\n}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;new_string&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n const parsed = schema.parse(body);\n return process(parsed);\n}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;See all that duplicated text? &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; replaces it with a compact line-range reference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;src/server.ts&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;edits&amp;#34;&lt;/span&gt;: [{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;checksum&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;1-50:a3b1c2d4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;range&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;12:kf..16:qz&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n const parsed = schema.parse(body);\n return process(parsed);\n}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The model never echoes the old text. It says which lines to replace, proves it read them correctly, and provides the new content. ~200 fewer output tokens per edit, on the most expensive token class.&lt;/p&gt;
&lt;p&gt;Oh, and there&amp;rsquo;s a fun gotcha with the built-in tool: if &lt;code&gt;old_string&lt;/code&gt; appears more than once in the file, the edit fails. The model has to pad in extra context lines until the match is unique. Yet more wasted tokens. &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; addresses lines directly. No ambiguity, no padding.&lt;/p&gt;
&lt;h2 id="every-edit-is-verified-against-reality"&gt;Every edit is verified against reality&lt;/h2&gt;
&lt;p&gt;The same mechanism that saves tokens is what makes edits reliable. When the agent reads a file through &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt;, every line comes back tagged with a short hash:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1:bx|import { Server } from &amp;#34;@modelcontextprotocol/sdk/server/index.js&amp;#34;;
2:dd|
3:ew|const server = new Server({ name: &amp;#34;trueline-mcp&amp;#34;, version: &amp;#34;0.1.0&amp;#34; });
checksum: 1-3:8a64a3f7
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When the agent wants to edit, it echoes those hashes back. If the file changed since the read the hashes won&amp;rsquo;t match and the edit is &lt;strong&gt;rejected before it touches disk&lt;/strong&gt;. No silent corruption, no guessing, no &amp;ldquo;why does this file look wrong?&amp;rdquo; twenty minutes later.&lt;/p&gt;
&lt;p&gt;This is the part that kills the re-read cycle. Instead of the agent discovering a stale match, failing, re-reading the whole file, and trying again, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; catches the mismatch immediately and tells the agent exactly what&amp;rsquo;s wrong. One targeted re-read of the changed range, and it&amp;rsquo;s back on track.&lt;/p&gt;
&lt;p&gt;Multiple edits to the same file go through in a single call too, each independently verified. The built-in &lt;code&gt;Edit&lt;/code&gt; handles one replacement per call, so &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; cuts tool-call overhead for multi-site changes.&lt;/p&gt;
&lt;h2 id="three-tools-zero-config"&gt;Three tools, zero config&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_read&lt;/code&gt;&lt;/strong&gt; — reads a file, tags each line with a hash, returns a range checksum.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_edit&lt;/code&gt;&lt;/strong&gt; — verifies hashes, then applies the edit atomically. Supports multiple edits per call.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_diff&lt;/code&gt;&lt;/strong&gt; — same verification, but outputs a unified diff without touching disk. Good for previewing changes before committing to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once installed, a &lt;code&gt;SessionStart&lt;/code&gt; hook nudges the agent toward the &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; tools, and a &lt;code&gt;PreToolUse&lt;/code&gt; hook blocks the built-in &lt;code&gt;Edit&lt;/code&gt; tool so it can&amp;rsquo;t fall back to string matching. You don&amp;rsquo;t have to think about it—the agent uses verified edits from the start, automatically.&lt;/p&gt;
&lt;p&gt;Security-wise, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; enforces the same deny patterns Claude Code uses (&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;*.key&lt;/code&gt;, etc.)&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/plugin marketplace add rjkaes/trueline-mcp
/plugin install trueline-mcp@trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two commands. Your next Claude Code session will use hash-verified edits automatically. No configuration, no changes to your workflow. Fewer wasted tokens and edits that don&amp;rsquo;t silently corrupt your code.&lt;/p&gt;
&lt;h2 id="prior-art"&gt;Prior art&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.can.ac/2026/02/12/the-harness-problem/"&gt;Can Boluk&lt;/a&gt; described the underlying problem (AI agents working against stale state) and &lt;a href="https://github.com/sethml/vscode-hashline-edit-tool"&gt;Seth Livingston&lt;/a&gt; built a hash-line edit tool for VS Code. &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; brings the same idea to Claude Code as an &lt;a href="https://modelcontextprotocol.io/"&gt;MCP&lt;/a&gt; plugin.&lt;/p&gt;
&lt;p&gt;The code is on GitHub: &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;rjkaes/trueline-mcp&lt;/a&gt;. Apache-2.0, TypeScript, built with &lt;a href="https://bun.sh"&gt;Bun&lt;/a&gt;.&lt;/p&gt;</description></item></channel></rss>