Skip to content

Seeing what the agent sends

In this lesson we look at what Claude Code sends to the model, in three places. The context meter shows how full the window is while you work. The session record on disk holds every message, tool call and tool result of a session. A request log, which you turn on for one session, holds each request exactly as it was sent. The exercise connects one more tool and follows it through all three.

The concepts course showed a toy harness’s own log of what is in each request: the instructions, the tool descriptions and the history, sent again on every call. The lesson on what the tool list costs estimated what a server’s tool definitions take from that request. Here you look at the real requests of your own agent.

In Claude Code, /context shows what fills the window right now, broken down by category, with suggestions for what to trim [1]. One of the categories is the tools of Model Context Protocol (MCP) servers, shown as MCP tools. With tool search on, which is the default, only the tool names are in the window, and the model loads a full schema when a task needs it. With ENABLE_TOOL_SEARCH=false every schema loads at the start [1].

/context answers when you ask. A status line shows a number all the time. Claude Code runs the status line command after each new reply from the model, passes it the session data as JSON (JavaScript Object Notation) on standard input, and shows what it prints [2]. The command runs on your machine and costs no tokens. For this lesson the useful fields are these:

  • context_window.used_percentage, the share of the window in use. It is counted from the input tokens of the last request, and it can be null early in a session.
  • context_window.total_input_tokens, those input tokens, cache reads and cache writes included.
  • transcript_path, the path of the session record on disk.

All three come from the statusline page [2]. statusline.py in site/examples/customizing-agents/seeing-what-the-agent-sends/ prints them on one line, and a dash for a field that is missing or null. You point Claude Code at it with a statusLine entry in a settings file [2]:

{
"statusLine": {
"type": "command",
"command": "python3 /tmp/handbook-inspect/.claude/statusline.py"
}
}
Example · run it

Run statusline_demo.py in the fixture directory, and compare with the output below. The first sample input is from before the first request, when the share is still null. The second is from after a request.

used_text = "-" if used is None else f"{round(used)}%"
total_text = "-" if total is None else f"{total:,} tokens"
record = "-" if not transcript else os.path.basename(transcript)
return f"context {used_text} | {total_text} | record {record}"
Output
context - | 0 tokens | record 2f6c0d1e-5a7b-4c9d-8e3f-1a2b3c4d5e6f.jsonl
context 12% | 23,480 tokens | record 2f6c0d1e-5a7b-4c9d-8e3f-1a2b3c4d5e6f.jsonl

Output verified in CI from site/examples/customizing-agents/seeing-what-the-agent-sends/statusline_demo.py.

The meter tells you that the window is filling, and /context tells you which category fills it. Neither shows the text itself.

Claude Code keeps data under ~/.claude as you work. The transcript of a session is projects/<project>/<session>.jsonl, and it holds every message, every tool call and every tool result of that session [3]. The project directory is named after the project’s path, with every character other than a letter or a digit turned into a dash, so /home/user/work/my-repo becomes -home-user-work-my-repo. On macOS a copy in /tmp is at /private/tmp, and its directory starts with -private-tmp-. The status line above gives you the file name, and transcript_path gives the full path.

Resume and rewind read past sessions from these files, and they are the place to look when a run went wrong yesterday and you want to see which file the agent read before it did. They are also plain text and unencrypted, so whoever can read your files can read them. A .env file the agent opened, or a key that a command printed, ends up in the record as well [3]. Claude Code deletes records older than cleanupPeriodDays, which is 30 days unless you set it. From version 2.1.288, claude purge <path> deletes a project’s transcripts, its memory and its lines in the prompt history, after it shows you the plan [3].

The record holds the session turn by turn. The system prompt and the tool definitions that came with each request aren’t in the page’s list of what it holds. For those you need the request itself.

Checkpoint · match

Match each question to the view that answers it. The request log was off in last week’s and yesterday’s sessions.

Claude Code can write every request it sends to a directory on your machine. It is part of its OpenTelemetry monitoring, the standard it uses to export usage data [4]. Telemetry is on only with CLAUDE_CODE_ENABLE_TELEMETRY=1. OTEL_LOG_RAW_API_BODIES=file:<dir> then writes the full body of each request to <dir>/<uuid>.request.json, and from version 2.1.274 Claude Code adds one line per successful response to <dir>/index.jsonl, with the session id, the query_source that sent the request and the file names [4]. OTEL_METRICS_EXPORTER=none and OTEL_LOGS_EXPORTER=none switch off both exporters, so the events themselves don’t go to a collector anywhere [4]. In our run in October 2026, the request files were written with both exporters set to none. If your organization already collects Claude Code telemetry, ask its administrators before you turn on the request log, because their settings may send the events somewhere you don’t expect.

