> ## Documentation Index
> Fetch the complete documentation index at: https://docs.horizon.prefect.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Data handling and sensitive-data redaction

> What request and response data Horizon records for served MCP traffic, and how the experimental sensitive-data redaction plugin blocks or masks PII in tool results.

Horizon sits in the request path of every MCP server it serves, so it sees the
traffic those servers handle. This page covers two things that follow from that
position: what request and response data Horizon records for served traffic, and
the experimental **sensitive-data redaction** feature, which can block or mask
sensitive values in a tool result before it reaches the caller.

For how stored values are encrypted and where secrets can appear, see
[Encryption and data protection](/security/data-protection).

## Traffic records

Every MCP request passes through the [gateway](/gateway), which writes one record
per request to Horizon's traffic log. That record is what the
[Observability](/observability) views read from, and it holds three kinds of data.

| Kind              | What it contains                                                                           |
| ----------------- | ------------------------------------------------------------------------------------------ |
| Request metadata  | The MCP method, the tool name, the session and client, and the acting identity.            |
| Response metadata | The status the gateway returned, whether it errored, and how long it took.                 |
| Payloads          | The full request `params` (a tool call's arguments) and the full response result or error. |

Metadata is recorded for every request. Payloads are recorded by default, which
is why a tool call's arguments and its result appear in the request detail on the
[Logs](/observability#request-logs) page. That makes the Logs page useful for
debugging a failed call, and it also means whatever your tools receive and return
is stored there unless you turn payload logging off.

### Payload logging

Whether payloads are stored is a per-project choice. Under the server's
**Settings**, the **General** tab has a **Data Controls** card with two switches:

| Switch            | Effect when off                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------- |
| Log MCP Requests  | Request `params` are no longer stored, so tool-call arguments stop appearing in Logs.     |
| Log MCP Responses | Response results and errors are no longer stored, so tool output stops appearing in Logs. |

Both are on by default. Turning one off stops that payload from being recorded at
all, so it never reaches the traffic record or the Logs page. Metadata is still
recorded either way, and a failed request is still marked as an error, so turning
payloads off narrows what is stored without hiding operational history.

This control decides what Horizon **stores**. Sensitive-data redaction, below,
decides what a caller **receives**, and masks detected values in what gets stored
as a side effect. The two work independently.

### Retention

Horizon currently retains traffic records indefinitely. Customers cannot set a
retention period. Turning request or response payload logging off affects future
requests only and does not delete existing traffic records.

## Sensitive-data redaction

<Warning>
  Sensitive-data redaction is experimental and best-effort. Detection is not
  exhaustive, and this feature is not a compliance control. Do not rely on it
  to meet HIPAA, PII, or other regulatory obligations.
</Warning>

Sensitive-data redaction is a per-project gateway feature that scans each tool
result after your server produces it and before it reaches the caller. When it
finds sensitive data, it acts on the result: it either blocks the whole result or
masks the matched spans. Detection combines managed PII detection with custom
regex rules you define, and both run on every tool result while the feature is
enabled.

### How detection works

Automatic PII detection finds entities such as email addresses, phone numbers,
and government identifiers in the result text. Each finding carries a confidence
value, and a **sensitivity** setting decides how confident a finding must be to
count. A higher sensitivity accepts lower-confidence findings, so it catches more
but is likelier to flag safe text.

| Sensitivity      | Behavior                                   |
| ---------------- | ------------------------------------------ |
| Low              | Catches only high-confidence matches       |
| Medium (default) | Balanced                                   |
| High             | Catches more, at the cost of over-flagging |

Detection runs on the text in the result, including text inside embedded
resources and string values in structured content. The scan operates on English
text.

### Custom rules

Custom rules match values that automatic detection would not recognize, such as an
internal account number or record identifier. Each rule pairs a **pattern** with a
**label**, uses Python's regular-expression syntax, and runs in addition to
automatic detection. A regex match always counts, regardless of the sensitivity
setting.

| Field   | Format                                                                                                                             |
| ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Label   | Uppercase letters, digits, and underscores (`^[A-Z0-9_]+$`), 1–64 characters. Names the rule and appears in the recorded findings. |
| Pattern | A Python regular expression, 1–500 characters. Inline flags such as `(?i)` for case-insensitive matching are allowed.              |

A project can define up to **10** custom rules.

### What happens on a match

When a scan finds sensitive data, the project's **action** decides what the caller
receives.

| Action          | Result the caller receives                                                                                                                                                      |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Block (default) | The entire tool result is replaced with a single error result reading `Tool result blocked`. None of the original content is returned.                                          |
| Redact          | Each matched span is replaced with `[REDACTED]`, and the rest of the result is returned unchanged. If a match cannot be safely masked in place, that result is blocked instead. |

Detection **fails closed**. If a scan cannot complete, for any reason, the result
is blocked rather than returned unscanned. A result whose text is too large to
scan is treated the same way. Failing closed means a scanning problem withholds
data rather than leaking it.

### Enabling redaction

Redaction is configured per project, under the server's experimental settings.
Because it is experimental, it is gated: it may not be available for your
organization yet. If the experimental settings do not offer it, contact
[horizon-support@prefect.io](mailto:horizon-support@prefect.io) to request access.

<Steps>
  <Step title="Open experimental settings">
    Go to the server's **Settings**, then **Experimental**, and find
    **Sensitive data redaction**.
  </Step>

  <Step title="Enable the feature">
    Turn on **Enabled**.
  </Step>

  <Step title="Choose an action and sensitivity">
    Set the **Action** to **Block** or **Redact**, and set the **Sensitivity** to
    **Low**, **Medium**, or **High**. New configurations default to blocking at
    medium sensitivity.
  </Step>

  <Step title="Add a custom rule">
    Under **Custom rules**, choose **Add custom rule**, enter a **label** (such as
    `ACCOUNT_ID`) and a regex **pattern** (such as `\bCUSTOM-[0-9]{6}\b`). Add up
    to ten rules.
  </Step>

  <Step title="Save">
    Choose **Save** to apply the configuration. It takes effect for subsequent
    tool results.
  </Step>
</Steps>

### What gets recorded

When redaction acts on a result, Horizon records a summary of what matched: a
count per rule and per detected entity type, such as `EMAIL`. It never records the
matched values themselves.

Because redaction runs before the response is finalized, it also shapes what lands
in the [response payload](#payload-logging) when response logging is on. A blocked
result stores the `Tool result blocked` placeholder, and a redacted result stores
the masked text, so the sensitive values never reach the traffic record. Redaction
acts only on responses. It does not change what a request payload records.

## Security reviews

If your procurement or security review needs implementation detail beyond this
page, such as the detection provider's data handling or retention specifics,
contact [horizon-support@prefect.io](mailto:horizon-support@prefect.io) to request
a formal security review.

## Related docs

<CardGroup cols={2}>
  <Card title="Encryption and data protection" icon="lock" href="/security/data-protection">
    How Horizon encrypts stored values and where secrets can appear.
  </Card>

  <Card title="Observability" icon="chart-line" href="/observability">
    Inspect the request logs, sessions, and payloads recorded for a server.
  </Card>

  <Card title="Gateway" icon="route" href="/gateway">
    How requests move through routing, access checks, and the plugins that run on them.
  </Card>

  <Card title="Environment variables" icon="key" href="/environment-variables">
    Create, scope, and rotate the encrypted values your hosted servers use.
  </Card>
</CardGroup>
