HarperFast / HarperFast/harper
[MCP/OpenAPI] hidden is not honored on nested sub-properties, and leaks as a schema key in OpenAPI
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
Follow-up from the docs pass for #1923 ([documentation#605](https://github.com/HarperFast/documentation/pull/605)).
## Problem
`@hidden` / `hidden: true` is documented as the way to keep a field out of the MCP tool descriptors and the OpenAPI document — the latter matters because `/openapi.json` has no per-user filtering, so anything reaching it is visible to anyone who can hit the HTTP port. That suppression is implemented **only at the top level**:
**MCP** — `attributeVisible` is consulted in the top-level loops (`components/mcp/tools/schemas/derive.ts:166`, `:208`, `:319`), but `attributeToProperty` recurses into `attr.properties` with no visibility check, so a hidden sub-property is emitted with its `description`.
**OpenAPI** — `resources/openApi.ts:142` does `if (hidden) continue;` for top-level attributes only. The nested-object branch calls `attributeToFragment`, which does not suppress and instead **emits the flag as a schema key**:
```ts
// resources/jsonSchemaTypes.ts:119
if (attr.hidden) fragment.hidden = true;
```
So a hidden nested sub-property appears in the public OpenAPI document along with its description *and* a `"hidden": true` marker advertising that it was meant to be suppressed.
## Why it matters
The docs tell authors to use `@hidden` for fields that should not surface publicly ("don't put secrets, internal-only commentary, or speculative prose in docstrings; use `@hidden` to suppress"). For a nested field that guidance currently does not hold. This is narrow — it needs a nested object whose sub-field is marked hidden — but the failure is silent and in the direction of disclosure.
Note the exposure is bounded: table-backed GraphQL nested types usually take the `$ref` branch in `openApi.ts`, so this mainly affects programmatic `static properties` objects and any table path that reaches the `attr.properties` branch.
## Suggested fix
1. Filter in the recursion: skip `hidden` sub-attributes in `attributeToProperty` (`derive.ts`) and in `attributeToFragment`'s `properties` loop (`jsonSchemaTypes.ts`), rather than only in the top-level loops.
2. Stop emitting `hidden` as a JSON Schema key at all — it is a Harper directive, not JSON Schema vocabulary, and it does not belong in an output document. (Check consumers first: `Table.properties` round-trips through `fragmentToAttribute`, which reads it back, so the key may need to stay in the canonical projection while being stripped on the MCP/OpenAPI emit paths.)
3. Add unit coverage for a hidden sub-property on both surfaces — the existing tests only assert top-level suppression.
Once fixed, the "top-level only" caveats in `reference/resources/resource-api.md` need to come back out.
_Issue generated by kAIle (Claude Opus 4.8)._
Contributor guide
Assessment
This issue has not been assessed yet.