In Claude Code, the built-in tools all provide TWO forms of output:
- a set of content blocks, for consumption by subsequent LLM requests
- raw tool-specific JSON output, for consumption by hooks and display in the UI
Currently the MCP spec only allows for tools to return the first form content, a set of content-blocks. I think the MCP spec should be expanded to allow an optional rawContent: any, for consumption by hooks and UI.
Why?
First, when someone writes a tool, then they'd now be able to tailor the for-LLM content to be exactly the kind of content that LLMs like best to consume, while allowing hook-authors to consume their tool's output in the format best for the hook author.
Second, imagine if all of Claude Code's built-in tools could be moved into its MCP server, and all of Gemini CLI's built-in tools could be moved to its MCP server. (They currently can't because MCP specification isn't expressive enough: it lacks the raw json). That way, when someone writes an agent, they could freely chose what set of built-in tools to use!
I documented for each of Claude Code's built-in tools how the for-LLM-output of the tool differs from the for-hook-and-UI output of the tool: https://github.com/ljw1004/claude-log/blob/main/parse.py
- For the Read tool
- for-LLM-output is similar to the output of
cat -n, i.e. numbered lines, with a at the end to warn it about malicious files
- for-hook-output is nicely structured {filePath: str, content: str, numLines: int, startLine: int, totalLines: int}
- For the Edit tool
- for-LLM-output says "The file foo.py has been updated. Here's the result of running
cat -n on a snippet of the edited file:" and then it shows line-numbered content of the changed lines plus surrounding lines
- for-hook-output is nicely structured {originalFile: str, structuredPatch: list[{oldStart:int, oldLines:int, newStart: int, newLines: int, lines: list[str]}}
- and similarly for the others
I've not submitted an MCP spec proposal before. I wanted to create this first as an issue to sound out what people think about it, before I go down full-blown spec proposal route.
In Claude Code, the built-in tools all provide TWO forms of output:
Currently the MCP spec only allows for tools to return the first form
content, a set of content-blocks. I think the MCP spec should be expanded to allow an optionalrawContent: any, for consumption by hooks and UI.Why?
First, when someone writes a tool, then they'd now be able to tailor the for-LLM content to be exactly the kind of content that LLMs like best to consume, while allowing hook-authors to consume their tool's output in the format best for the hook author.
Second, imagine if all of Claude Code's built-in tools could be moved into its MCP server, and all of Gemini CLI's built-in tools could be moved to its MCP server. (They currently can't because MCP specification isn't expressive enough: it lacks the raw json). That way, when someone writes an agent, they could freely chose what set of built-in tools to use!
I documented for each of Claude Code's built-in tools how the for-LLM-output of the tool differs from the for-hook-and-UI output of the tool: https://github.com/ljw1004/claude-log/blob/main/parse.py
cat -n, i.e. numbered lines, with a at the end to warn it about malicious filescat -non a snippet of the edited file:" and then it shows line-numbered content of the changed lines plus surrounding linesI've not submitted an MCP spec proposal before. I wanted to create this first as an issue to sound out what people think about it, before I go down full-blown spec proposal route.