Found during review of PR #1352 (issue #1163, part of #1127). Pre-existing core behaviour (#568), out of scope there — filed so it is not lost.
The defect
#1163 closed this leak on the read side: a field withheld from the MCP schema is now refused with the byte-identical message an unknown field gets, so the refusal discloses nothing the schema withheld.
The write side still distinguishes the two:
- a withheld field →
field-level access denied
- a nonexistent field →
not a field of this list
So an assistant can enumerate the fields it may not write, one probe at a time, by reading which refusal comes back — exactly the disclosure the read-side work exists to prevent. #1163 made this newly visible by omitting denied fields from the create/update data schemas: the schema now withholds a name, and the refusal then confirms it exists.
Acceptance criteria
Notes
The read-side fix is the model to follow: relation visibility and field visibility were unified into one advertisableFields vocabulary, and the refusal path looks names up in a map built from that same list, so a withheld name takes the identical branch to an unknown one.
Care is needed not to degrade a genuine validation error into a misleading "no such field" for a field the caller may write — the masking must apply only where the name was actually withheld.
Generated by Claude Code
Found during review of PR #1352 (issue #1163, part of #1127). Pre-existing core behaviour (#568), out of scope there — filed so it is not lost.
The defect
#1163 closed this leak on the read side: a field withheld from the MCP schema is now refused with the byte-identical message an unknown field gets, so the refusal discloses nothing the schema withheld.
The write side still distinguishes the two:
field-level access deniednot a field of this listSo an assistant can enumerate the fields it may not write, one probe at a time, by reading which refusal comes back — exactly the disclosure the read-side work exists to prevent. #1163 made this newly visible by omitting denied fields from the
create/updatedataschemas: the schema now withholds a name, and the refusal then confirms it exists.Acceptance criteria
dataschema is refused with the byte-identical message a nonexistent field getspackages/core/src/mcp/projection.ts:401)Notes
The read-side fix is the model to follow: relation visibility and field visibility were unified into one
advertisableFieldsvocabulary, and the refusal path looks names up in a map built from that same list, so a withheld name takes the identical branch to an unknown one.Care is needed not to degrade a genuine validation error into a misleading "no such field" for a field the caller may write — the masking must apply only where the name was actually withheld.
Generated by Claude Code