flatten-mcp
Reduce Claude Code session token usage by moving bulky tool results into a local backup, keeping history intact and reversible.
flatten_session: Move large tool results (text, base64 images/screenshots) from a Claude Code session JSONL file into a backup, replacing them with compact[FLATTENED ...]markers — dramatically reducing context tokens while preserving every prompt and event verbatim. Supports dry-run previews, minimum size thresholds, and targeting sessions by UUID, "last", or "current". Crash-safe and reversible.retrieve_flattened: Fetch the original content of any flattened tool result from the backup using its ID and session ID — returns original text or re-renders flattened images.unflatten_session: Fully reverse a flatten operation by re-inlining all backed-up content into the session JSONL, restoring it to its exact pre-flatten state, then deleting the backup.flatten_messages(in-memory): Swap bulkytool_resultblocks in an Anthropic Messages APImessages[]array for compact markers, returning the originals in anextractedarray. Purely functional — no disk or network access. The caller is responsible for persisting the extracted data.unflatten_messages(in-memory): Restore a previously flattenedmessages[]array by re-inlining content from the caller-suppliedextractedarray, byte-for-byte. Unknown markers are left as-is.
flatten-mcp
The same Claude Code session, resumed for a fraction of the tokens — nothing summarized, nothing lost. A long session carries its entire history on every message, and deep in, most of that is no longer conversation: it is files Claude already read and boiled down to a line or two, still riding along in context. flatten-mcp does what the name says — the digested bulk moves to a local backup, a small marker stays behind, and every prompt, reply, and decision survives word for word, any block one call from coming back. Claude gets cheaper and sharper.
What is all that weight? The 2 MB log that became one line, the screenshot Claude
described, the five files it summarized — raw source that did its job and turned into a
sentence. flatten-mcp moves each tool result above a size threshold into a local backup next
to the session and leaves a small [FLATTENED …] marker in its place; any block is one call
from coming back.
| Auto tool-result clearing | flatten-mcp | |
What happens | history rewritten into a summary | old tool results cleared as the limit nears | bulk moved to a local backup, markers remain |
Speed & cost | slow — a full model pass over your history, spends tokens/budget | automatic, no token cost | instant, zero tokens — a local file rewrite |
Lossy? | yes — an interpretation | cleared content is gone from context | no — byte-identical restore any time |
You choose when? | you or the auto-cliff | automatic | yes |
Session file on disk | rewritten | unchanged | shrinks; the backup keeps every original |
Try it first — nothing installed, nothing written:
npx -y flatten-mcp-session flatten --dry-runRun it from a project you use Claude Code in — any terminal, or straight from inside a
session with the ! prefix: it prints what a flatten would save on your most recent
session and writes nothing.
The report doesn't just total the savings — it shows exactly where the weight sits:
context tokens : 168707 saved of 444927 (37.9%) exact
breakdown : (exact tokens)
claude-in-chrome (MCP) 126x 8.9 MB 94,342 tok
Read 55x 1.6 MB 64,028 tok
Bash 23x 40.9 KB 7,301 tok
…Add --breakdown deep and every row opens into its individual blocks — each command,
file, and screenshot that built the bulk, largest first.
Quick start
Runs through npx — no global install, nothing added to your project. Every read/write
stays inside the agent's own session store — Claude Code's ~/.claude/projects/ by
default, Codex's ~/.codex/sessions when you target it — and there are zero network
calls by default. (Node ≥ 18, which Claude Code already runs on.)
1. Install — either path:
# Terminal: register the server user-wide (pinned; use @latest if you prefer auto-updates)
claude mcp add flatten -s user -- npx -y flatten-mcp@2.6.0
# Optional: the /flatten slash command
curl -fsSL https://raw.githubusercontent.com/shayaShav/flatten-mcp/main/commands/flatten.md -o ~/.claude/commands/flatten.md# Or as a Claude Code plugin — registers the server AND bundles /flatten in one step
claude plugin marketplace add shayaShav/flatten-mcp
claude plugin install flatten-mcp@flatten-mcp2. Restart Claude Code (or open a new session) — an already-open session does not pick
up a newly added server. Check with /mcp: flatten should be listed as connected.
3. Use it — two steps, always:
/flatten → the session file is rewritten in place, right after a complete backup is written
/resume → switch to another session and back; the reloaded copy is the lighter oneUntil you /resume, the window you are in still holds the full pre-flatten copy in memory —
nothing will look different. After it, watch the context indicator drop.
In ~/.claude.json or your project's .mcp.json:
{
"mcpServers": {
"flatten": { "command": "npx", "args": ["-y", "flatten-mcp@2.6.0"] }
}
}For development: git clone https://github.com/shayaShav/flatten-mcp.git && cd flatten-mcp && npm install, then point the config at node /absolute/path/to/dist/index.js.
Related MCP server: Claude Code MCP Server
Usage
Bare
/flatten(or asking "flatten this session") targets the current session — the server identifies it fromCLAUDE_CODE_SESSION_ID. Pass a UUID to target another session.Preview first with a dry run — "dry-run flatten this session" — nothing is written.
See what's in there: every dry run includes the breakdown; pass
breakdown: trueon a real flatten (CLI:--breakdown) to get it there too, orbreakdown: "deep"(CLI:--breakdown deep) to list every block — each command and file with its own size and tokens, largest first.Undo completely by asking to unflatten: every block returns to its exact original value.
Don't flatten a session that is mid-generation; flatten between turns, or from a second window — which also keeps the tool schemas out of your working session entirely.
Working in Codex CLI instead? The same tools take
agent: "codex"— see OpenAI Codex CLI, too.
Flattening is pure file surgery — no model intelligence involved — so a fast, inexpensive
model (/model haiku) flattens just as well as a frontier one. Or skip the model turn
entirely: ! npx -y flatten-mcp-session flatten runs the CLI from inside the session —
zero tokens, no model pass over your still-heavy history.
What you'll actually save
The reduction is the bulk you remove, not a fixed percentage:
Read-heavy sessions (large files, long logs, screenshots): the demo above measured 340,071 → 132,800 tokens, a 61% cut. The more ingested bulk, the bigger the cut — base64-screenshot-heavy sessions can go higher.
Prose-heavy sessions (little external data): savings are small — there's not much bulk to move.
A common point to reach for it is around 200k tokens; the most dramatic cuts show up at 250k–400k. It's repeatable — a re-flatten only touches bulk that arrived since the last one. The three tool schemas cost ~1,200 tokens per turn while the server is connected; one flatten of a read-heavy session removes orders of magnitude more from every later turn (207k in the demo), and the separate-window pattern above makes even that overhead zero.
Where the saving lands: a session re-sends its history on every message, so removed bulk stops costing you on every later turn — prompt caching softens that (cache reads bill at roughly a tenth of the input price), but a cold cache re-warms the full context at a premium, and on subscription plans the same tokens draw down your usage limits. Just as important, a leaner window keeps the context ceiling — and lossy auto-compaction — further away.
OpenAI Codex CLI, too
The same engine, the same guarantees, for Codex sessions. Install flatten-mcp as a Codex
plugin — it bundles the server plus a flatten-codex skill that keeps every call on the
Codex store — or skip installing and drive the terminal CLI:
# Codex plugin
codex plugin marketplace add https://github.com/shayaShav/flatten-mcp
# then /plugins → install flatten-mcp
# Or zero-install: the CLI reaches Codex rollouts directly
npx -y flatten-mcp-session flatten --agent codex
codex resume <session-id> # the resumed rollout is the lighter copyMeasured live on real sessions: resuming a flattened rollout sent 39–51% fewer input
tokens by Codex's own counter (27,029 → 13,139 on the largest run). Codex rebuilds
resume context from the rollout file, so what leaves the file leaves the model's context —
and restore stays byte-identical, proven on every candidate-bearing rollout of a 728-file
corpus (209/209). A resumed Codex session has no MCP retrieve tool, so each marker's tail
carries the exact command that fetches its block back
(flatten-mcp-session retrieve <session> <id> --agent codex); the backup sits next to the
rollout, invisible to codex resume.
Two honest notes. Codex token savings are local estimates — Anthropic's count_tokens
does not measure GPT-5's tokenizer, so the context total comes from Codex's own usage
events. And the size of the win depends on how much output Codex persisted: it sometimes
stores only a preview of large command output. Claude Code stays the first-class path;
Codex rides the SessionAdapter seam more agents can follow (see
Compatibility & roadmap).
Tools
Tool | What it does |
| Move bulky tool results into the backup, leaving |
| Fetch one original block back by id — text, or a flattened screenshot re-rendered as a real image. Takes |
| Reverse everything: re-inline every block from the backup, then delete the backup. Takes |
In a flattened session the model sees markers like this, carrying everything needed to fetch the original:
[FLATTENED id=toolu_01AbC… tool=Read file_path=/src/server.ts | text 48213B/612L | session=2f9c… | retrieve_flattened(id,session) for raw content]How it works
One backup, not deletion.
<session>.jsonl.bakholds the complete session fully inlined; the live file carries markers. Kept in lockstep every run (backup = unflatten(live),live = flatten(backup)).Crash-safe. Originals are written to the backup before bulk leaves the session, each write via atomic temp-file-and-rename — an interrupted run can't leave a half-written session.
Self-cleaning. A full unflatten restores everything inline and deletes the backup — zero artifacts left.
Re-flatten friendly. As the session grows, run it again; only new bulk is touched, and content added after a flatten is never lost on restore.
Lossless. Text and base64 images are stored exactly as they appeared —
unflatten_sessionrestores byte-identical values.Honest numbers. Claude Code stores each tool result twice on disk but sends one to the model; reports separate
diskBytesSavedfromcontextTokensSaved(the number that matters), estimated locally — or exact viacount_tokenswhen you opt in withFLATTEN_COUNT_EXACT=1(plusANTHROPIC_API_KEY). The breakdown's per-group counts ride the same opt-in; per-block figures in deep mode stay estimates.
Details — session JSONL format, backup model, marker protocol — in docs/ARCHITECTURE.md.
Validate the claims yourself: (1) pick a meaty session; (2) ask for a dry run and read
the report; (3) /flatten for real, /resume, and watch the context indicator drop by the
reported amount; (4) unflatten and confirm the session file returns byte-identical (diff
against a copy if you kept one).
Security & verification
Provenance you can check. Every release is published from CI via npm trusted publishing (OIDC) with provenance attestations, from a signed tag — no npm token exists anywhere. Verify:
npm audit signatures. Pin an exact version (as the Quick start does) and the committedpackage-lock.jsondocuments the tree we test against;npxresolves the two direct dependencies' own trees at install time — audit withnpm ls --omit=dev.File access. Confined to the session stores:
<CLAUDE_CONFIG_DIR or ~/.claude>/projects/<encoded-project-dir>/and, underagent: "codex",<CODEX_HOME or ~/.codex>/sessions/— rewriting session files there is the tool's entire job, always backup-first and atomic. The one exception:flatten-mcp-session retrieve --outwrites a retrieved image where you tell it to.Network. Zero outbound calls unless you explicitly opt in to exact token counts. With both
FLATTEN_COUNT_EXACT=1andANTHROPIC_API_KEYset — key presence alone is not enough — exactly one endpoint is ever contacted:POST api.anthropic.com/v1/messages/count_tokens(free). The request body contains the counting model id (FLATTEN_COUNT_MODEL) and a single user message holding the tool results being flattened, reduced to their text and image blocks; a second identical call counts the replacement markers, and — when the breakdown is requested — one more of the same shape per report row. Sent only to Anthropic; the key is read from the environment and never stored or logged. There is no other outbound URL in the codebase. The optionalflatten-mcp-httpbin (below) accepts inbound connections when you run it — localhost by default — and makes no outbound calls.Small enough to audit in one sitting. A few small TypeScript files, two direct dependencies, no telemetry, no shell, no hooks — no analytics, no spawned processes, no permission bypasses. Vulnerability reports: SECURITY.md.
Beyond Claude Code — CLI & library
The same engine ships as a terminal CLI, an in-memory library, and a Streamable HTTP server, so raw Messages API callers (any language) get the identical flatten/unflatten semantics with no MCP and no session files.
npx -y flatten-mcp-session flatten # most-recent session in this project
npx -y flatten-mcp-session flatten <session> --dry-run
npx -y flatten-mcp-session flatten last --dry-run --breakdown deep # per-block x-ray
npx -y flatten-mcp-session list
npx -y flatten-mcp-session unflatten <session>
npx -y flatten-mcp-session retrieve <session> <tool_use_id> --out shot.png
# Target OpenAI Codex CLI rollouts instead of Claude Code sessions:
npx -y flatten-mcp-session flatten --agent codex
npx -y flatten-mcp-session list --agent codex
npx -y flatten-mcp-session retrieve <uuid> <call_id> --agent codex<session>: UUID,last,"last N",current, or a keyword — same grammar as the MCP tool. Shared flags:--agent <claude|codex>(defaultclaude),--project-dir,--claude-dir,--codex-home,--json.--agent codextargets~/.codex/sessions(override with--codex-homeor$CODEX_HOME). A UUID reaches any rollout in the tree;last/"last N"/keyword are scoped to rollouts whose cwd equals the project dir, andcurrentfalls back tolast(Codex has no live-session linkage). Codex token savings are reported as local estimates only — the context total comes from Codex's own usage events. The backup sits next to the rollout as<rollout>.jsonl.bak, invisible tocodex resume.Drives the exact same on-disk engine as the MCP server — ideal for cron and scripts. After a real flatten,
/resumethe session in Claude Code (orcodex resumethe rollout) to load the lighter copy.
echo '[{"role":"user","content":"hi"}]' | npx -y flatten-mcp-cli --flatten
npx -y flatten-mcp-cli --flatten --min-size 2000 < body.json > flattened.json
npx -y flatten-mcp-cli --unflatten < flattened.json > restored.json--flattenprints{ messages, extracted, flattenedCount, contextTokensSaved, … }— persistextractedyourself; you are the store.--unflattenrestores byte-for-byte. No server, no disk, no network. Bad input → stderr + exit 1.
import { flattenMessages, unflattenMessages } from 'flatten-mcp';
const { messages, extracted, contextTokensSaved } = flattenMessages(myMessages);
// send `messages` to the API; persist `extracted` yourself — you are the store.
const original = unflattenMessages(messages, extracted); // byte-for-byte restoreSynchronous, never mutates input (deep-copies first).
flattenRequestBody/unflattenRequestBodyhandle a full{ system, messages, tools, … }body.Exact token counts (optional, async):
flattenMessagesExactuses Anthropic's freecount_tokenswhenANTHROPIC_API_KEYis set — calling the*Exactvariant is the opt-in here (countExact: falseforces the estimate); theFLATTEN_COUNT_EXACTvariable gates only the MCP server and session CLI.Prompt-caching caveat: flattening earlier messages changes the cached prefix and invalidates
cache_controlbreakpoints from that point on — flatten before establishing a breakpoint, or the cache re-write can cost more than the flatten saves in short-lived conversations.
npx -y flatten-mcp-http # POST http://127.0.0.1:8787/mcp
npx -y flatten-mcp-http --port 3000 --host 0.0.0.0Serves
flatten_messages/unflatten_messages— the same stateless in-memory engine as the library, callable from any MCP client or hosted registry inspector. Persist the returnedextractedyourself and feed it back to restore, exactly like the library.The three disk tools are not exposed over HTTP: they operate on the local Claude Code session store, which does not exist wherever a remote client calls from. (On the stdio server,
FLATTEN_INMEMORY_TOOLS=1adds these two tools alongside the disk ones.)No auth, permissive CORS, no outbound network calls — the tools are pure functions over the request's JSON. Binds
127.0.0.1by default; put your own proxy/auth in front before exposing it further. Note the transport cost: the conversation you flatten travels to this server and back — inside your own process, prefer the library.
A public flatten-mcp-http instance runs at https://shaya.cloud/flatten-mcp
(Streamable HTTP, no credentials). Same contract as the library: it serves
flatten_messages / unflatten_messages only — persist the returned extracted
yourself — and the disk tools still need the local install above. Mind the transport:
your conversation travels to this server and back, so send only what you would route
through a third-party service.
# Claude Code
claude mcp add --transport http flatten-remote https://shaya.cloud/flatten-mcpClaude (claude.ai / Desktop): Settings → Connectors → Add custom connector → paste the URL.
Cursor: Add to Cursor, or
"flatten": { "url": "https://shaya.cloud/flatten-mcp" }inmcp.json.VS Code:
"flatten": { "type": "http", "url": "https://shaya.cloud/flatten-mcp" }inmcp.json.Liveness:
curl https://shaya.cloud/flatten-mcp/health
FAQ
Won't Anthropic just build this in? Claude Code already clears old tool results
automatically near the limit (see the table up top). Flatten is a different contract:
you pick the moment, the restore is byte-identical, and the on-disk session you
/resume from actually shrinks.
Will the model fetch a flattened block, or hallucinate around it? Each marker carries
the id and session, and in practice the model calls retrieve_flattened when it needs raw
bytes back. Deterministic recovery is always there regardless: unflatten_session
re-inlines everything.
Does it need Node in my project? No — it runs through npx ephemerally and touches
only your agent's session files, not your project or toolchain.
Can a team use it? It's per-developer (each dev's local session store). Standardize by
committing the mcpServers block to your project's .mcp.json, or point the team at the
plugin install.
Compatibility & roadmap
Claude Code and OpenAI Codex CLI session stores — selected per call with
--agent <claude|codex>(CLI) or theagentparameter (MCP), defaultclaude. The disk engine runs behind aSessionAdapterseam, so each agent's store is a self-contained adapter over the shared block logic; more agents can follow the same seam — contributions welcome (CONTRIBUTING.md). WSL2 counts as Linux: if your agent runs inside WSL2, flatten-mcp runs in the same environment and targets those sessions normally. Native Windows is untested.
Configuration
Operates on the project the CLI runs in; pass project_dir on any call to target another.
Env var | Required | Purpose |
| no | Claude config dir whose |
| no | Codex home whose |
| no | Set to |
| no | The key for the exact count. Ignored by the MCP server and session CLI unless |
| no | Model id for the exact count (default |
| no | Set to |
Uninstall
Unflatten anything you want back inline first — a flattened session needs its
<session>.jsonl.bak for retrieve_flattened/unflatten_session, and uninstalling does
not remove backups. Then:
claude mcp remove flatten -s user && rm -f ~/.claude/commands/flatten.md # terminal install
claude plugin uninstall flatten-mcp # plugin installTo reclaim disk for sessions you'll never restore, delete their .jsonl.bak files from
~/.claude/projects/<encoded-project-dir>/ (Claude Code) or from next to the rollouts
under ~/.codex/sessions/ (Codex).
Contributing
Issues and PRs welcome — dev setup, project map, and workflow in CONTRIBUTING.md; security reports via SECURITY.md.
License
MIT © Shaya Shaviv
Available Tools
5 toolsflatten_messagesFlatten messages[] (in memory)ARead-onlyIdempotent
Flatten a raw Anthropic Messages API messages[] array in memory: every bulky tool_result block (large text or base64 image) larger than min_size bytes is swapped for a compact [FLATTENED id=...] marker, and the originals are returned in "extracted". Persist "extracted" yourself — you are the store — and feed it back to unflatten_messages to restore the conversation byte-for-byte. Purely functional: no session file, no disk, no network; the input is never mutated. This is the same engine as the flatten-mcp library export; for production use inside your own process, prefer importing the library so the conversation does not travel over a transport.
| Name | Required | Description | Default |
|---|---|---|---|
| messages | Yes | The raw Messages API messages[] array ({ role, content } objects, verbatim). | |
| min_size | No | Only flatten tool_result blocks larger than N serialized bytes. |
Output Schema
| Name | Required | Description |
|---|---|---|
| messages | Yes | The flattened messages[] array — safe to send — with every bulky tool_result replaced by a compact [FLATTENED id=...] marker. Deep-copied; the input is never mutated. |
| extracted | Yes | The originals removed from the conversation. Persist this array yourself and pass it back to unflatten_messages to restore byte-for-byte. |
| flattenedCount | Yes | How many tool_result blocks were flattened. |
| contextTokensExact | Yes | Always false here — the in-memory tool never makes a network call; use the library flattenMessagesExact for an exact count. |
| contextTokensSaved | Yes | Estimated context tokens removed from the conversation. |
| imageBlocksFlattened | Yes | How many image blocks were among the flattened results. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint, idempotentHint), the description adds that it is purely functional with no session file, disk, or network, and the input is never mutated. This enriches behavioral understanding.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the action and each sentence adds value. While somewhat long, it is well-structured and informative without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema exists, the description appropriately focuses on usage and behavior. It covers the functional nature, persistence requirement, and alternative, making it complete for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds meaning: it explains min_size is for blocks larger than N bytes, and that messages should be a raw Messages API array. This adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it flattens a raw Anthropic Messages API messages[] array in memory, swapping bulky tool_result blocks with markers and returning originals in 'extracted'. It uses a specific verb and resource, and distinguishes from siblings like unflatten_messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells the agent to persist 'extracted' itself and feed it back to unflatten_messages for restoration. It also advises using the library directly for production, providing clear context on when to use this tool vs alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flatten_sessionFlatten Claude Code or Codex sessionA
Flatten a Claude Code or OpenAI Codex CLI session: move bulky tool results (large text output and, for Claude, base64 image/screenshot blocks) out of the session JSONL into a backup copy, leaving a compact [FLATTENED ...] marker. The conversation reads identically — every prompt and event stays verbatim — but resumes with far fewer context tokens. Crash-safe (atomic rewrite + a single backup holding the complete session) and reversible via unflatten_session. Choose the store with agent ("claude" default, or "codex"). Reports diskBytesSaved and contextTokensSaved out of contextTokensTotal. For claude these are estimated locally, or exact when FLATTEN_COUNT_EXACT=1 and ANTHROPIC_API_KEY are both set; for codex the token savings are ALWAYS a local estimate (Anthropic count_tokens does not measure the GPT-5 tokenizer) and contextTokensTotal comes from Codex's own token_count events. With no session_id, flattens the current live session (claude); under codex "current" falls back to "last" (Codex has no live-session linkage). Also accepts a UUID, "last", "last N", or "current"; under codex a UUID reaches any rollout in the tree, while "last"/"last N"/keyword are scoped to the project dir. After flattening, /resume the session (claude) or codex resume the rollout (codex) to load the lighter copy.
| Name | Required | Description | Default |
|---|---|---|---|
| agent | No | Which agent's session store to target: "claude" (default) or "codex". | claude |
| dry_run | No | Report what would be flattened without modifying files | |
| min_size | No | Only flatten tool results larger than N bytes | |
| breakdown | No | Include the per-tool/resource breakdown of what was flattened. false, true, or "summary" = the aggregated adaptive rows plus byKind/bySlot groupings; "deep" ALSO lists every individual block under its row (tool + arg summary + bytes + per-block token estimate), groups sorted by context tokens then blocks by bytes. Dry runs always include at least the summary; set true/"summary"/"deep" to also get it on a real flatten. | |
| sessionId | No | camelCase alias for session_id (accepted so a camelCase call does not fail validation). | |
| claude_dir | No | Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude. Applies to agent "claude" only. | |
| codex_home | No | Absolute path (or ~/...) to the Codex home whose sessions to target — the dir holding sessions/. Default: $CODEX_HOME if set, else ~/.codex. Applies to agent "codex" only. | |
| session_id | No | Session UUID, "last", "last N", or "current". Omit to flatten the current live session (claude); under codex "current" falls back to "last". | |
| project_dir | No | Absolute path to project. Default: the project the CLI runs in (cwd). Under codex, scopes "last"/"last N"/keyword to rollouts whose cwd equals this dir. | |
| include_tool_use_result | No | Also flatten the top-level toolUseResult mirror Claude Code keeps per result line (roughly doubles disk savings; lossless & restorable). Set false to only touch message.content. |
Output Schema
| Name | Required | Description |
|---|---|---|
| sessions | Yes | One entry per session flattened (a single entry for one session_id, or several for "last N"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses crash-safe atomic rewrite, reversible nature, estimation vs exact token savings for each agent, and behavior with 'current' under codex. No contradiction with annotations (readOnlyHint=false, destructiveHint=false). Adds extensive behavioral context beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with core purpose; but the description is long and includes many details that could be condensed. However, given the tool's complexity, the length is justified and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all aspects: agent differences, token calculation, session ID handling, directory paths, output fields mentioned. Comprehensive for a 10-parameter tool with output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% description coverage, so baseline is 3. The description adds moderate extra context, e.g., explaining dry_run reports without modifying, breakdown options in detail, and behavior of session_id. But the schema descriptions are already good, so only slight improvement.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the tool flattens Claude Code or Codex CLI sessions by moving bulky tool results to a backup copy and leaving compact markers. It distinguishes from siblings like unflatten_session and flatten_messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance on when to use (to reduce context tokens), how to choose agent, fallback behaviors for different session_id values, and mentions reversible via unflatten_session. Clearly states alternatives and context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retrieve_flattenedRetrieve flattened contentARead-onlyIdempotent
Retrieve original tool result content from a flattened session, read straight from its backup. When you see [FLATTENED id=XXX tool=Read ... | text NNNB/NNL | session=YYY | ...] in the conversation, call this with the value after "id=" as tool_use_id and the value after "session=" as session_id, and set agent to match the session ("claude" default, or "codex"). Returns the original text output, or — for flattened screenshots (claude) — the actual image so you can view it again.
| Name | Required | Description | Default |
|---|---|---|---|
| agent | No | Which agent's session store the flattened session lives in: "claude" (default) or "codex". | claude |
| claude_dir | No | Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/, e.g. ~/.claude-2 for a second profile. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude. Applies to agent "claude" only. | |
| codex_home | No | Absolute path (or ~/...) to the Codex home whose sessions to target — the dir holding sessions/. Default: $CODEX_HOME if set, else ~/.codex. Applies to agent "codex" only. | |
| session_id | Yes | Value after "session=" in the [FLATTENED ... session=YYY ...] marker | |
| project_dir | No | Absolute path to project. Default: the project the CLI runs in (cwd). Ignored under codex (rollouts are located by UUID globally). | |
| tool_use_id | Yes | Value after "id=" in the [FLATTENED id=XXX ...] marker |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | "text", "image", or "mixed". |
| slot | Yes | "content"/"toolUseResult" (claude) or "output" (codex). |
| tool_name | Yes | Originating tool name of the retrieved result. |
| line_count | Yes | Line count of the original text projection. |
| tool_use_id | Yes | The tool_use_id that was retrieved. |
| original_size | Yes | Byte size of the original content. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint. The description adds valuable context: it reads 'straight from its backup', returns original text output, and for flattened screenshots (claude) returns the actual image for viewing. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is efficient and front-loaded, starting with the core purpose then immediately giving usage instructions. Every sentence adds value—no filler. It's appropriately sized for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 6 parameters (2 required), a complex trigger pattern, and an output schema, the description covers all necessary aspects: trigger identification, parameter extraction, agent selection, default paths, and return types. The output schema exists and the description hints at what is returned (text or image), making it complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for all 6 parameters. The description adds extra meaning beyond the schema by explaining how to derive parameters from the FLATTENED marker (e.g., 'value after id=') and providing context for agent and directory defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves original tool result content from a flattened session, with a specific verb ('Retrieve') and resource ('original tool result content from a flattened session'). It distinguishes from sibling tools like flatten_session by explaining the use case of reading previously flattened content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to use the tool: when a [FLATTENED ...] marker appears in the conversation. It provides step-by-step instructions on extracting tool_use_id and session_id from the marker, setting the agent, and default values.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unflatten_messagesUnflatten messages[] (in memory)ARead-onlyIdempotent
Restore a conversation flattened by flatten_messages: re-inlines every tool_result whose content is a [FLATTENED id=...] marker from the matching entry in "extracted", byte-for-byte. Markers with no matching entry are left in place. Purely functional — no disk, no network, input never mutated.
| Name | Required | Description | Default |
|---|---|---|---|
| messages | Yes | The flattened messages[] array (the "messages" field of a flatten_messages result). | |
| extracted | Yes | The "extracted" array returned by flatten_messages for this conversation. |
Output Schema
| Name | Required | Description |
|---|---|---|
| messages | Yes | The restored messages[] array, byte-for-byte identical to the pre-flatten conversation. Any [FLATTENED id=...] marker with no matching extracted entry is left in place. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and idempotentHint=true. Description reinforces with 'purely functional — no disk, no network, input never mutated.' Also details behavior for missing markers. Fully transparent and consistent with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no wasted words. First sentence defines the core function, second adds important caveats. Perfectly front-loaded and concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the straightforward nature of the tool, the description covers the restoration process, marker handling, and principles (functional, idempotent). Output schema exists (as per context signal), so no need to detail return values. Comprehensive for the task.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema descriptions provide clear definitions for both parameters (messages and extracted). The tool description adds behavioral context about the marker format and byte-for-byte restoration, enhancing understanding beyond schema. With 100% schema coverage, baseline is 3, but the additional context merits a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it restores a conversation flattened by flatten_messages, re-inlining tool_result markers byte-for-byte. The verb 'restore' and resource 'conversation' are explicit. Distinguishes from sibling tools like flatten_messages by directly referencing the inverse operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implicitly specifies usage: use when you have a flattened conversation and want to restore it. Does not explicitly state when not to use or list alternatives, but the context of being the inverse of flatten_messages is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unflatten_sessionUnflatten (restore) sessionADestructive
Reverse a flatten: re-inline every flattened tool result back into the session JSONL from the backup, restoring the session to its pre-flatten state, then delete the backup so nothing is left behind. Choose the store with agent ("claude" default, or "codex"). Under codex a UUID reaches any rollout in the tree; "last"/"current" are scoped to the project dir ("current" falls back to "last").
| Name | Required | Description | Default |
|---|---|---|---|
| agent | No | Which agent's session store to target: "claude" (default) or "codex". | claude |
| claude_dir | No | Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/, e.g. ~/.claude-2 for a second profile. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude. Applies to agent "claude" only. | |
| codex_home | No | Absolute path (or ~/...) to the Codex home whose sessions to target — the dir holding sessions/. Default: $CODEX_HOME if set, else ~/.codex. Applies to agent "codex" only. | |
| session_id | Yes | Session UUID, "last", or "current" (the live session; under codex "current" falls back to "last") | |
| project_dir | No | Absolute path to project. Default: the project the CLI runs in (cwd). Under codex, scopes "last"/keyword to rollouts whose cwd equals this dir. |
Output Schema
| Name | Required | Description |
|---|---|---|
| newSize | Yes | Session file size after restoring, in bytes. |
| skipped | No | Present with a reason when the restore was skipped (e.g. no backup to restore from). |
| notFound | Yes | Marker ids that had no matching backup entry and were left in place. |
| sessionId | Yes | The session UUID that was processed ("" when nothing matched). |
| backupPath | Yes | The backup that was restored from (and removed on a full restore). |
| originalSize | Yes | Session file size before restoring, in bytes. |
| restoredCount | Yes | How many flattened tool results were re-inlined. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral details beyond annotations: it explicitly states the backup is deleted, which aligns with destructiveHint=true. It also explains per-agent behavior and keyword scoping, providing full transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, each carrying essential information: core action in the first, agent-specific nuances in the second. No redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (5 parameters, 1 required, output schema exists), the description covers all necessary aspects: purpose, behavioral details, parameter semantics, and agent-specific behavior. The output schema handles return values, so no gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage, baseline is 3. The description adds meaning by explaining how 'agent' selects the store, how 'session_id' handles UUID/keywords, and how 'project_dir' scopes lookups for codex. This significantly aids correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reverses a flatten operation by re-inlining tool results and deleting the backup. It distinguishes from siblings like flatten_session (the opposite) by specifying it restores the pre-flatten state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use (restoring a flattened session) and provides context for agent and scope selection. It lacks explicit when-not-to-use or alternatives, but the sibling list and context make it clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
1 tool update
- Added
unflatten_session
2 tool updates
v2.6.1- Added
retrieve_flattened - Removed
unflatten_session
3 tool updates
v2.6.0- Changed
flatten_session12 fields changed- added
Input schema / properties / agent{ "default": "claude", "description": "Which agent's session store to target: \"claude\" (default) or \"codex\".", "enum": [ "claude", "codex" ], "type": "string" } - added
Input schema / properties / breakdown{ "anyOf": [ { "type": "boolean" }, { "enum": [ "summary", "deep" ], "type": "string" } ], "default": false, "description": "Include the per-tool/resource breakdown of what was flattened. false, true, or \"summary\" = the aggregated adaptive rows plus byKind/bySlot groupings; \"deep\" ALSO lists every individual block under its row (tool + arg summary + bytes + per-block token estimate), groups sorted by context tokens then blocks by bytes. Dry runs always include at least the summary; set true/\"summary\"/\"deep\" to also get it on a real flatten." } - changed
Input schema / properties / claude_dir / descriptionBefore"Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude."
After"Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude. Applies to agent \"claude\" only."
- added
Input schema / properties / codex_home{ "description": "Absolute path (or ~/...) to the Codex home whose sessions to target — the dir holding sessions/. Default: $CODEX_HOME if set, else ~/.codex. Applies to agent \"codex\" only.", "type": "string" } - changed
Input schema / properties / project_dir / descriptionBefore"Absolute path to project. Default: the project the CLI runs in (cwd)"
After"Absolute path to project. Default: the project the CLI runs in (cwd). Under codex, scopes \"last\"/\"last N\"/keyword to rollouts whose cwd equals this dir."
- changed
Input schema / properties / session_id / descriptionBefore"Session UUID, \"last\", \"last N\", or \"current\". Omit to flatten the current live session."
After"Session UUID, \"last\", \"last N\", or \"current\". Omit to flatten the current live session (claude); under codex \"current\" falls back to \"last\"."
- added
Output schema / properties / sessions / items / properties / breakdown{ "additionalProperties": false, "description": "X-ray of what was flattened: adaptive tool/resource rows plus byKind and bySlot groupings, each with the bytes and context tokens freed. Present on every dry run with at least one qualifying block, and on a real flatten only when breakdown=true. contextTokens are exact when tokensExact (per-group count_tokens, requiring the FLATTEN_COUNT_EXACT=1 + ANTHROPIC_API_KEY opt-in), otherwise a local estimate; they are always 0 for the toolUseResult slot (the mirror is disk-only and never in model context).", "properties": { "byKind": { "description": "Grouped by block kind.", "items": { "additionalProperties": false, "properties": { "bytes": { "description": "Disk bytes this group frees.", "type": "number" }, "contextTokens": { "description": "Context tokens this group frees — exact when tokensExact, else estimated; 0 for toolUseResult-slot blocks.", "type": "number" }, "count": { "description": "How many blocks this group holds.", "type": "number" }, "key": { "description": "Block kind: \"text\", \"image\", or \"mixed\" (the group key).", "type": "string" } }, "required": [ "key", "count", "bytes", "contextTokens" ], "type": "object" }, "type": "array" }, "bySlot": { "description": "Grouped by storage slot.", "items": { "additionalProperties": false, "properties": { "bytes": { "description": "Disk bytes this group frees.", "type": "number" }, "contextTokens": { "description": "Context tokens this group frees — the full contextTokensSaved on the content row, 0 on the disk-only toolUseResult row.", "type": "number" }, "count": { "description": "How many blocks this group holds.", "type": "number" }, "key": { "description": "Slot: \"content\" (message.content, in model context) or \"toolUseResult\" (the disk-only mirror).", "type": "string" } }, "required": [ "key", "count", "bytes", "contextTokens" ], "type": "object" }, "type": "array" }, "rows": { "description": "Adaptive tool/resource rows: MCP tools collapse per server, heavyweight resources get their own row, and the light tail folds into a single \"other\" row (at most 9 rows). Partitions the flattened blocks exactly. In deep mode each row also carries its individual blocks in .entries.", "items": { "additionalProperties": false, "properties": { "bytes": { "description": "Disk bytes this row frees.", "type": "number" }, "contextTokens": { "description": "Context tokens this row frees — exact when tokensExact, else estimated; 0 for toolUseResult-slot blocks.", "type": "number" }, "count": { "description": "How many blocks this row holds.", "type": "number" }, "entries": { "description": "Deep mode only (breakdown=\"deep\"): the individual blocks this row aggregates, sorted by bytes desc — the per-command attribution. Absent in summary mode.", "items": { "additionalProperties": false, "properties": { "args": { "description": "Short arg summary (command=…, file_path=…); \"\" when none.", "type": "string" }, "bytes": { "description": "Disk bytes this block frees.", "type": "number" }, "contextTokens": { "description": "Per-block net context-token estimate (local; never reconciled to the exact per-group total).", "type": "number" }, "kind": { "description": "\"text\", \"image\", or \"mixed\".", "type": "string" }, "lineCount": { "description": "Line count of the block's text projection.", "type": "number" }, "name": { "description": "Originating tool name of this block.", "type": "string" }, "slot": { "description": "\"content\" (in model context) or \"toolUseResult\" (disk-only mirror, 0 context tokens).", "type": "string" } }, "required": [ "name", "args", "bytes", "kind", "slot", "contextTokens", "lineCount" ], "type": "object" }, "type": "array" }, "key": { "description": "Row key: a tool family (\"<server> (MCP)\" for MCP tools, else the built-in tool name), or \"other\" for the tail-collapsed row.", "type": "string" }, "resource": { "description": "Present only on a resource-promoted row: the raw file_path/path/url value that earned this tool family its own line.", "type": "string" } }, "required": [ "key", "count", "bytes", "contextTokens" ], "type": "object" }, "type": "array" }, "tokensExact": { "description": "True when the rows' contextTokens are exact (per-group count_tokens), false when locally estimated.", "type": "boolean" } }, "required": [ "tokensExact", "rows", "byKind", "bySlot" ], "type": "object" } - changed
Output schema / properties / sessions / items / properties / entries / descriptionBefore"One row per flattened block (id, originating tool name, size, kind, and slot)."
After"One row per flattened block — id, originating tool name, arg summary, size, kind, slot, per-block token estimate, and line count. The machine-readable per-command attribution the breakdown aggregates."
- added
Output schema / properties / sessions / items / properties / entries / items / properties / args{ "description": "Short arg summary of the originating call (e.g. command=…, file_path=…), same grammar as the marker; \"\" when none.", "type": "string" } - added
Output schema / properties / sessions / items / properties / entries / items / properties / contextTokens{ "description": "Per-block net context-token estimate (local; not reconciled to the exact per-group total).", "type": "number" } - added
Output schema / properties / sessions / items / properties / entries / items / properties / lineCount{ "description": "Line count of the block's text projection.", "type": "number" } - changed
Output schema / properties / sessions / items / properties / entries / items / requiredBefore[ "id", "name", "size", "kind", "slot" ]
After[ "id", "name", "args", "size", "kind", "slot", "contextTokens", "lineCount" ]
- Removed
retrieve_flattened - Changed
unflatten_session5 fields changed- added
Input schema / properties / agent{ "default": "claude", "description": "Which agent's session store to target: \"claude\" (default) or \"codex\".", "enum": [ "claude", "codex" ], "type": "string" } - changed
Input schema / properties / claude_dir / descriptionBefore"Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/, e.g. ~/.claude-2 for a second profile. Default: $CLAUDE_CONFIG_DIR if set (so a server running inside an alternate profile targets it), else ~/.claude."
After"Absolute path (or ~/...) to the Claude config dir whose sessions to target — the dir holding projects/, e.g. ~/.claude-2 for a second profile. Default: $CLAUDE_CONFIG_DIR if set, else ~/.claude. Applies to agent \"claude\" only."
- added
Input schema / properties / codex_home{ "description": "Absolute path (or ~/...) to the Codex home whose sessions to target — the dir holding sessions/. Default: $CODEX_HOME if set, else ~/.codex. Applies to agent \"codex\" only.", "type": "string" } - changed
Input schema / properties / project_dir / descriptionBefore"Absolute path to project. Default: the project the CLI runs in (cwd)"
After"Absolute path to project. Default: the project the CLI runs in (cwd). Under codex, scopes \"last\"/keyword to rollouts whose cwd equals this dir."
- changed
Input schema / properties / session_id / descriptionBefore"Session UUID, \"last\", or \"current\" (the live session)"
After"Session UUID, \"last\", or \"current\" (the live session; under codex \"current\" falls back to \"last\")"
5 tool updates
- Changed
flatten_messages1 field changed- changed
Output schema / (root)Beforenull
After{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "contextTokensExact": { "description": "Always false here — the in-memory tool never makes a network call; use the library flattenMessagesExact for an exact count.", "type": "boolean" }, "contextTokensSaved": { "description": "Estimated context tokens removed from the conversation.", "type": "number" }, "extracted": { "description": "The originals removed from the conversation. Persist this array yourself and pass it back to unflatten_messages to restore byte-for-byte.", "items": { "additionalProperties": false, "properties": { "content": { "description": "The original tool_result value, verbatim (string or content-block array)." }, "id": { "description": "tool_use_id — the marker key used to restore this block.", "type": "string" }, "input": { "additionalProperties": {}, "description": "Originating tool input, or {}.", "type": "object" }, "kind": { "description": "\"text\", \"image\", or \"mixed\".", "type": "string" }, "lineCount": { "description": "Newline count of the original text projection.", "type": "number" }, "name": { "description": "Originating tool name, or \"unknown\".", "type": "string" }, "size": { "description": "Serialized byte size of the original.", "type": "number" } }, "required": [ "id", "name", "input", "size", "lineCount", "kind" ], "type": "object" }, "type": "array" }, "flattenedCount": { "description": "How many tool_result blocks were flattened.", "type": "number" }, "imageBlocksFlattened": { "description": "How many image blocks were among the flattened results.", "type": "number" }, "messages": { "description": "The flattened messages[] array — safe to send — with every bulky tool_result replaced by a compact [FLATTENED id=...] marker. Deep-copied; the input is never mutated.", "items": { "additionalProperties": {}, "type": "object" }, "type": "array" } }, "required": [ "messages", "extracted", "flattenedCount", "imageBlocksFlattened", "contextTokensSaved", "contextTokensExact" ], "type": "object" }
- Changed
flatten_session1 field changed- changed
Output schema / (root)Beforenull
After{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "sessions": { "description": "One entry per session flattened (a single entry for one session_id, or several for \"last N\").", "items": { "additionalProperties": false, "properties": { "backupPath": { "description": "Path to the single self-syncing backup holding the complete inlined session.", "type": "string" }, "contextSavingsPercent": { "description": "contextTokensSaved as a percent of contextTokensTotal, or \"n/a\".", "type": "string" }, "contextTokensExact": { "description": "True if counted via count_tokens, false if estimated locally.", "type": "boolean" }, "contextTokensSaved": { "description": "Context tokens removed from the model context (the number that matters for --resume/compaction).", "type": "number" }, "contextTokensTotal": { "description": "Real context size from the last turn API usage, or null if unknown.", "type": [ "number", "null" ] }, "diskBytesSaved": { "description": "Bytes removed from the .jsonl on disk (speeds --resume parsing).", "type": "number" }, "diskSavingsPercent": { "description": "diskBytesSaved as a percent of the original file size.", "type": "string" }, "dryRun": { "description": "True when dry_run was set — no files were modified.", "type": "boolean" }, "entries": { "description": "One row per flattened block (id, originating tool name, size, kind, and slot).", "items": { "additionalProperties": false, "properties": { "id": { "type": "string" }, "kind": { "type": "string" }, "name": { "type": "string" }, "size": { "type": "number" }, "slot": { "type": "string" } }, "required": [ "id", "name", "size", "kind", "slot" ], "type": "object" }, "type": "array" }, "flattenedCount": { "description": "How many tool results were flattened (0 on a no-op or dry run with nothing to do).", "type": "number" }, "imageBlocksFlattened": { "description": "How many image/screenshot blocks were among them.", "type": "number" }, "newSize": { "description": "Session file size after flattening, in bytes.", "type": "number" }, "originalSize": { "description": "Session file size before flattening, in bytes.", "type": "number" }, "resumeHint": { "description": "Present only when a live session was actually rewritten — reminds you to /resume to load the lighter copy.", "type": "string" }, "sessionId": { "description": "The session UUID that was processed.", "type": "string" } }, "required": [ "sessionId", "dryRun", "flattenedCount", "imageBlocksFlattened", "diskBytesSaved", "diskSavingsPercent", "contextTokensTotal", "contextTokensSaved", "contextSavingsPercent", "contextTokensExact", "originalSize", "newSize", "backupPath", "entries" ], "type": "object" }, "type": "array" } }, "required": [ "sessions" ], "type": "object" }
- Changed
retrieve_flattened1 field changed- changed
Output schema / (root)Beforenull
After{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "kind": { "description": "\"text\", \"image\", or \"mixed\".", "type": "string" }, "line_count": { "description": "Line count of the original text projection.", "type": "number" }, "original_size": { "description": "Byte size of the original content.", "type": "number" }, "slot": { "description": "\"content\" (message.content) or \"toolUseResult\" (the disk mirror).", "type": "string" }, "tool_name": { "description": "Originating tool name of the retrieved result.", "type": "string" }, "tool_use_id": { "description": "The tool_use_id that was retrieved.", "type": "string" } }, "required": [ "tool_use_id", "tool_name", "original_size", "line_count", "kind", "slot" ], "type": "object" }
- Changed
unflatten_messages1 field changed- changed
Output schema / (root)Beforenull
After{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "messages": { "description": "The restored messages[] array, byte-for-byte identical to the pre-flatten conversation. Any [FLATTENED id=...] marker with no matching extracted entry is left in place.", "items": { "additionalProperties": {}, "type": "object" }, "type": "array" } }, "required": [ "messages" ], "type": "object" }
- Changed
unflatten_session1 field changed- changed
Output schema / (root)Beforenull
After{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "backupPath": { "description": "The backup that was restored from (and removed on a full restore).", "type": "string" }, "newSize": { "description": "Session file size after restoring, in bytes.", "type": "number" }, "notFound": { "description": "Marker ids that had no matching backup entry and were left in place.", "items": { "type": "string" }, "type": "array" }, "originalSize": { "description": "Session file size before restoring, in bytes.", "type": "number" }, "restoredCount": { "description": "How many flattened tool results were re-inlined.", "type": "number" }, "sessionId": { "description": "The session UUID that was processed (\"\" when nothing matched).", "type": "string" }, "skipped": { "description": "Present with a reason when the restore was skipped (e.g. no backup to restore from).", "type": "string" } }, "required": [ "sessionId", "restoredCount", "notFound", "originalSize", "newSize", "backupPath" ], "type": "object" }
TDQS
Each tool targets a distinct operation: flatten_session for session files, flatten_messages for in-memory arrays, unflatten_messages for reversing in-memory, and retrieve_flattened for retrieving backed-up content. No overlap in purpose.
All tool names follow a verb_noun pattern (e.g., flatten_session, unflatten_messages, retrieve_flattened). The pattern is consistent and predictable.
Four tools is well-scoped for the domain of conversation flattening and restoration. Each tool serves a specific need without unnecessary duplication.
The set covers flattening and in-memory restoration, but misses an explicit unflatten_session tool, which is referenced in flatten_session's description as reversible. This gap may force agents to adapt.
Maintenance
Related MCP Connectors
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Augments MCP Server - A comprehensive framework documentation provider for Claude Code
Cloud-hosted MCP server for durable AI memory
Related MCP Servers
- AlicenseAqualityDmaintenanceA Model Context Protocol (MCP) server designed to easily dump your codebase context into Large Language Models (LLMs).1123Apache 2.0
- AlicenseAqualityFmaintenanceA server that allows LLMs to run Claude Code with all permissions bypassed automatically, enabling code execution and file editing without permission interruptions.11771,313MIT
- AlicenseBqualityDmaintenanceMCP server for managing Claude Code conversation sessions1278MIT
- AlicenseAqualityDmaintenanceAn MCP server that enables users to retrieve, filter, and search through Claude Code conversation history stored in local projects. It provides tools for listing projects and sessions, paginating through message history, and searching across conversations with keyword filtering.42811MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shayaShav/flatten-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server