<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vivek Chimman</title>
    <description>The latest articles on DEV Community by Vivek Chimman (@vivek_chimman_26).</description>
    <link>https://dev.to/vivek_chimman_26</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4031932%2F995e4973-c3c5-47dd-a1a6-9fde18728613.png</url>
      <title>DEV Community: Vivek Chimman</title>
      <link>https://dev.to/vivek_chimman_26</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vivek_chimman_26"/>
    <language>en</language>
    <item>
      <title>I built an MCP server to clean prompts — then learned MCP can't save your input tokens</title>
      <dc:creator>Vivek Chimman</dc:creator>
      <pubDate>Fri, 17 Jul 2026 06:34:09 +0000</pubDate>
      <link>https://dev.to/vivek_chimman_26/i-built-an-mcp-server-to-clean-prompts-then-learned-mcp-cant-save-your-input-tokens-3lca</link>
      <guid>https://dev.to/vivek_chimman_26/i-built-an-mcp-server-to-clean-prompts-then-learned-mcp-cant-save-your-input-tokens-3lca</guid>
      <description>&lt;p&gt;I run a small tool that strips filler from LLM prompts — hedging, redundancy, pleasantries — while keeping every actual requirement. Paste a rambly 181-token prompt, get back the same request at 73 tokens. Same output from the model, 60% fewer input tokens.&lt;/p&gt;

&lt;p&gt;The obvious next step was: put this inside the coding agents. I use Claude Code daily; MCP is right there. Expose a &lt;code&gt;clean_prompt&lt;/code&gt; tool, let the agent clean prompts automatically, save tokens on every turn.&lt;/p&gt;

&lt;p&gt;I built it. It works. And then I traced a session transcript and realized it cannot do the one thing I built it for. This post is the three wrong assumptions I burned a week on, so you don't have to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrong assumption #1: an MCP tool can clean MY prompt
&lt;/h2&gt;

&lt;p&gt;Here's the sequence when you type a messy prompt into an agent that has a cleaning MCP tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your raw prompt enters the conversation context. &lt;strong&gt;The input meter has already run.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The model reads it, decides to call &lt;code&gt;clean_prompt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The tool returns the cleaned version — which is &lt;strong&gt;appended&lt;/strong&gt; to the context.&lt;/li&gt;
&lt;li&gt;The model proceeds with raw + cleaned + the tool-call overhead + the tool schema in the system prompt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Net effect: you paid for the raw prompt, then paid again for the cleaned copy, plus overhead. An MCP tool runs &lt;em&gt;inside&lt;/em&gt; the agent loop, &lt;em&gt;after&lt;/em&gt; your text arrives. It is structurally incapable of reducing what you pay for your own input.&lt;/p&gt;

&lt;p&gt;Where MCP cleaning genuinely pays: prompts the agent sends &lt;em&gt;downstream&lt;/em&gt; — RAG queries, sub-agent instructions, pipeline calls. Those calls never see the raw version, so the savings are real there. That's a legitimate use case; it just isn't the "clean my typing" use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrong assumption #2: hooks can rewrite the prompt
&lt;/h2&gt;

&lt;p&gt;Fine — intercept the prompt &lt;em&gt;before&lt;/em&gt; the model sees it. Claude Code has hooks; there's one called &lt;code&gt;UserPromptSubmit&lt;/code&gt; that fires on exactly the right event.&lt;/p&gt;

&lt;p&gt;It can do two things: &lt;strong&gt;add context&lt;/strong&gt; or &lt;strong&gt;block the prompt&lt;/strong&gt;. It cannot replace the text. I re-checked Codex's hooks framework too — same story, add-context or block only. No agent I tested exposes a "mutate the user's prompt before the model sees it" hook. (If you know one that does, genuinely, tell me in the comments.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrong assumption #3: slash-command bash injection replaces the prompt
&lt;/h2&gt;

