Skip to content

feat(list-notes): contentPreviewChars for lightweight folder scans#15

Merged
Dan8Oren merged 1 commit into
mainfrom
feat/list-notes-preview
Jun 18, 2026
Merged

feat(list-notes): contentPreviewChars for lightweight folder scans#15
Dan8Oren merged 1 commit into
mainfrom
feat/list-notes-preview

Conversation

@Dan8Oren

@Dan8Oren Dan8Oren commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Summary

Adds an optional contentPreviewChars parameter to the list-notes tool. When set (together with path), each returned note includes an HTML-stripped, whitespace-collapsed text preview truncated to N characters, with content_truncated: true when the body was cut.

Why

Today the only way to get note text from list-notes is includeContent: true, which returns the raw HTML note.body() for every note in a folder. For folders with many or large notes this can blow past the MCP response token cap, and clients then have to do their own HTML cleanup.

contentPreviewChars lets an agent scan a whole folder cheaply — e.g. 100 notes × 200 chars — and then get-note only the ones it cares about. Strip + truncate happens inline in a single JXA call, no extra round trips, no client-side post-processing.

Behaviour

  • New optional integer parameter on list-notes
  • HTML tag stripping + entity decoding ( , &, <, >, ", ') + whitespace collapse
  • Adds content_truncated: true on notes that exceeded the limit
  • Requires path — enforced at the schema level via z.refine, because the no-path branch reads cached content from LanceDB and does not run the JXA preview pipeline. Trying to use it without a path returns a clear validation error rather than silently ignoring the flag.
  • When both includeContent and contentPreviewChars are set, the preview wins (truncated text replaces full HTML).

Test plan

  • list-notes with path + contentPreviewChars: 200 returns previews and content_truncated flags
  • list-notes with contentPreviewChars but no path returns a schema validation error
  • list-notes with only includeContent: true is unchanged (regression check)
  • HTML entities (&,  , etc.) are decoded in previews
  • Long-form notes show content_truncated: true; short notes do not

Adds an optional `contentPreviewChars` parameter to `list-notes` that
returns an HTML-stripped, whitespace-collapsed preview of each note,
truncated to N characters, in a single JXA call. Notes whose body
exceeded the limit are flagged with `content_truncated: true`.

This avoids the MCP response token cap when callers want to scan many
notes in a folder before deciding which ones to fetch in full via
`get-note`. Strip + truncate happens inline in JXA, so no extra round
trips and no client-side HTML cleanup.

The new parameter requires `path` (enforced at the schema level via
`refine`), since the indexed/no-path branch reads cached content from
LanceDB and does not run the JXA preview pipeline.
@Dan8Oren Dan8Oren force-pushed the feat/list-notes-preview branch from 5e48f1d to 5aede08 Compare June 5, 2026 14:31
@Dan8Oren

Dan8Oren commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

Amended after CI failure. Two things I should have done before pushing the first time:

  1. Prettier reflow committed. Adding the new contentPreviewChars cell to the Available Tools table widened the column, and prettier --check (which I had not run locally) wanted the rest of the rows re-padded to match. Done.
  2. Runtime verification. I had only run tsc --noEmit before, not exercised the feature. Now added test/test-list-notes-preview.mjs which covers:
    • Zod schema rejects contentPreviewChars without path (the new refine)
    • Zod schema still accepts path/includeContent/empty (no regression)
    • JXA against a real Apple Notes folder returns previews, all <= contentPreviewChars
    • No HTML tags leak through the strip
    • content_truncated: true set on truncated notes, absent (not false) on the rest

All 11 assertions pass locally against my Notes (folder iCloud/Notes, 46 notes). Full local CI parity (tsc + prettier --check) is now green.

Known limitation surfaced by verification: double-encoded entities (e.g. &amp;amp;) are only single-decoded by the current regex pass. Not introduced by this change (existed in source-note HTML), and acceptable for a preview, but worth flagging.

Force-pushed via --force-with-lease.

@Dan8Oren Dan8Oren merged commit 6917c2d into main Jun 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant