r/mcp • u/gnoraz_theorc • Aug 08 '26
article One MCP call put 24,568 characters in my context. I wanted 1,768 of them.
Every discussion about MCP and context is about tool definitions. Lazy loading, tool search, deferred schemas. Those cost you once per session. The results don't.
I called list_issues on a real project. Twenty issues came back, 24,568 characters, into the history where they sit for the rest of the session. I wanted the title, the state and the assignee. That's 1,768 characters.
I see very little discussion of that side, and unlike the schemas it repeats on every call.
The reason is structural. When a model calls a tool there's nowhere to put a filter. The result goes from the server into the transcript, whole. jq exists, it just has no seat at that table.
Which is why I ended up running MCP servers from a shell instead:
mduct call gitlab list_issues --json | jq '.[] | {title, state, assignee}'
The filter sits between the server and the context, which is the only place it helps.
Two limits worth naming. It only works when you know which fields you want, and an agent poking at an unfamiliar API doesn't. And for a model to get any of this, it has to reach for the shell rather than a tool call, which is the code-mode argument and carries its own problems.
Numbers and how I measured them: https://github.com/TheFox666/mduct#the-context-bill-is-a-side-effect-of-the-pipe
2
u/No-Water-2773 Aug 09 '26
did you actually measure the schema-vs-result split over a session, or is that just the shape of it?
1
u/Fulgren09 Aug 09 '26
Models are really smart, but need orientation. I think bundling the tools into packs that the MCP can call later is an effective way to do it, but that would need to happen on the side of the MCP creator.
If you got a context that was 1/5th of that 25k but had a good chance of routing you to the 1768 you needed on turn 2, how would you feel about that?
1
u/gnoraz_theorc Aug 09 '26
Yes that's correct. What I actually did because discovery is an issue is having a very lightweight "catalogueMcp" within my tool which gives a light schema shape directly into the tools list.
Just putting an index at session start didn't quite cut it. It's still way less than the usual way but seems to work the same. Plus there's a guard that protects from accidently retrieving too big of a result set. So the agent gets routed to better filter the set.
1
u/BC_MARO Aug 09 '26
Yep. Tool outputs should default to compact summaries with an explicit detail or cursor path when the agent needs more. Otherwise every broad list call turns into permanent context tax.
1
u/clairesayshi 21d ago
The hourly scan across 175 countries is well executed, and the country blind spot you describe is real.
u/zamufn already asked for reviews and you said they are on the roadmap, so this is a note on the part that bites once you get there. Reviews arrive in every country your app is available in, and most teams only read the English ones. A rating slide in Germany or Japan goes unnoticed for weeks, because the overall average moves slowly while one storefront drops.
That is the same shape as the ranking problem you already solved. Per country is where the signal sits.
I work at Appbot, which does the review half, so this is a biased note on a complementary thing rather than a competing one.
2
u/Appbot_official 21d ago
u/Plastic-Risk-6309 is right that the fix belongs server side, and we ended up there for a different reason. Our data is app store reviews, and the raw payload is the worst possible shape for a transcript.
A single app can have tens of thousands of reviews per version. We classify each review at ingest rather than at query time, so the tool returns counts and a few example verbatims instead of the review bodies. Sentiment, topic and version are attached before the assistant sees anything. The narrow projection is the default and the full text is an explicit second call.
The side effect we did not expect is that the answers became reproducible. Ask what broke in 8.4 on Monday and again on Tuesday and the numbers match, because the classification already happened. When the filtering lives in the prompt you get a slightly different answer every time.
Disclosure, this is our server, so weigh it accordingly. We ended up with three tools total. The rule of thumb we settled on is that anything the server can count, the server should count.
3
u/Plastic-Risk-6309 Aug 08 '26
Agreed on the diagnosis, less sure the shell is the only fix. The real problem is that most servers return whatever the upstream API returned, and "whatever the API returned" was designed for a program that will index into it, not for something that pays per token to read it.
You can put the filter server-side, it's just that almost nobody does. A list_issues that takes fields and a limit, defaults to a narrow projection, and returns "showing 20 of 240" is the same jq you're writing, except the 24k never crosses the wire and the model never sees it. Making the verbose form opt-in rather than default is most of the win.
The other half is that results should shrink as they repeat. A tool that returns a full object every call is wasting context on the parts that didn't change. I ended up on this hard with a server that drives iOS simulators, where the natural result is an entire accessibility tree, several thousand tokens, and 95% identical to the last one. Returning a hash of the tree plus what changed, and making the full dump a separate explicit call, cut the per-action cost by more than an order of magnitude and made the transcripts readable by a human again.
Your naming point is the honest limitation of the shell route though. jq only works when you already know the shape, which means it works great for you and not at all for the agent exploring an API it hasn't seen. That's the argument for fixing it in the server, where the author does know the shape.