&lt;p&gt;Claude Code slash commands support &lt;code&gt;!`command`&lt;/code&gt; injection — the bash runs &lt;em&gt;before&lt;/em&gt; the model sees the command body, and its output replaces it. So &lt;code&gt;/clean &amp;lt;messy text&amp;gt;&lt;/code&gt; → bash pipes the text through the cleaning API → the model receives only the cleaned version. I shipped this and it worked — the model's turn visibly ran on the cleaned text.&lt;/p&gt;

&lt;p&gt;Then I opened the session's JSONL transcript. The raw text was still there, recorded as &lt;code&gt;&amp;lt;command-args&amp;gt;&lt;/code&gt;. And when the command resolved as a skill, the raw text appeared &lt;strong&gt;about four times&lt;/strong&gt; — command-args, tool args, skill-load note, bash output. The context cost went up, not down.&lt;/p&gt;

&lt;p&gt;One more trap from that transcript session, as a bonus: my script failed open (missing API key → passes the original text through, by design), and the model then &lt;em&gt;paraphrased&lt;/em&gt; my raw prompt into a plausible-looking "Cleaned prompt: …" on its own. It looked identical to a real clean. The only way to tell was record-level transcript forensics. If you build anything that fails open inside an agent loop, make the failure loudly visible — the agent will helpfully paper over it otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually works: replace the text before you hit send
&lt;/h2&gt;

&lt;p&gt;The token meter starts when your text enters the context. So the only place cleaning can save input tokens is &lt;strong&gt;in the text box, before send&lt;/strong&gt;. Agent platforms give you no API for that moment — so I went around them with OS-level text replacement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A global hotkey&lt;/strong&gt; (Windows for now — Win32 &lt;code&gt;RegisterHotKey&lt;/code&gt;): type the messy prompt into any chat box — Claude Code, Codex, a web chat — press Ctrl+Shift+K, the box's content is selected, sent to the cleaning API, and replaced in place. You review the cleaned text and hit send. The raw version never enters any context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0im7jz6ngajl7o00vvr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0im7jz6ngajl7o00vvr5.png" alt=" " width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0rkchtsjrxlj619swq9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0rkchtsjrxlj619swq9c.png" alt=" " width="799" height="394"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxwdp8fopcrn6h2bebwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxwdp8fopcrn6h2bebwu.png" alt=" " width="799" height="425"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkm8bhm97gj9d3ji3zbf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkm8bhm97gj9d3ji3zbf3.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Measured on my own usage with the default cleaner: 181 → 73 tokens (60%) on a hedge-heavy landing-page prompt, 233 → 157 (33%) on a dense product spec — filler-heavy prompts compress hardest. Swapping the cleaner model (Ctrl+Shift+L → Llama 3.3 70B) took that same spec to 106 tokens (55%). Nothing dropped — the cleaner keeps every requirement, constraint, and conditional; it only removes what the model ignores anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest architecture summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Saves your input tokens?&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP tool&lt;/td&gt;
&lt;td&gt;❌ (adds tokens)&lt;/td&gt;
&lt;td&gt;Runs after raw text is in context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hooks&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Add-context / block only, no mutation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slash command + bash injection&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Raw persists in command-args; ~4× as a skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLI pipe&lt;/td&gt;
&lt;td&gt;✅ one-shots only&lt;/td&gt;
&lt;td&gt;Cleans before the process starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In-place hotkey before send&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Raw never enters any context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP for downstream calls&lt;/td&gt;
&lt;td&gt;✅ for those calls&lt;/td&gt;
&lt;td&gt;Sub-calls never see the raw&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you take one thing from this: &lt;strong&gt;know where the meter starts.&lt;/strong&gt; A lot of "token optimization" tooling operates after that point and quietly makes things worse.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This ships as &lt;a href="https://aitokencleaner.com/developers?utm_source=devto&amp;amp;utm_campaign=devlaunch" rel="noopener noreferrer"&gt;AI Token Cleaner&lt;/a&gt; — REST API + MCP server + the hotkey. Free tier is 100 API cleans/day, no card. The playground needs no signup at all if you just want to see what it cuts. Happy to answer anything in the comments — especially if your agent setup has a pre-send mutation point I missed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>mcp</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
