Bridges the gap between the in-memory `ToolCall` / `ToolResponse`
types and on-the-wire JSON-RPC frames. Pure Rust, no serde dep
(shell-core stays wasm32-clean — adding serde would inflate the
bundle for a feature only the server binary uses).
- `response_to_json(&ToolResponse) -> String` — emits the
standard `{"jsonrpc":"2.0","id":...,"result":...}` for OK and
`{"jsonrpc":"2.0","id":...,"error":{"code":...,"message":...}}`
for Err. Hand-rolled emitter with proper JSON escaping for
`"`, `\`, `\n`, `\r`, `\t`, and control chars.
- `parse_tool_call(&str) -> Option<ToolCall>` — minimal parser
that extracts `id` / `method` from a single-line JSON-RPC
request. Empty `arguments` map for now; the server binary
will swap in a real serde parse when wired.
- `error_code_to_int` — maps `ToolErrorCode` variants to
JSON-RPC's reserved + application-range codes per the spec
(-32600..-32603 transport, -32001..-32002 application).
Tests (4 new):
- Ok response carries `"jsonrpc":"2.0"`, the right id, and the
result map serialised correctly.
- Err response carries the right error code (-32601 for
UnknownTool) and message.
- Round-trip: parse_tool_call → registry.dispatch → response_to_json
preserves the request id through the full pipeline.
- JSON escapes special chars (`"`, `\n`) in both id and message.
#7 MCP now ~30% — types + registry + wire format. Real stdio
listener (line-delimited JSON over stdin/stdout) lives in the
follow-up server binary.
Tests total: 227 shell-core (+4) + 20 native + 8 desktop = 255.
Wasm32 build clean.