The monitoring page leaves request bodies out unless you ask for them. The variable’s description warns that a body carries the whole conversation, so it reveals all that the switches for prompt text and tool details would reveal [4]. A request file holds the system prompt, every tool definition and every message so far, with the full text of each file the agent read and any secret a command printed. So keep the log on your own machine, in a directory only your user can read and outside every repository. Turn it on for the session you are investigating, and delete the directory when you have your numbers. Don’t send a request file to an online token counter or paste it into a chat assistant.

Each request lists the tools in its tools field. In the Claude application programming interface (API), a definition marked defer_loading is sent to the API but stays out of the model’s context window until the model searches for that tool [5]. So /context shows what is in the window, the request log shows what was sent, and the two can differ. In our run on 7 October 2026, a claude -p run with tool search on and no MCP server, the deferred tools were Claude Code’s own built-in tools. They appeared by name in a message, and the tools field held one placeholder marked defer_loading. The exercise starts Claude Code with ENABLE_TOOL_SEARCH=false, which loads every MCP tool definition upfront [6], so each MCP tool definition in the log is one the model reads.

A gateway can log requests too. You point ANTHROPIC_BASE_URL at it, and the gateway can log every request that passes through [7]. Anthropic doesn’t vouch for gateway products made by others [7]. A gateway you don’t run yourself also holds a copy of everything that passes through it, file contents and secrets included. The log in a local directory never leaves your machine.

Claude Code also sends requests of its own besides the turns of your conversation, and the side requests are in the log too. The monitoring page’s cost counter sorts requests into main, subagent and auxiliary ones. The query_source in index.jsonl is a different field, with values such as repl_main_thread for the main conversation and compact [4].

read_log.py in the fixture directory reads a log directory and prints, for each request, the estimated tokens of the system prompt, the tools and the messages, at four characters per token. The mcp tools column is the tool definitions of MCP servers and their share of the request. Claude Code names an MCP tool mcp__<server>__<tool> [8], and the script groups the tools by that name. The source column is the query_source from index.jsonl. The script skips a request without tools and leaves out a definition marked defer_loading, and it prints how many of each it found. sample_log.py writes a sample log of one side request without tools, then one prompt that took three model calls, with three built-in tools and a notes server with five tools, and runs read_log.py on it.

Example · run it

Run sample_log.py in the fixture directory, and compare with the output below.

all_tools = body.get("tools") or []
if not all_tools:
skipped += 1
continue
tools = [tool for tool in all_tools if not tool.get("defer_loading")]
Output
estimated tokens, 4 characters per token
request  system   tools  messages   total  mcp tools   source
      1     404     926        20   1,350  604 (45%)   repl_main_thread
      2     404     926       107   1,437  604 (42%)   repl_main_thread
      3     404     926       235   1,565  604 (39%)   repl_main_thread
mcp__notes: 5 tools
skipped 1 request(s) without tools
left out 0 deferred definition(s)

Output verified in CI from site/examples/customizing-agents/seeing-what-the-agent-sends/sample_log.py.

The sample is small, so read it for its pattern. The system prompt and the tools are the same in every request, and only the messages grow. The notes server’s five definitions are 604 of the 1,350 tokens of the first request, before the agent has done anything. Two of the five tools did the work. add_note and delete_note came along on every call, and any instruction the agent read could ask for them.

Checkpoint · choice

The server’s tool definitions are 45% of the first request and 39% of the third. Why does the share fall?

Checkpoint · scenario

The measurement is done: the server’s tool definitions are a fifth of every request. What do you do with the log?

Exercise

Connect one more tool in a copy and follow it through the meter, the record and the log. Copy the handbook directory and the status line script to places you can delete, and point the copy’s settings at the script. Run the shell steps from the course repository’s top level.

