Keep only the fields an MCP tool result needs
A tool called get_customer returns the whole customer record: name, address,
date of birth, payment method, support history, internal risk flags. The agent
needed the email address. Everything else now sits in the model's context. It
is sent to the provider on the next turn, may be summarised into memory, and is
one prompt injection away from leaking. Nothing was broken: the tool was
allowed, the call was allowed, and the personal-data scan did its job. OWASP
lists this as MCP10, Context Injection & Over-Sharing.
The scans ask whether a result holds something sensitive. This control asks whether the result needed those fields at all. DVARA, the AI governance platform, can remove the fields a tool's result did not need before they reach the model, even when the server is a vendor's and you cannot change what it returns.
Not included in DVARA Open Source.
How it works
You list, per tool, the fields to keep. Everything else in that tool's result is removed. A tool you have not listed is not changed, so you can adopt this one tool at a time.
Fields are written as paths: email, or customer.email for a field inside
another. Lists are passed through: orders.total keeps total in every order. A
path keeps the field and everything inside it.
Some tools key a result by data rather than by field name, for example a map
from email address to customer. Write * for such a key: customers.*.email
keeps the email under every customer. A named key wins over *.
The Gateway applies the list to:
- the structured result (
structuredContent); - a text part of the result that holds JSON (servers usually send the structured result there too, so it is trimmed the same way);
- the JSON a REST tool returns.
A text part that is plain prose cannot be trimmed safely. It is left as it is, and the record counts it, so you can see that it still carries what it carried.
Fields are removed before the result is scanned for personal data and prompt injection. A removed field is never scanned, logged or sent on.
A valid result stays valid
If the tool declares an output schema, a field the schema says is required is always kept, even when you did not list it. A client that checks results against the schema will not reject a trimmed one. The record says which fields were kept for this reason. If one of them is the sensitive field, the fix is in the tool or its schema, or in redaction by the personal-data scan.
A result that no longer matches its schema
DVARA pins each tool's definition, its output schema included, when you approve it. When this control is on and a tool has an output schema, the record also lists the fields a result carries that the schema does not declare. A server returning more than it declared is over-sharing, or has changed shape since you approved it. This is recorded, not refused.
Turn it on
Three modes, set per workspace:
| Mode | What happens |
|---|---|
off | Nothing. The default. |
discover | Results are not changed. Each tool call's audit record lists every field the result carried and, for a listed tool, what enforce would remove. |
enforce | Fields not listed for a tool are removed from its results. |
Start with discover, so you write the list from what the tool really returns:
- Set the mode to
discoverand call the tool. - Read the tool call's record in the audit log: it lists the fields the result
carried, and how many. Fields the tool's output schema declares are listed by
name; any other key is shown as
*(see What is recorded). For a tool with no output schema, take the names from its documentation. - List the fields the agent needs, and check the record again: it shows what would be removed.
- Set the mode to
enforce.
Set both in the workspace's metadata, for example with a GitOps import:
workspaces:
- name: support
metadata:
mcp.response-projection.mode: enforce
mcp.response-projection.tools:
crm/get_customer: [email, orders.total]
The tool is named as <server id>/<tool name>. The import refuses an unknown
mode, a tool name without its server, and an entry with no fields. A change
reaches the gateways with their next configuration update, with no restart.
What is recorded
Each tool call's audit record names the fields that were removed and how many, the fields kept because the output schema requires them, and the fields outside the output schema. It never holds a field's value.
A field's path is built from the keys of the result, and a server can use data
as a key: an email address, an account number. The audit record is signed and
cannot be edited, so it must not hold them. A part of a path is written by name
only when the tool's output schema or your list of fields names it. Any other
part is written as *, as in customers.*.email, and a count says how many
fields the paths stand for.
Limits
- No Flightdeck page yet. Set the keys by GitOps import.
- Plain text is not trimmed. Only JSON can be cut down by field.
- Tool calls only. Results read later through a task, and resources a client reads, are not trimmed.
- Required fields stay. The Gateway will not make a result break its own schema.