A field-by-field teardown of one bloated MCP connector response
This is the second post in our series on the mechanics of MCP cost. The first, why MCP connector responses cost so many tokens, covered what drives the bill. This one opens up a single response to show where the cost sits.
What does a typical connector response contain?
Take a generic example: a read of a single project-management issue, the kind of object a Jira, Confluence-style or other tracker connector returns. The schema below is illustrative and anonymised. It is not a real vendor's response, but it is shaped like the ones enterprises see in practice. The same pattern holds for a CRM record or a docs page; the field names change, the bloat does not.
Here is the object, before anything trims it:
{
"id": "ISSUE-8842a1f0-3c2e-4d9b-bb71-0f5c9a2e7d44",
"key": "PROJ-1184",
"self": "https://example.tracker/api/v3/issue/8842a1f0",
"schema_version": "2026-02",
"title": "Checkout fails on expired card retry",
"status": { "id": "10421", "name": "In Progress", "category_id": "4", "color": "#2b7" },
"assignee": {
"account_id": "u-92f3c0a1", "display_name": "A. Rivera",
"email": "a.rivera@example.com", "avatar_48": "https://...", "time_zone": "Europe/London"
},
"reporter": {
"account_id": "u-1a77bd2e", "display_name": "M. Osei",
"email": "m.osei@example.com", "avatar_48": "https://...", "time_zone": "Europe/Lisbon"
},
"description": "Retrying an expired card on checkout returns a 500 instead of a field error.",
"priority": { "id": "2", "name": "High", "icon_url": "https://..." },
"labels": ["payments", "regression"],
"created_at": "2026-05-29T08:14:22.118Z",
"updated_at": "2026-06-16T17:02:51.904Z",
"due_date": "2026-06-20",
"watchers": { "count": 7, "account_ids": ["u-...", "u-...", "u-..."] },
"permissions": { "edit": true, "delete": false, "transition": true, "admin": false },
"custom_fields": {
"story_points": 3, "team_id": "t-payments", "sprint_id": "s-2026-24",
"epic_link": "PROJ-1102", "severity_matrix": "S2/P1", "qa_owner": "u-...",
"release_train": "rt-checkout-q3", "cost_center": "cc-4417"
},
"comments": {
"total": 12,
"items": [
{ "id": "c-001", "author_id": "u-...", "created_at": "...", "body": "Repro on staging." },
{ "id": "c-002", "author_id": "u-...", "created_at": "...", "body": "Card vault returns null." }
]
},
"history": [
{ "ts": "...", "field": "status", "from": "To Do", "to": "In Progress", "by": "u-..." },
{ "ts": "...", "field": "assignee", "from": null, "to": "u-92f3c0a1", "by": "u-..." }
],
"links": {
"blocks": ["PROJ-1190"], "blocked_by": [], "relates_to": ["PROJ-1102", "PROJ-1177"]
}
}
That is one issue. The model reads every token of it the moment the connector hands it back.
Which fields does the model's answer really use?
Now suppose the query was an everyday one: "What is the status of PROJ-1184, who owns it, and when is it due?" That is a common shape of question, and the answer needs very little:
- Used by the answer:
key,title,status.name,assignee.display_name,due_date. Possiblypriority.nameanddescriptionfor context.
Everything else in the object was returned but never read by that answer:
- Returned but unused:
id,self,schema_version, the fullstatusobject minus its name, the fullassigneeandreporterobjects minus a display name (account IDs, emails, avatar URLs, time zones),labels,created_at,updated_at,watchers,permissions, the entirecustom_fieldsblock, everycommentsitem, the wholehistoryarray, andlinks.
None of those are useless in general. The audit history matters when you ask about the audit history; the permission block matters to a write call. They are unused for this query. The connector cannot know which query it is serving, so it returns the complete object every time, and the model pays to read the complete object every time.
How much of the payload is unused?
For this one example, the fields the answer used are a small share of the object and the large majority is structure and metadata the answer never touched. We are deliberately not putting a single hard percentage on that, because it would be misleading. The unused share swings with the connector, the object and the question. A history-heavy issue with a long comment thread skews far more wasteful than a fresh one. A query that does need the audit trail flips fields from the unused column into the used one.
Treat the split above as illustrative of one response, not as a measured benchmark. The number that matters is yours, measured on your own traffic, which is what the prompt at the end is for.
Two things drive the waste, and they are the same two from the first post:
- Field bloat. The query wanted five fields. It got around thirty top-level and nested ones, including a full comment thread and change history.
- Format overhead. Deeply nested JSON spends tokens on keys, brackets and quoting as well as values. The
assigneeandreporterobjects each carry five sub-fields to deliver one display name the answer uses.
What would a transit layer trim?
A reshaping layer applies field selection, projection and format to the response before it reaches the model, then passes the trimmed result through. For the query above, the same answer can come from something closer to this:
{
"key": "PROJ-1184",
"title": "Checkout fails on expired card retry",
"status": "In Progress",
"assignee": "A. Rivera",
"due_date": "2026-06-20",
"priority": "High"
}
Same answer. The model still says the issue is In Progress, owned by A. Rivera, due 20 June, and it can still mention the priority and the gist. What it no longer reads is the audit trail, the permission block, the avatar URLs, the cost-centre custom field and the rest of the object that the answer was never going to use.
The important part is what does not happen here. The full object is not stored anywhere. Stash Lite is a transit layer, not a cache. It serves your existing MCP connectors, reshapes each response as it passes through, and stores nothing. The trimmed shape exists in transit and then it is gone. The document passes through to the AI; it does not live in Stash Lite.
That distinction is what keeps the security review small. The connectors and their auth are unchanged, so the security posture stays the same as talking to the official servers. A layer that retains nothing has far less to reason about than anything that keeps a copy. What changes is the size of the payload the model reads, not who can see the data or where it rests.
Does this hold for other connectors?
Yes, with different field names. A CRM record returns lifecycle stages, enrichment fields, association IDs and activity logs around the name, owner and deal value an answer usually wants. A docs page returns block trees, formatting nodes, version metadata and permission data around the text you asked for. The connectors enterprises run in practice, Notion, Coda, Jira and Confluence (Atlassian), HubSpot, GitHub, Salesforce, and more, all return complete objects by design, and the same used-versus-unused split appears each time. You keep your existing connectors and their permissions; the reshaping happens to what comes back, in transit.
Stash Lite is in early access. You can join the waitlist on the Stash Lite homepage.
The teardown prompt
You can run this same field-by-field teardown on your own connector responses. Paste this to your AI agent in a session where your connectors are live:
Run a field-by-field teardown of one connector response.
1. Make one realistic read call I'd normally make (pull a single issue,
record, or page) and show me the full response object you received.
2. Pick a realistic question I'd ask about that object.
3. Mark every field as one of: USED BY THE ANSWER, or RETURNED BUT UNUSED
for that question. Include nested fields, not just top-level keys.
4. Show me the trimmed object that would contain only the USED fields,
in a flatter shape, and confirm the answer to my question is unchanged.
5. Give a directional sense of how much of the original object was unused
for this query. Label it as illustrative, not a measured benchmark.
Then repeat for one or two of my other common queries on the same object,
since which fields are "used" changes with the question.
That gives you a concrete picture of where the tokens go in your own workload, on your own objects. If the unused share is consistently large across your common queries, and your call volume is high, an in-transit reshaping layer is worth a look.
This is the second post in our Stash Lite series on the real mechanics of MCP cost at enterprise scale, measured carefully and hedged where it should be. Next up: how reshaping rules are written so the trimmed response still carries everything the answer needs, without breaking on the query that does want the audit trail.
FAQ
What is in a bloated MCP connector response?
A typical read object carries far more than the answer needs: internal IDs, timestamps, audit and permission blocks, nested relations, formatting metadata, and full change history, alongside the few fields the query was about. The model reads all of it on every call, even when the answer only used a title, a status and an assignee.
Which fields does the model's answer use?
Usually a small, predictable handful per query: a title or name, a status, an owner or assignee, maybe a due date and a short body. The bulk of the object, the IDs, audit trails, permission blocks and nested metadata, is returned but never read by the answer.
How much of a connector response is unused?
It varies a lot by connector and query, so treat any single figure as illustrative rather than measured. In the example we walk through, the fields the answer used are a small share of the payload and most of the rest is structure and metadata the answer never touched. Measure it on your own traffic to know your real number.
Does Stash Lite store the response to trim it?
No. Stash Lite is a transit layer, not a cache. The response is reshaped as it passes through and nothing is retained. The document passes through to the AI; it does not live in Stash Lite.
Cut your connector token bill. Stash Lite serves your Claude connectors for far less token cost — read-only, stores nothing.
Get early access →