Terminal window
cp -r site/examples/customizing-agents/mcp-first-server/handbook /tmp/handbook-inspect
mkdir -p /tmp/handbook-inspect/.claude
cp site/examples/customizing-agents/seeing-what-the-agent-sends/statusline.py /tmp/handbook-inspect/.claude/
printf '%s\n' '{"statusLine": {"type": "command", "command": "python3 /tmp/handbook-inspect/.claude/statusline.py"}}' > /tmp/handbook-inspect/.claude/settings.json
mkdir -m 700 ~/claude-request-log
  1. cd /tmp/handbook-inspect and start claude. Trust the folder, check that the status line shows, and run /context. Write down the total and the MCP tools line, if there is one. Quit.

  2. Add the file-system server to the copy, as in the lesson on your first server. It can read, write, edit and move files in the directory you give it, which is the copy [9]. Start a logged session with every MCP tool definition loaded, so the log counts what the model reads:

    Terminal window
    cd /tmp/handbook-inspect
    claude mcp add handbook -- npx -y @modelcontextprotocol/server-filesystem@2026.8.31 /tmp/handbook-inspect
    CLAUDE_CODE_ENABLE_TELEMETRY=1 OTEL_METRICS_EXPORTER=none OTEL_LOGS_EXPORTER=none OTEL_LOG_RAW_API_BODIES=file:$HOME/claude-request-log ENABLE_TOOL_SEARCH=false claude

    Run /context and compare the MCP tools line with step 1. Ask: “Use the handbook server to read on-call.md and tell me when the rota changes.” Watch the status line after the reply.

  3. In a second terminal, find the record. The status line shows its file name. Run grep -l "rota changes every Monday" ~/.claude/projects/*/*.jsonl and check that it is one of the files grep names. Records of the earlier handbook exercises can match too.

  4. Quit the session, then run python3 site/examples/customizing-agents/seeing-what-the-agent-sends/read_log.py ~/claude-request-log from the course repository. Read the mcp tools column of the first row whose source is repl_main_thread, the main conversation [4]. If no row shows it, read the first row whose source isn’t a title or another side request, and note its source. If the source column shows -, read the first row. If you do the stretch goal, do it now, before you clean up.

  5. Clean up: rm -rf ~/claude-request-log ~/claude-request-log-2, then cd /tmp/handbook-inspect && claude mcp remove handbook. Run claude purge without a path and pick the copy from its list. The list may show it as /private/tmp/handbook-inspect. Check that the plan names the copy before you answer y [3]. Last, rm -rf /tmp/handbook-inspect.

A good result is three numbers from your own run: the MCP tools line of /context before and after, and the handbook share in the first main-conversation row of read_log.py. Write them in a short note with one line on whether you would keep the server connected in a project that reads its files once a week. Then ask yourself: which of the three views would have shown you that a secret was read, and how long would it have stayed on disk?

Stretch: Before step 5, deny the server's write tools by name in the copy's .claude/settings.json, run mkdir -m 700 ~/claude-request-log-2, run the logged claude command from step 2 with file:$HOME/claude-request-log-2, ask the same question, quit, run read_log.py on ~/claude-request-log-2, and compare the mcp tools column of its first repl_main_thread row with the one from step 4.

Recap

  1. /context breaks down what fills the window by category, and a status line can show the share in use, the input tokens and the record’s path after every reply [1] [2].
  2. The session record under ~/.claude/projects/ holds every message, tool call and tool result in plain text, secrets included, until cleanupPeriodDays or claude purge removes it [3].
  3. OTEL_LOG_RAW_API_BODIES=file:<dir> writes each request, with the system prompt, the tool definitions and the messages, to a local directory [4]. The log shows what each part costs in every request.
  4. Turn the log on for one session, keep it in a directory outside every repository that only you can read, and delete it when you have your numbers. A gateway on ANTHROPIC_BASE_URL that you don’t run holds a copy of the same data. Anthropic doesn’t vouch for gateway products made by others [7].

You can now

  • Inspects the requests to see what tools and context cost, and keeps request logs local

  1. Anthropic. Explore the context window. Claude Code documentation. Reference. Claude Code context window
  2. Anthropic. Customize your status line. Claude Code documentation. Reference. Claude Code statusline
  3. Anthropic. Explore the .claude directory. Claude Code documentation. Reference. Claude Code claude directory
  4. Anthropic. Monitoring. Claude Code documentation. Reference. Claude Code monitoring
  5. Anthropic. Tool search tool. Claude Platform documentation. Reference. Claude docs tool-search-tool
  6. Anthropic. Connect Claude Code to tools via MCP. Claude Code documentation. Reference. Claude Code mcp
  7. Anthropic. Other LLM gateways. Claude Code documentation. Reference. Claude Code llm gateway
  8. Anthropic. Configure permissions. Claude Code documentation. Reference. Claude Code permissions
  9. Model Context Protocol a Series of LF Projects, LLC. Filesystem MCP Server. GitHub, modelcontextprotocol/servers, src/filesystem. Reference. MCP filesystem server