# `ConduitMcp.Reflect`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.11.0/lib/conduit_mcp/reflect.ex#L1)

The single boundary helper for client-supplied text that is echoed back to
the client or written to the log.

Three separate hazards, one function:

  * **Type.** Interpolating a non-binary — `protocolVersion: {}`, a
    `requestId` object — raises inside the handler, and the surrounding
    `rescue` turns a client mistake into a misleading
    "Internal server error".
  * **Size.** A 1 MB string sits comfortably inside the transports'
    `length: 1_000_000` parser cap, and an unclamped echo reflects it in
    full into both the error message and the log line.
  * **Control characters.** An unfiltered echo of
    `"tools/call\x00\x01\x02"` reaches the operator's log with terminal
    escapes and NULs intact.

`text/2` applies `to_string/1`, strips control characters (C0/C1, DEL,
zero-width and bidi controls, and the Unicode line separators — keeping
nothing, not even tabs or newlines, which is what lets a value forge log
lines), and clamps both the byte length and the grapheme length. Both clamps
are needed: a grapheme cluster is unbounded in size, so one base character
plus 400 000 combining marks is a single grapheme and ~800 KB of output.

# `text`

```elixir
@spec text(term(), pos_integer()) :: String.t()
```

Renders `value` as text that is safe to put in an error message or a log
line: coerced to a string, control characters removed, clamped to `max`
graphemes *and* to a hard byte ceiling (default 200).

## Examples

    iex> ConduitMcp.Reflect.text("tools/call")
    "tools/call"

    iex> ConduitMcp.Reflect.text("tools/call\x00\x01")
    "tools/call"

    iex> ConduitMcp.Reflect.text(%{})
    "%{}"

    iex> ConduitMcp.Reflect.text(String.duplicate("a", 500)) |> String.length()
    200

---

*Consult [api-reference.md](api-reference.md) for complete listing*
