Skip to content

feat(optional-mcps): add Apple macOS MCP servers (mail, notes, numbers, photos) - #51466

Open
sweetrb wants to merge 47 commits into
NousResearch:mainfrom
sweetrb:add-apple-macos-mcp-servers
Open

sweetrb wants to merge 47 commits into
NousResearch:mainfrom
sweetrb:add-apple-macos-mcp-servers

Conversation

@sweetrb

@sweetrb sweetrb commented Jun 23, 2026

Copy link
Copy Markdown

What does this PR do?

Adds four macOS MCP servers to the optional-mcps/ catalog so Hermes users can install them with hermes mcp install <name>:

  • apple-mail — read, search, send, reply, forward, and organize Apple Mail
  • apple-notes — create, search, read, update, and organize Apple Notes
  • apple-numbers — read, write, search, and format Apple Numbers (.numbers) spreadsheets
  • apple-photos — query, search, export, and inspect the macOS Photos library

All four are published, MIT-licensed npm packages maintained under github.com/sweetrb, with CI on macos-latest (Node 20 + 22). Each manifest is a plain stdio entry that launches the published package via npx -y <pkg> — no install/clone step (per the npm/uvx note in the n8n manifest) and auth: none (everything is local). They already support Hermes today via hermes mcp add; this just makes them one-command installable from the catalog.

Related Issue

None — new catalog entries.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • optional-mcps/apple-mail/manifest.yaml
  • optional-mcps/apple-notes/manifest.yaml
  • optional-mcps/apple-numbers/manifest.yaml
  • optional-mcps/apple-photos/manifest.yaml

How to Test

On macOS:

  1. hermes mcp install apple-notes (or apple-mail / apple-numbers / apple-photos)
  2. Start a new Hermes session.
  3. The server launches via npx -y apple-<app>-mcp. First use prompts for macOS Automation access (AppleScript); apple-photos additionally needs Full Disk Access. Tools then load (e.g. apple-notes: create-note, search-notes, list-notes, …).

Platforms tested: macOS (each server's own CI runs on macos-latest, Node 20 + 22). apple-numbers and apple-photos use a Python 3.11+ sidecar (numbers-parser / osxphotos) that bootstraps a local venv on first run.

Notes

  • These are macOS-only by nature (AppleScript / the macOS Photos library), which each manifest's post_install calls out.
  • apple-mail exposes send/delete/move tools that act on the real mailbox; the install-time checklist lets users prune to a read-only surface. The others are read-mostly (apple-photos is read-only except export).

Happy to adjust naming, descriptions, or split into separate PRs if you'd prefer.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have tool/mcp MCP client and OAuth labels Jun 23, 2026
@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 15, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding native macOS MCP coverage through the existing catalog path.

Problems

  • optional-mcps/apple-{mail,notes,numbers,photos}/manifest.yaml uses bare npx -y <package> arguments (for example apple-mail:24). Current catalog policy requires pinned transport details and says MCPs are never auto-updated (hermes_cli/mcp_catalog.py:13-15), while the security-audit test documents that bare npx packages resolve latest and are not auditable (tests/hermes_cli/test_security_audit.py:76-78). Pin each package to the exact version validated on macOS.
  • apple-mail documents destructive mail operations but has no tools.default_enabled. If probing fails, the installer intentionally writes no filter and all tools become enabled later (hermes_cli/mcp_catalog.py:554-583); non-TTY installs do the same (:604-615). Add a read-only default allow-list so the advertised safe pruning also holds on those paths.

Suggested changes

  • Use versioned npx package specs and add a catalog regression test for pinned/auditable npx arguments.
  • Add conservative default tool lists for mutation-capable entries.

Automated hermes-sweeper review.

auth:
type: none

post_install: |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pin this npx package to the exact macOS-validated version (and do the same for the other three manifests). Bare npx packages resolve latest at runtime, contrary to the catalog's no-auto-update contract, and current MCP dependency auditing intentionally cannot identify unversioned packages.

Comment thread optional-mcps/apple-mail/manifest.yaml Outdated
Requires macOS — the server controls Apple Mail via AppleScript and will
prompt for Automation access to Mail on first use. It exposes send / reply /
forward / delete / move tools that act on your real mailbox; the install-time
checklist lets you prune those if you want a read-only surface.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tools.default_enabled containing only the intended read-only tools. With no manifest default, a probe failure or non-TTY install writes no filter and enables every tool later (hermes_cli/mcp_catalog.py:554-583,604-615), including the send/delete/move operations documented below.

@sweetrb

sweetrb commented Jul 15, 2026

Copy link
Copy Markdown
Author

Both review points addressed in af7101d:

  • Version pins: all four npx specs now pin the exact macOS-validated versions (apple-mail-mcp@2.8.6, apple-notes-mcp@2.5.12, apple-numbers-mcp@1.1.7, apple-photos-mcp@2.1.0) — each was validated end-to-end on macOS 26 against real Mail/Notes/Numbers/Photos data this week. Pin bumps will come via PR after re-validating, per the no-auto-update policy.
  • tools.default_enabled: all four manifests now ship conservative read-only allow-lists, so the probe-failure and non-TTY install paths (mcp_catalog.py:554-583,604-615) yield a non-mutating surface. apple-mail's default is browse/search/read/diagnostics only — send/reply/forward/delete/move/flag/rule/template mutations all require explicit opt-in. apple-photos' mutation tools are additionally gated server-side behind APPLE_PHOTOS_MCP_ENABLE_WRITES, so both switches must be on before anything can write.
  • Regression test: added TestShippedCatalog::test_npx_uvx_packages_are_version_pinned — every npx/uvx catalog entry must be parseable by security_audit._extract_mcp_component into a (name, version) component, tying the pin policy directly to the audit's own parser. Verified it fails on a bare spec and passes on the pinned manifests.
  • post_install texts updated to describe the read-only default posture.

sweetrb added 2 commits July 15, 2026 10:59
…ists

Address hermes-sweeper review on NousResearch#51466:
- Pin all four npx packages to the exact macOS-validated versions
  (apple-mail-mcp@2.8.6, apple-notes-mcp@2.5.12, apple-numbers-mcp@1.1.7,
  apple-photos-mcp@2.1.0) per the catalog's no-auto-update policy; bare
  specs resolve 'latest' and are invisible to the security audit. Pins
  satisfy the catalog-wide exact-pin enforcement landed in 9df5f87.
- Add tools.default_enabled read-only allow-lists to all four manifests so
  a failed tool probe or non-TTY install yields a safe, non-mutating
  surface (mail: browse/search/read/diagnostics only; notes/numbers: reads;
  photos: reads — its write tools are additionally env-gated server-side).
- Update post_install texts to describe the read-only default posture.

Host: robs-work-mbpromax
@sweetrb
sweetrb force-pushed the add-apple-macos-mcp-servers branch from af7101d to 503a31e Compare July 15, 2026 15:01
@sweetrb

sweetrb commented Jul 15, 2026

Copy link
Copy Markdown
Author

Rebased onto current main — the branch had gone conflicting after 9df5f87 (catalog-wide exact-pin enforcement) landed. Since that commit ships a stricter version of the regression test I'd added (it also rejects dist-tags and ranges), I dropped mine in favor of yours; the four pinned manifests pass TestShippedCatalog including the new exact-pin test. Net diff is now the four manifests only: pinned versions + tools.default_enabled read-only defaults + updated post_install texts.

…eases

The pins added in 503a31e have aged out while this PR was in review:

  apple-mail-mcp     2.8.6   -> 2.9.1
  apple-notes-mcp    2.5.12  -> 2.6.11
  apple-numbers-mcp  1.1.7   -> 1.1.10
  apple-photos-mcp   2.1.0   -> 2.1.5

The mail pin is the one that matters: 2.8.6 predates 2.8.16, which fixed an
IMAP socket leak where dropPool left ESTABLISHED connections behind and
eventually tripped Gmail's per-account simultaneous-connection cap. Merging
the old pin would have shipped that to every Hermes user who enabled the
entry.

Each version was validated on macOS before pinning: `npx -y <pkg>@<ver>`
boots, completes an MCP initialize handshake reporting the matching
serverInfo version, and returns a full tools/list with every tool described
(mail 50, notes 36, numbers 26, photos 21).

The read-only `tools.default_enabled` allow-lists are unchanged and were
re-verified against the new tool surfaces — every allow-listed name still
resolves in the version now pinned. New tools added since the old pins are
excluded by default, which is the intended behavior of a positive allow-list.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Aug 1, 2026

Copy link
Copy Markdown
Author

Refreshed the version pins in 92f0b20 — the ones from 503a31e have aged out during review:

package was now
apple-mail-mcp 2.8.6 2.9.1
apple-notes-mcp 2.5.12 2.6.11
apple-numbers-mcp 1.1.7 1.1.10
apple-photos-mcp 2.1.0 2.1.5

The mail pin is the one worth flagging: 2.8.6 predates 2.8.16, which fixed an IMAP socket leak where dropPool left ESTABLISHED connections behind and eventually tripped Gmail's per-account simultaneous-connection cap. Merging as-pinned would have shipped that to anyone who enabled the entry, so this is a correctness fix rather than routine version churn.

Validation for each new pin, on macOS: npx -y <pkg>@<ver> boots, completes an MCP initialize handshake reporting the matching serverInfo version, and returns a full tools/list with every tool carrying a description — mail 50, notes 36, numbers 26, photos 21.

The read-only tools.default_enabled allow-lists are unchanged. I re-verified every allow-listed name against the new tool surfaces and all of them still resolve, so no entry went stale across the bump. Tools added since the old pins are excluded by default, which is the positive allow-list behaving as intended — I deliberately did not widen the default surface without your call on it.

tests/hermes_cli/test_mcp_catalog.py and tests/hermes_cli/test_security_audit.py pass (65 passed), including test_all_shipped_manifests_are_version_locked.

Happy to re-pin again if this sits longer — just say the word rather than merging a stale pin.

2.6.11 predates a silent data-loss fix in export-notes-json: notes sharing
an exact title collapsed to one repeated note, with the others absent and
no error or count mismatch. Verified on a 359-note library — 2.6.11 exported
359 entries carrying only 351 distinct ids (8 notes lost); 2.6.12 exports
359 for 359.

Validated on macOS per catalog policy: npx -y apple-notes-mcp@2.6.12 boots,
completes an MCP initialize handshake reporting serverInfo.version 2.6.12,
and returns 36 tools each carrying a description. All 20 tools.default_enabled
entries still resolve against the new surface, so no allow-listed name went
stale; the 16 tools outside the allow-list stay disabled by design.

Host: robs-homeoffice-mbpromax
@sweetrb

sweetrb commented Aug 1, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-notes-mcp in 7162aa5 — 2.6.11 → 2.6.12. The other three pins (apple-mail-mcp@2.9.1, apple-numbers-mcp@1.1.10, apple-photos-mcp@2.1.5) are still the current releases and are unchanged.

This one is worth flagging rather than treating as routine churn, same as the mail pin last time: 2.6.11 predates a silent data-loss fix. export-notes-json re-fetched each note by title, and AppleScript's note "<name>" specifier resolves an ambiguous (duplicated) name deterministically to the same match — so any set of N notes sharing an exact title exported as one note repeated N times, with the other N−1 simply absent. No error, no warning, and the reported total stayed internally consistent, so nothing surfaced the loss.

Measured on a real 359-note library:

version exported entries distinct ids
2.6.11 359 351 — 8 notes silently missing
2.6.12 359 359

Merging the old pin would have shipped that to anyone enabling the entry.

Validation for the new pin, on macOS, per the catalog's "version validated on macOS" policy: npx -y apple-notes-mcp@2.6.12 boots, completes an MCP initialize handshake reporting serverInfo.version 2.6.12, and returns a full tools/list of 36 tools, every one carrying a description.

The read-only tools.default_enabled allow-list is unchanged. I re-verified all 20 entries against the new tool surface and every one still resolves, so nothing went stale across the bump. The 16 tools outside the allow-list remain disabled — that's the positive allow-list behaving as intended, and I've again deliberately not widened the default surface without your call.

tests/hermes_cli/test_mcp_catalog.py and tests/hermes_cli/test_security_audit.py pass (65 passed), including test_all_shipped_manifests_are_version_locked.

Net diff is still the four manifests only. Happy to re-pin again if this sits longer — just say the word rather than merging a stale pin.

apple-mail-mcp  2.9.1  -> 2.10.3
apple-notes-mcp 2.6.12 -> 2.6.13
apple-numbers-mcp 1.1.10 -> 1.1.11
apple-photos-mcp  2.1.5 -> 2.1.6

The mail pin is the one worth flagging: 2.9.1 predates 2.10.2, which floors
fast-uri and ip-address. Both are inlined into the shipped bundle and carried
high-severity advisories (GHSA-7p8r-x3mc-p8w7, GHSA-mwp4-54f8-5fhr), so merging
as-pinned would have shipped them.

Validated on macOS per catalog policy: npx -y <pkg>@<ver> boots, completes an
MCP initialize handshake reporting the matching serverInfo.version, and returns
a full tools/list with every tool carrying a description — mail 50, notes 36,
numbers 26, photos 21.

tools.default_enabled is unchanged in all four. Every allow-listed name still
resolves against the new surfaces (18/20/7/13), so nothing went stale across the
bump, and no newly added tool was pulled into a default surface.

tests/hermes_cli/test_mcp_catalog.py and test_security_audit.py pass (65).

Host: robs-homeoffice-mbpromax
@sweetrb

sweetrb commented Aug 4, 2026

Copy link
Copy Markdown
Author

Refreshed all four pins — the previous set has aged out during review.

package was now
apple-mail-mcp 2.9.1 2.10.3
apple-notes-mcp 2.6.12 2.6.13
apple-numbers-mcp 1.1.10 1.1.11
apple-photos-mcp 2.1.5 2.1.6

The mail pin is the one that matters. 2.9.1 predates 2.10.2, which floors two transitive dependencies that are inlined into the shipped bundle and both carried high-severity advisories:

Merging the old pin would have shipped both to anyone who enabled the entry, so this is a correctness fix rather than routine version churn. (The cause is worth knowing if you carry similar overrides: the repo's own fast-uri: 3.1.4 override had been written as an exact pin, so when the 3.1.5 fix landed the "floor" was acting as a ceiling and the advisory could never clear.)

The other three are documentation-accuracy releases from a full audit of every doc surface against the live tool inventory — notably a search-contacts handler that had always discarded the phone numbers its own description promised, and a numbers backend split that told users they needed Numbers.app plus an Automation grant to write a cell value when those tools run entirely on the Python sidecar.

Validation for each new pin, on macOS, per the catalog's "version validated on macOS" policy: npx -y <pkg>@<ver> boots, completes an MCP initialize handshake reporting the matching serverInfo.version, and returns a full tools/list with every tool carrying a description — mail 50, notes 36, numbers 26, photos 21 (all unchanged from the previous pins, so no tool was added or removed).

tools.default_enabled is unchanged in all four. I re-verified every allow-listed name against the new surfaces — 18 / 20 / 7 / 13, all still resolving — so nothing went stale across the bump, and no newly added tool was silently pulled into a default surface.

tests/hermes_cli/test_mcp_catalog.py and tests/hermes_cli/test_security_audit.py pass (65 passed), including test_all_shipped_manifests_are_version_locked.

Net diff remains the four manifests only. Happy to re-pin again if this sits longer — just say the word rather than merging a stale pin.

apple-mail-mcp  2.10.3 -> 2.10.4
apple-notes-mcp 2.6.13 -> 2.6.14
apple-numbers-mcp 1.1.11 -> 1.1.12
apple-photos-mcp  2.1.6 -> 2.1.7

These clear every open advisory across the four servers: fast-uri
(GHSA-7p8r-x3mc-p8w7, high), ip-address (GHSA-mwp4-54f8-5fhr, high, + two
moderate), hono (GHSA-8j4g-w8fx-2239) and postcss. fast-uri is inlined into the
shipped bundles, so the earlier pins carried it. pnpm audit now reports no known
vulnerabilities in all four.

Validated on macOS per catalog policy: each version boots under npx, completes
an MCP initialize handshake reporting the matching serverInfo.version, and
returns a full tools/list with every tool described — 50/36/26/21, unchanged.
tools.default_enabled is unchanged and every allow-listed name still resolves.

tests/hermes_cli/test_mcp_catalog.py + test_security_audit.py pass (65).

Host: robs-homeoffice-mbpromax
@sweetrb

sweetrb commented Aug 4, 2026

Copy link
Copy Markdown
Author

Re-pinned once more — these are security releases, so worth flagging rather than letting the earlier pins ride.

package was now
apple-mail-mcp 2.10.3 2.10.4
apple-notes-mcp 2.6.13 2.6.14
apple-numbers-mcp 1.1.11 1.1.12
apple-photos-mcp 2.1.6 2.1.7

Between them these clear every open advisory across all four servers — pnpm audit now reports no known vulnerabilities in each:

If you carry similar transitive overrides, the fast-uri cause may be worth knowing: three of the four repos had fast-uri: 3.1.4 written as a security floor but as an exact pin, so when the 3.1.5 fix landed the override was acting as a ceiling and the advisory could never clear — Dependabot couldn't route around it either, since the override wins. They're caret ranges now.

hono was deliberately deferred for a day: the fix release was inside our 24-hour minimumReleaseAge soak (one repo missed the cutoff by 2m36s). No minimumReleaseAgeExclude carve-out was added at any point — hono isn't in the shipped bundles, so nothing vulnerable shipped while it waited.

Validation per the catalog's "version validated on macOS" policy, for each new pin: npx -y <pkg>@<ver> boots, completes an MCP initialize handshake reporting the matching serverInfo.version, and returns a full tools/list with every tool carrying a description — 50 / 36 / 26 / 21, unchanged from the previous pins.

tools.default_enabled is unchanged in all four, and every allow-listed name still resolves against the new surfaces, so nothing went stale.

tests/hermes_cli/test_mcp_catalog.py and test_security_audit.py pass (65 passed). Net diff is still the four manifests only.

…p detection fix

1.1.12 predates 1.1.13, which fixes a macOS-visible defect this manifest's
own post_install text depends on: doctor reported "Numbers.app not found"
on every Mac that had taken Apple's 2026 rename, because the check tested
the hard-coded /Applications/Numbers.app path. The AppleScript formula and
formatting tools therefore looked unavailable on an up-to-date machine --
exactly the surface post_install tells users to enable.

Deliberately NOT bumped to 1.1.14 (latest). 1.1.14 is a dependency-only
Dependabot bump published today, so it buys nothing here and is strictly
worse against the catalog's 2-week pin-age rule. Same reasoning leaves the
other three pins alone: apple-mail-mcp@2.10.4, apple-notes-mcp@2.6.14 and
apple-photos-mcp@2.1.7 already carry every security and correctness fix,
and their newer releases are deps-only.

Validated 1.1.13 per catalog policy: npm-installed the published artifact,
drove an MCP initialize handshake (serverInfo.version == 1.1.13,
protocolVersion 2025-06-18), and confirmed tools/list returns the full
26-tool surface. Re-checked every tools.default_enabled entry against that
surface -- all 7 resolve, none is mutating, and the 19 write/format tools
stay disabled. tests/hermes_cli/test_mcp_catalog.py: 39 passed.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Aug 5, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-numbers — and this round I want to flag a policy tension rather than keep quietly bumping pins.

The one pin change

package was now why
apple-numbers-mcp 1.1.12 1.1.13 doctor reported Numbers.app not found on every Mac that had taken Apple's 2026 rename — the check tested the hard-coded /Applications/Numbers.app path. So the AppleScript formula/formatting tools looked unavailable on an up-to-date machine, which is precisely the surface this manifest's post_install tells users they can enable.

The other three are unchanged — apple-mail-mcp@2.10.4, apple-notes-mcp@2.6.14, apple-photos-mcp@2.1.7.

Validated 1.1.13 per catalog policy: installed the published artifact, drove an MCP initialize handshake (serverInfo.version == 1.1.13, protocolVersion 2025-06-18), confirmed tools/list returns the full 26-tool surface, and re-checked every tools.default_enabled entry against it — all 7 resolve, none is mutating, and the 19 write/format tools stay disabled. tests/hermes_cli/test_mcp_catalog.py: 39 passed.

The tension: I have been violating your 2-week pin-age rule

mcp_catalog.py:13-19 says pins should be "at least 2 weeks old at pin time". It arrived in 9df5f87, the same commit that added the exact-pin enforcement I rebased onto — so it has been in force since 2026-07-15, and I did not honour it in the 08-01 or 08-04 re-pins. Those went to same-day releases. That is on me.

The reason it kept happening is that the rule and the security posture are in direct conflict for these four packages right now. Newest release that is ≥14 days old today, versus what it would ship:

package newest ≥14d what pinning it would reintroduce
apple-mail-mcp 2.8.13 (Jul 21) the pre-2.8.16 IMAP socket leak that trips Gmail's per-account connection cap, and the pre-2.10.2 fast-uri GHSA-7p8r-x3mc-p8w7 / ip-address GHSA-mwp4-54f8-5fhr (both high, both inlined into the shipped bundle)
apple-notes-mcp 2.6.8 (Jul 21) the export-notes-json silent data-loss bug (duplicate-titled notes exported as one note repeated) plus the same two high advisories
apple-numbers-mcp 1.1.9 (Jul 21) the same two high advisories
apple-photos-mcp 2.1.3 (Jul 21) the same two high advisories

There is no version of any of the four that is both ≥14 days old and free of known advisories — the fixes landed 2026-08-03/04. Strict compliance today means knowingly shipping high-severity vulnerabilities in the bundle; compliance-by-waiting means the pins go stale again the moment the next fix lands.

I am not going to resolve that unilaterally in your repo, so: how do you want it handled? Three options I can see, happy to implement whichever you pick (or something else):

  1. Waive the age rule for first-party, provenance-signed packages. All four publish tokenless via npm OIDC Trusted Publishing with --provenance, so the attestation chain back to the GitHub Actions run is verifiable — which is the specific supply-chain risk the soak window exists to cover. Would want the carve-out written into the policy rather than left implicit.
  2. Keep the rule and accept the lag. I re-pin only on a ≥14-day cadence and this PR pins the Jul 21 set, with the known advisories documented in each post_install. I think this is the worst option for your users, but it is self-consistent.
  3. Merge at the current pins and let the age clock start from merge. The four pinned versions are all security-complete as of today; I stop chasing every patch and only re-pin for a genuine security or correctness regression (which is what this commit does).

My preference is 1, falling back to 3.

One process note either way: these have now been re-pinned four times across three weeks of review, and each round has been a real fix rather than churn — the 08-01 round caught a pin predating the Gmail connection-cap fix, 08-04 caught one predating two high advisories, this one catches the Numbers.app detection bug. That pattern is a symptom of the pins aging faster than review, so whichever option you choose, it is worth deciding it before merge rather than after.

get-mail-stats is in this entry's default_enabled allow-list, and on 2.10.4 it
fails on every call path for anyone with IMAP configured: scoped calls are
rejected client-side with -32602 (the tool emits a field its advertised
outputSchema didn't enumerate, and a bare zod shape renders as
additionalProperties:false), unscoped calls time out because the all-accounts
fan-out counted accounts sequentially. Both fixed in 2.10.6
(sweetrb/apple-mail-mcp#135).

Validated on macOS per catalog policy: npx -y apple-mail-mcp@2.10.6 completes
the MCP initialize handshake with serverInfo.version 2.10.6, tools/list returns
all 50 tools each with a description, and all 16 default_enabled entries still
resolve against the new surface (no renames). Newly added tools are left out of
the allow-list deliberately.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Aug 6, 2026 •

Copy link
Copy Markdown
Author

Re-pinned apple-mail from 2.10.4 to 2.10.6, because 2.10.4 ships a tool in this entry's own default_enabled allow-list that is broken on every call path.

get-mail-stats on 2.10.4:

  • scoped (account given) → client-side -32602 … data must NOT have additional properties. The handler emits a field its advertised outputSchema never enumerated, and a bare zod raw shape renders as additionalProperties: false, so the client discards a correct result.
  • unscoped → -32001 timeout. The all-accounts path counted accounts sequentially, so wall clock was the sum over every account, each costing one IMAP STATUS per mailbox.

Both fixed in 2.10.6 (sweetrb/apple-mail-mcp#135, reported by a user hitting it on a four-account setup). Since the entry advertises get-mail-stats as part of its safe read-only default surface, leaving the pin at 2.10.4 would ship a tool that cannot succeed for IMAP users.

Validated on macOS per the catalog policy before re-pinning: npx -y apple-mail-mcp@2.10.6 completes the initialize handshake with serverInfo.version 2.10.6; tools/list returns all 50 tools, each with a description; and all 16 default_enabled entries still resolve against the new surface, so nothing silently dropped out of the default set from a rename. Newly added tools are deliberately left out of the allow-list — widening the default surface isn't mine to decide here. tests/hermes_cli/test_mcp_catalog.py (39) and test_security_audit.py (26) both pass against the updated manifest.

The other three pins (apple-notes-mcp@2.6.14, apple-numbers-mcp@1.1.13, apple-photos-mcp@2.1.7) are unchanged on purpose — their newer releases are dependency-only or fix latent issues that don't affect any allow-listed tool, and a release landing on npm isn't by itself a reason to move a pin.

Still open from my last comment: the ≥2-weeks-old pin rule in hermes_cli/mcp_catalog.py:13-19 versus shipping known-broken or advisory-carrying versions. This bump runs into it again — 2.10.6 is new, but the only alternative is pinning a version whose advertised read-only tool fails 100% of the time. I've applied the same tiebreak as before (pick the oldest version that is actually correct), but that's your call to make, not mine, and I'm happy to follow whichever of the three options from my earlier comment you prefer.

…ot churn

apple-mail 2.10.6 -> 2.10.8, apple-notes 2.6.14 -> 2.6.16,
apple-numbers 1.1.13 -> 1.1.15, apple-photos 2.1.7 -> 2.1.9.

Every bump fixes a defect in a tool this entry's own default_enabled
allow-list advertises:

- All four: every tool advertised outputSchema additionalProperties:false,
  so any handler emitting an undeclared key had its correct result rejected
  client-side with -32602. Latent in notes/numbers/photos; not latent in
  mail, where it broke get-mail-stats outright.
- apple-mail 2.10.7: IMAP accounts were deduplicated by LABEL, so one
  mailbox declared under two nicknames was counted twice -- get-unread-count
  reported 23 against a true 15. Both tools are allow-listed here.
- apple-mail 2.10.8: get-mail-stats with no account could still die as a
  bare -32001 returning nothing, because the per-account budget never
  covered the Mail.app account enumeration that precedes the fan-out.

The deps-only releases in between (notes 2.6.15, numbers 1.1.14,
photos 2.1.8) are deliberately skipped -- a release landing on npm is not
by itself a reason to move a pin.

Validated each new pin on macOS per catalog policy: npx -y <pkg>@<ver>
boots, initialize reports the matching serverInfo.version, and tools/list
returns the full surface with every tool described (50/36/26/21,
unchanged). All 58 default_enabled entries re-verified against the new
surfaces -- every one still resolves, and newly added tools are left out.

tests/hermes_cli/test_mcp_catalog.py (39) and test_security_audit.py (26)
pass.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Aug 7, 2026

Copy link
Copy Markdown
Author

Re-pinned all four in fb84f91. Every one of these is a defect in a tool this entry's own default_enabled allow-list advertises, so I'd rather flag them than let them ride.

package was now
apple-mail-mcp 2.10.6 2.10.8
apple-notes-mcp 2.6.14 2.6.16
apple-numbers-mcp 1.1.13 1.1.15
apple-photos-mcp 2.1.7 2.1.9

All four — advertised output schemas rejected undeclared keys. The MCP client validates structuredContent against the schema the server advertised, and a bare zod raw shape renders as additionalProperties: false. So any field a handler emitted that its schema didn't enumerate was a hard client-side -32602, discarding a result the handler had computed correctly. The server never noticed, because zod's own parse strips unknown keys rather than failing — which is why the earlier "all fields optional, no .strict()" migration read as permissive: it covered optionality, not undeclared keys. Latent in notes/numbers/photos; not latent in mail, where it broke get-mail-stats on every call.

apple-mail 2.10.7 — silent double-counting. IMAP accounts were deduplicated by label, so one mailbox declared under two nicknames produced two account specs and every fan-out tool visited it twice. Measured: get-unread-count reported 23 against a true 15, and get-mail-stats inflated both totals the same way. Both tools are allow-listed here, and a wrong count reads as a real answer.

apple-mail 2.10.8 — get-mail-stats could still return nothing. The per-account budget added in 2.10.6 never covered the Mail.app account enumeration that runs before the fan-out, so the worst case was their sum and the call died as a bare -32001 with no partial result. Now bounded by a single wall-clock deadline for the whole call.

Deliberately skipped: apple-notes-mcp@2.6.15, apple-numbers-mcp@1.1.14, apple-photos-mcp@2.1.8 — dependency-only. A release landing on npm isn't by itself a reason to move a pin.

Validation per the catalog's "version validated on macOS" policy, for each new pin: npx -y <pkg>@<ver> boots, completes an initialize handshake reporting the matching serverInfo.version, and returns a full tools/list with every tool carrying a description — 50 / 36 / 26 / 21, unchanged from the previous pins, so no tool was added or removed.

tools.default_enabled is unchanged in all four. I re-verified all 58 allow-listed names against the new surfaces (18 / 20 / 7 / 13) — every one still resolves, so nothing went stale across the bump. Tools added since remain outside the allow-list; widening your default surface still isn't mine to decide.

tests/hermes_cli/test_mcp_catalog.py (39) and test_security_audit.py (26) pass. Net diff is still the four manifests only.

Still open from my earlier comments: the ≥2-weeks-old pin rule (hermes_cli/mcp_catalog.py:13-19) versus shipping versions with known defects in allow-listed tools. I've applied the same tiebreak as before — the oldest version that is actually correct — but that's your call, and I'm happy to implement whichever of the three options you prefer. This is the fifth re-pin in three weeks and each has been a real fix rather than churn, so it's worth settling before merge rather than after.

…s the call

2.10.8's overall deadline for get-mail-stats did not cover time the call
spent queued behind other tool calls, so a concurrent caller could see a
call outlive the deadline entirely and report complete data (measured:
15.9s against a 6s deadline). get-mail-stats is in this entry's own
default_enabled allow-list, so the stale pin ships that to anyone enabling
it. 2.10.9 anchors the deadline at request arrival.

The other three pins are unchanged and still current.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Aug 8, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-mail from 2.10.8 to 2.10.9 in 67719a9. Same reason as the last few rounds: it is a defect in a tool this entry's own default_enabled allow-list advertises, not routine churn.

get-mail-stats on 2.10.8: the overall wall-clock deadline added in 2.10.8 (APPLE_MAIL_MCP_STATS_DEADLINE_MS) still did not bound the call. Tool calls are serialized so they cannot race into Mail.app's single-threaded AppleScript dispatch, but the deadline clock started on the handler's first line — which runs only once that queue releases — so a call measured its own execution and none of its wait. Measured on 3 IMAP accounts: three concurrent calls returned at 5.5s / 10.3s / 15.9s with the deadline set to 6s, the last one still reporting partial: false. A caller issuing these concurrently could therefore blow through its own request timeout with no partial result and nothing naming a cause. 2.10.9 anchors the deadline at request arrival, so the same case bounds at 5.8s and a queued-out call says so.

The other three pins are unchanged and still current releases — apple-notes-mcp@2.6.16, apple-numbers-mcp@1.1.15, apple-photos-mcp@2.1.9.

Validated on macOS per the catalog's "version validated on macOS" policy: npx -y apple-mail-mcp@2.10.9 boots, completes an MCP initialize handshake reporting serverInfo.version 2.10.9, and returns a full tools/list of 50 tools, every one carrying a description — unchanged from the previous pin, so no tool was added or removed. All 18 default_enabled entries re-verified against the new surface: every one still resolves, so nothing went stale across the bump, and no newly added tool was pulled into the default surface.

tests/hermes_cli/test_mcp_catalog.py and test_security_audit.py pass (65 passed), including test_all_shipped_manifests_are_version_locked. Net diff is still the four manifests only.

Still open from my earlier comments: the ≥2-weeks-old pin rule (hermes_cli/mcp_catalog.py:13-19) versus shipping a version with a known defect in an allow-listed tool. Same tiebreak applied as before — the oldest version that is actually correct — and it is still your call, not mine; happy to implement whichever of the three options you prefer. This is the sixth re-pin, and each has been a real fix, which is the symptom I flagged earlier: the pins age faster than the review. Worth settling before merge rather than after.

… shape changed

apple-notes-mcp 2.6.16 -> 2.7.0. Flagging rather than quietly bumping,
because this one changes a tool in this entry's own default_enabled
allow-list rather than fixing a defect behind it.

`list-notes` now returns `notes: Array<{title, id}>` where it returned
`string[]`. The reason is an identity bug: AppleScript's `note "<name>"`
specifier resolves a duplicated title to the same one note every time, so
anything that listed titles and then re-resolved each one by title silently
fetched one note twice and never reached the other. Ids in the listing close
that. The human-readable line is now `  - <title> [id: <id>]`, matching
`search-notes`.

Validated on macOS per catalog policy: `npx -y apple-notes-mcp@2.7.0`,
MCP initialize handshake returns serverInfo.version 2.7.0, tools/list
returns all 36 tools, and all 20 default_enabled entries still resolve —
no renames, nothing dropped. Guard tests pass (tests/hermes_cli/
test_mcp_catalog.py 39 passed, tests/ci/test_classify_changes.py 21 passed).

default_enabled is unchanged: 2.7.0 adds no tools, and widening this entry's
default surface isn't mine to decide.

Host: robs-homeoffice-mbpromax
@sweetrb

sweetrb commented Sep 23, 2026

Copy link
Copy Markdown
Author

Pin refresh, 2026-09-23. notes 2.8.13 → 2.8.49 in a863320. Mail, numbers, and photos pins are unchanged.

This is the same carve-out as 2.8.11 and 2.8.13: defects in default_enabled tools, so the pin moves ahead of the age policy (sweetrb/apple-notes-mcp):

Changes outside the default surface are listed in the manifest comment: the readback entity-decoding fix (#211), and fail-closed Recently Deleted guards on delete-note (#198, #214).

Validated on macOS per catalog policy: npx -y apple-notes-mcp@2.8.49 completes the initialize handshake reporting serverInfo.version 2.8.49. tools/list returns 66 tools, every one with a description (15 added, none removed), and all 20 default_enabled entries resolve. tests/hermes_cli/test_mcp_catalog.py passes 39/39. Nothing was added to default_enabled.

get-note-content (default_enabled) failed outright on notes with a large
embedded image; 2.9.12 raises the AppleScript output cap from 64MB to 512MB
so the read succeeds. Validated: initialize handshake reports 2.9.12, 77
tools, all 20 default_enabled entries resolve. test_mcp_catalog.py 39/39.
@sweetrb

sweetrb commented Sep 25, 2026

Copy link
Copy Markdown
Author

Re-pinned `apple-notes-mcp` `2.8.49` → `2.9.12`: `get-note-content` (a default_enabled tool) failed outright on notes with a large embedded image — the AppleScript output cap was 64MB against a ~110MB body. 2.9.12 raises that cap to 512MB, so the read now succeeds instead of erroring (#237/#242 upstream). Nothing else in the 2.9.x line so far touches a default_enabled tool as a defect fix — a few additive JSON fields elsewhere (search-notes, list-folders, list-attachments), no behavior removed.

Validated on macOS: initialize handshake reports 2.9.12, tools/list returns 77 tools (11 more than the previous pin, all new ones correctly left out of default_enabled), all 20 default_enabled entries still resolve. test_mcp_catalog.py 39/39 green.

mail (2.19.14), numbers (1.2.2), photos (2.1.12) pins re-checked this round — all still current or their newer npm releases carry nothing default_enabled needs.

@Enough1122

Copy link
Copy Markdown

Re-checked at head ee15834a. The pin move itself is solid: optional-mcps/apple-notes/manifest.yaml:120 now pins apple-notes-mcp@2.9.12, and the stated reason holds in the upstream source — at v2.8.49 the body read went through the general 64 MB cap (src/utils/applescript.ts:30, src/services/appleNotesManager.ts:1474), and at v2.9.12 it passes noteBodyMaxBuffer() (appleNotesManager.ts:1561, 512 MB at applescript.ts:64). That is the #237/#246 fix. Static extraction from both published builds matches your numbers: 66 → 77 tools, 11 added, none removed, all 20 default_enabled names present at each. Same for the other three: 52/18 mail, 26/6 numbers, 21/13 photos, no drift.

One statement in the manifest is not accurate, and I'd fix it before merge. manifest.yaml:97-98 says "Nothing else in 2.9.1-2.9.30 touches a default_enabled tool as a defect fix," then lists 2.9.14/2.9.18/2.9.27 as additive. I pulled the upstream CHANGELOG and 2.9.25 contradicts it:

Error codes no longer depend on words inside a note title. Classification matched the whole message, and messages quote the title, so a missing note titled "Meeting timed out" came back as timeout_indeterminate with indeterminate: true […] the note-not-found responses in src/index.ts set not_found directly, and the AppleScript error mapping no longer reads a title such as "Lost connection plan" or "Access denied log" as a dropped connection or a permission refusal (#185).

That is a behaviour change on the default surface, not an additive JSON field. Cross-checking the manifest's own default_enabled list (manifest.yaml:139-158), it lands on seven tools that are enabled by default here: get-note-content, get-note-by-id, get-note-details, get-note-plaintext, get-checklist-state, get-note-markdown, list-attachments. Any caller keying off code/indeterminate on those sees different answers before and after the pin — in the safer direction, but different.

This doesn't argue against the pin; 2.9.25 is a fix worth having. It argues against the manifest asserting no other default-surface behaviour changed in that range, because that's the sentence a future reader will rely on when deciding whether a future bump is safe.

Second, smaller: the notes for numbers 1.2.3 (manifest.yaml:30) and photos 2.1.13 present them as cosmetic. Both releases also carry a transitive qs security override (#77 / #84) plus hono/js-yaml floors. Declining them under the defect-only carve-out is your call; describing them as carrying nothing isn't quite right.

I could not verify the pre-flight logs (they're on your side, not in the repo). I also did not run test_mcp_catalog.py myself — I took the tool-count extraction from the published tarballs rather than re-running it.

…eleases

Addresses review on NousResearch#51466.

- apple-notes: drop the claim that nothing else in 2.9.1-2.9.30 touches a
  default_enabled tool. 2.9.25 (NousResearch#185, NousResearch#190) changes error classification on
  seven default-enabled read tools. That is a behaviour change, in the safer
  direction. It is newer than the 2.9.12 pin, so the pinned surface is
  unaffected, and a future bump past it must account for it. Also notes
  2.9.27's change to the opt-in search-notes wordCount.
- apple-numbers 1.2.3 / apple-photos 2.1.13: described as declined under the
  defect-only carve-out, not as cosmetic. Both carry a transitive qs security
  override (numbers#77, photos#84) and hono/js-yaml floors (numbers#80,
  photos#85), and photos 2.1.13 adds an opt-in SWR cache.
- apple-mail: 2.19.7 and 2.19.9 do touch default_enabled tools (additively),
  2.19.12 was unlisted, and mail#246 is closed, not reopened.

No pin changes.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Sep 25, 2026

Copy link
Copy Markdown
Author

@Enough1122, thank you for pulling the 2.9.25 CHANGELOG entry and checking it against the manifest's own default_enabled list. You're right: that sentence is the one a future bump would rely on, and it was wrong. Fixed in 77e07ca9. There are no pin changes, and test_mcp_catalog.py passes 39/39.

  • notes: removed the "nothing else in 2.9.1–2.9.30" claim. The comment now covers only what the 2.9.12 pin contains. It adds a separate "newer than this pin" block that names 2.9.25 as a behaviour change on the default surface, in the safer direction. That covers toolset check exception handling + empty choices in context compressor #185 (quoted titles no longer drive timeout_indeterminate / connection / permission, and not-found sets not_found directly) and feat: add vibe_check tool for system & project health diagnostics #190 (unresolvable ids keep a coded error). It lists the seven tools you found and says a bump past 2.9.25 must account for them. The same block records a smaller change you didn't raise: 2.9.27 changes the opt-in search-notes wordCount (fix: copy conversation_history to prevent caller list mutation #244). The pin stays at 2.9.12 because 2.9.25 is newer, so the pinned surface doesn't include it. 2.9.25 would qualify under the carve-out, but the carve-out allows a re-pin; it doesn't require one. I'd rather take it in a later bump that has been validated separately.
  • numbers 1.2.3 / photos 2.1.13: these are now described as declined under the defect-only carve-out, not as carrying nothing. Each note names the qs override (numbers#77, photos#84) and the hono/js-yaml floors (numbers#80, photos#85), plus photos' opt-in SWR cache. I checked the published tarballs. Those dependency changes live in the pnpm workspace and lockfile. In the shipped packages, numbers' build/index.js differs only by esbuild renumbering, photos' is byte-identical, and neither package's runtime dependency ranges changed.
  • mail: I checked it the same way and it had the same kind of error. 2.19.7 (dateSent on AppleScript rows) and 2.19.9 (optional body on search-messages) do touch default-enabled tools, additively. 2.19.12 wasn't listed. The note also still called mail#246 reopened, but it was closed as completed on 09-23. All three are corrected.

New head: 77e07ca9a7b95825249cf0a7995c9bea1516fa35.

@Enough1122

Copy link
Copy Markdown

AI code review — automated follow-up for reference; not a maintainer.

Checked the new head 77e07ca9. Both corrections landed, and the second one is better than what I asked for.

The 2.9.25 claim is gone — "nothing else in 2.9.1–2.9.30 touches a default_enabled tool as a defect fix" no longer appears. In its place the new "Newer than this pin, so NOT in the pinned surface" block does the useful thing: it names 2.9.25 as a behaviour change on the default surface, cites #185 and #190, and lists the seven affected default-enabled tools. That is exactly the sentence a future bump decision needs, and it's now scoped to the pin rather than asserting a negative about a range.

You also caught 2.9.27's opt-in search-notes wordCount (#244), which I missed. Two things I did raise, both fixed as described: the numbers/photos notes now read as declined under the defect-only carve-out with the qs override and hono/js-yaml floors named, rather than "carrying nothing"; and mail is corrected the same way, with 2.19.7 / 2.19.9 flagged as touching default-enabled tools and #246 no longer described as reopened.

On the 2.9.25 decision itself: keeping the pin at 2.9.12 and taking 2.9.25 in a separately validated bump is the right call. 2.9.25 does qualify under the carve-out, but "allows" and "requires" are different, and taking a behaviour change on seven default tools in the same commit that fixes a different thing would make both harder to review.

One note for the manifest's own consistency: the notes block still reads 2.9.1-2.9.12 the only other default-surface change is 2.9.10's, and the new block covers everything past the pin. Those two sentences are adjacent and a future editor could still read the first as range-wide. Trimming it to up to this pin would remove the ambiguity — cosmetic, your call.

Nothing else from me. This thread looks ready.

apple-mail: 2.19.15 (mailbox-name NFC/NFD matching) and 2.19.16 (iCloud
\Deleted-but-never-expunged messages fabricating search totals) both fix
defects in default_enabled tools (list-messages/search-messages/get-thread),
sweetrb/apple-mail-mcp#246.

apple-notes: 2.9.25 fixes error-code misclassification (note titles
containing words like "timeout"/"denied" were misread as connection/
permission failures) across 7 default_enabled tools, sweetrb/apple-notes-mcp
NousResearch#185/NousResearch#190. Pinned straight to 2.9.30 (current npm), the rest of the range
being additive fields, docs, or non-default-enabled tools.

Both validated on macOS: initialize handshake confirms serverInfo.version,
tools/list count, and all default_enabled entries resolve; 39/39
test_mcp_catalog.py pass.
@sweetrb

sweetrb commented Sep 26, 2026

Copy link
Copy Markdown
Author

Re-pinned two of the four servers (validated on macOS today):

  • apple-mail-mcp 2.19.14 → 2.19.16 — IMAP route inconsistency: list/get-message-rfc822 disagree with direct INBOX sweetrb/apple-mail-mcp#246 (an iCloud account, reported by @j5pu) turned out to have two distinct defects in list-messages/search-messages/get-thread: a mailbox-name NFC/NFD mismatch (2.19.15), then messages flagged \Deleted but never expunged fabricating huge search totals on a filter-less listing (2.19.16). Both clear the catalog's defect-only carve-out.
  • apple-notes-mcp 2.9.12 → 2.9.30 — 2.9.25 fixes error-code misclassification across 7 default_enabled tools (a note titled e.g. "Meeting timed out" or "Access denied log" was misreported as a connection/permission failure instead of a plain read). The rest of the range to 2.9.30 is additive fields, docs, security hardening on non-default-enabled write tools, or a CI-only fix — none of it changes the pinned default surface, so pinning straight to current npm.

apple-numbers-mcp (1.2.2) and apple-photos-mcp (2.1.12) are unchanged — npm-current (1.2.3, 2.1.13) still doesn't clear the carve-out (cosmetic-only, and a fix gated behind an off-by-default flag, respectively).

Both re-pins validated: MCP initialize handshake confirms serverInfo.version, tools/list count, and every default_enabled entry still resolves; test_mcp_catalog.py 39/39.

@Enough1122

Copy link
Copy Markdown

Re-verified at b54a5e0bf9. Both re-pins are correct, and holding the two unchanged servers is the part of this that matters — a catalog that re-pins everything to npm-current on every touch would defeat the defect-only carve-out, and keeping apple-numbers/apple-photos pinned where the carve-out is not satisfied is what proves the rule is being applied rather than rationalised after the fact.

The two held-back pins are the evidence that the carve-out is real. "cosmetic-only" and "a fix gated behind an off-by-default flag" are exactly the two categories the rule excludes, and you checked npm-current (1.2.3, 2.1.13) rather than assuming the pins were still current. If the reason for not bumping were "I did not look", the comment would read differently; naming the specific disqualifying property of each is what makes it checkable.

apple-mail-mcp 2.19.16 clearing two distinct defects is the right basis, and the second one is the better story. The NFC/NFD mailbox-name mismatch (2.19.15) is a correctness bug on a real iCloud account; the \Deleted-flagged-but-never-expunged messages fabricating huge filter-less search totals (2.19.16) is a data-integrity bug that a user would experience as "the search returns nonsense totals" and could not diagnose from the output. Both are in the listing and search tools — the read paths a user actually exercises — and both are defect fixes rather than feature changes, so both clear the carve-out on the rule's own terms.

apple-notes-mcp at 2.9.30, with 2.9.25's fix carried forward — the manifest documents this precisely enough that I checked it specifically and found no gap. I went looking for the version-skew risk here (pinning 2.9.30 while the justifying defect fixed in 2.9.25 is a different number) and the changelog block answers it directly: 2.9.25 changed error classification from whole-message matching to ignoring quoted text, so a note titled "Meeting timed out" no longer returns timeout_indeterminate. That is a behaviour change on the default surface in the safer direction, which is the harder case for a carve-out and the one worth flagging rather than burying — and it is flagged, with the seven affected default-enabled tools named (get-note-content, get-note-by-id, get-note-details, get-note-plaintext, get-checklist-state, get-note-markdown, list-attachments). A caller keying off code / indeterminate gets different, more accurate answers, and someone reading the manifest can find out which.

Two prior behaviour changes are documented in the same style, which is what makes these blocks useful rather than decorative. export-notes-json now pages (first 50 by default, offset / limit max 500 / modifiedSince, with page.nextOffset and hasMore) — a caller expecting the whole library must follow nextOffset. And recently-deleted notes are now excluded by default with excludedRecentlyDeleted counting them, includeRecentlyDeleted: true to list them. Both are on default_enabled tools. Both would change a caller's results silently, and both are written down at the version that introduced them.

The scope accounting is the part I would keep an eye on, since it is where a re-pin usually goes wrong. "20 default_enabled entries, 51 tools" and "77 tools, all 20 default_enabled entries resolve" for the two versions, with 11 tools added since 2.8.49 and none removed — and #181-roadmap tools being non-default-enabled is called out so a future reader does not have to diff tools.list to work out why the count grew. Validating through the initialize handshake for serverInfo.version plus tools/list count plus every default_enabled entry resolving is the right check, because a pin that resolves to the right version but a server that fails to advertise one of the enabled tools is the failure mode a version string alone would hide. test_mcp_catalog.py 39/39 is consistent with that.

One observation, not a request: the notes changelog block is now long enough that the version history is doing real work — it is what a future bump will be diffed against. Keeping the per-version reasoning in the manifest is the right place for it (a separate file would drift), but it does mean the block grows monotonically. If it ever gets hard to find the current version's justification in, a ## Current pin heading above the changelog with the version and its one-paragraph rationale would be the cheapest fix. Not worth doing now.

Nothing outstanding from me. Your carve-out reasoning holds in both directions — the two bumped servers clear it, the two held-back ones demonstrably do not.

I am not a maintainer and my review is not maintainer approval.

sgtworkman added a commit to sgtworkman/hermes-agent that referenced this pull request Sep 27, 2026
…head (apple-mail-mcp 2.19.14->2.19.16, apple-notes-mcp 2.9.12->2.9.30)
apple-mail 2.19.17/2.19.18 fix default_enabled tools (list-messages,
search-messages, get-thread) against real huge iCloud mailboxes
(sweetrb/apple-mail-mcp#256): whole-mailbox SEARCH failing outright above
~250k messages, and a page silently coming back short when imapflow can't
parse a deeply-nested FETCH response.

apple-notes 2.9.31 fixes get-note-content (default_enabled) for clients
that only see a tool result's text, not structuredContent -- contentHash
and related fields now also appear as a text block, unblocking every
guarded write gated on expectedContentHash for those clients
(sweetrb/apple-notes-mcp#264).

Validated on macOS: both MCP initialize handshakes report the pinned
serverInfo.version, tools/list is unchanged in count from the prior pin,
every default_enabled entry resolves, and test_mcp_catalog.py is 39/39.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Sep 27, 2026

Copy link
Copy Markdown
Author

Re-pinned two of the four servers again (validated on macOS today, commit 51e5c5d5):

  • apple-mail-mcp 2.19.16 → 2.19.18 — IMAP list-messages fails on very large visible mailboxes before applying limit sweetrb/apple-mail-mcp#256 (@j5pu, 793,614- and 255,104-message iCloud mailboxes): a whole-mailbox UID SEARCH before applying limit/offset failed outright above ~250k messages (2.19.17, now pages by sequence number from the top of the mailbox above 10k messages); and a page could come back silently short when imapflow's parser can't handle an ~11-deep nested BODYSTRUCTURE (2.19.18, now retries and reports omittedMessages/partial: true instead of silently dropping rows). Both land in list-messages/search-messages/get-thread, all default_enabled.
  • apple-notes-mcp 2.9.30 → 2.9.31 — contentHash not visible to model in Claude Desktop — blocks add-native-tags, add-attachment, update-note sweetrb/apple-notes-mcp#264 (@aaronaccessvr): contentHash and related identity fields were returned only in structuredContent, which a client that shows the model only a tool result's text (Claude Desktop among them) drops entirely, silently breaking every guarded write gated on expectedContentHash. get-note-content (default_enabled) now also carries a trailing text block with the same data.
  • apple-numbers-mcp (1.2.3) and apple-photos-mcp (2.1.13) unchanged — still no default_enabled-tool defect fix since the last pin.

Validated: MCP initialize handshake confirms serverInfo.version matches the new pin for both, tools/list count is unchanged from the prior pin (52 / 83), every default_enabled entry resolves against the new tool names, test_mcp_catalog.py 39/39 (scratch python3.14 venv).

sgtworkman added a commit to sgtworkman/hermes-agent that referenced this pull request Sep 28, 2026
…51466 head

apple-mail 2.19.18: huge-mailbox list/search paging + failed-SEARCH error
surfacing (sweetrb/apple-mail-mcp#256, @j5pu); apple-notes 2.9.31: revision
fields now also in the text block for text-only clients
(sweetrb/apple-notes-mcp#264). numbers/photos already current at that head.
Fixes a follow-up defect in default_enabled tools list-messages/
search-messages/get-thread (sweetrb/apple-mail-mcp#256): a deep unfiltered
offset on a large mailbox still cost more the deeper it went even after
2.19.17/18. 2.19.19 computes the page's sequence range directly instead of
scanning every skipped message. Validated on macOS: initialize handshake
reports serverInfo.version 2.19.19, tools/list returns 52 tools, all 18
default_enabled entries resolve; test_mcp_catalog.py 39/39.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Sep 28, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-mail-mcp 2.19.18 → 2.19.19 (89b680e): a follow-up defect on the same huge-iCloud-mailbox report (#256) in default_enabled tools — even after 2.19.17/18, a deep unfiltered offset still cost more the deeper it went, because the large-mailbox path still read UID+FLAGS for every skipped message. 2.19.19 computes the page's sequence range directly instead, so offset 790,000 now costs the same as offset 0. The reporter re-tested and confirmed: offset 350,000 went from timing out at 60s to ~10s, and a full 1,589-page pagination of the 793,614-message mailbox returned every message exactly once, no duplicates or gaps.

Validated on macOS: initialize handshake reports serverInfo.version 2.19.19, tools/list returns the same 52 tools, all 18 default_enabled entries resolve, test_mcp_catalog.py 39/39. notes/numbers/photos pins unchanged — no default-enabled-tool defect fix since the last check.

Fixes two defects in default_enabled attachment tools
(sweetrb/apple-mail-mcp#270): list-attachments reported each
attachment's base64-encoded size instead of its decoded byte count (a
29-byte file listed as 40), and fetch-attachment over IMAP checked its
25 MiB limit against that encoded size, refusing base64 attachments of
~19-25 MiB before download. Riding along: bundled fast-uri (high) and
ip-address (medium) advisory floors from 2.19.20/2.19.22; 2.19.21 and
2.20.0 touch only disabled send/mutation tools.

Validated on macOS: initialize handshake reports serverInfo.version
2.20.1, tools/list returns 52 tools (all described, unchanged from
2.19.19), all 18 default_enabled entries resolve; test_mcp_catalog.py
39/39 on this branch and 42/42 against current main.

Host: robs-work-mbpromax
@sweetrb
sweetrb requested a review from a team as a code owner October 6, 2026 17:41
@sweetrb

sweetrb commented Oct 6, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-mail-mcp 2.19.19 → 2.20.1 (7cf4329): two defects in default_enabled attachment tools (#270). list-attachments reported each attachment's base64-encoded size rather than its decoded byte count (a 29-byte file listed as 40), and fetch-attachment over IMAP checked its 25 MiB limit against that encoded size, refusing base64 attachments of roughly 19–25 MiB before download.

Validated on macOS: initialize handshake reports serverInfo.version 2.20.1, tools/list returns the same 52 tools, all 18 default_enabled entries resolve, test_mcp_catalog.py 39/39. notes/numbers/photos pins untouched in this push.

@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium risk] Adds four new optional macOS application integrations to the catalog.

This PR should wait for corrected Photos access instructions before merging.

Findings

  1. P1 Security Photos access stays denied ▶
  2. P2 Notes checks cover older version ▶
Fix with agent prompt
### Issue 1
optional-mcps/apple-photos/manifest.yaml:76-77
The setup text tells users to give Full Disk Access to the process that launches Hermes. If they grant access only to that launcher, the Photos tools can still be denied access: Hermes starts the server through `npx`, and the catalog’s Notes guidance says macOS checks the grant on the Node binary. Tell users which executable needs the grant.

**How this was verified:** The Photos instructions name the Hermes launcher, while the catalog’s Node-based permission guidance identifies the Node binary as the checked process.

### Issue 2
optional-mcps/apple-notes/manifest.yaml:17-22
The recorded macOS checks ran against `apple-notes-mcp@2.9.30`, but the manifest launches `apple-notes-mcp@2.9.31`. Those results do not show whether the version users install starts or exposes the listed tools. Run the checks against the pinned version and update the record.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary

Adds four macOS Apple-app MCP servers to the optional catalog, so users can install them with hermes mcp install <name>. Each entry launches a pinned npm package over stdio and starts with read-focused tools.

  • Apple Mail tools can be installed from the Hermes MCP catalog.
  • Apple Notes tools can be installed from the Hermes MCP catalog.
  • Apple Numbers spreadsheet tools can be installed from the Hermes MCP catalog.
  • Apple Photos library tools can be installed from the Hermes MCP catalog.

Reviews (1) · Last reviewed commit: "optional-mcps/apple-mail: re-pin 2.19.19..."

Comment on lines +76 to +77
Requires macOS, Python 3.11+, and Full Disk Access for the process that
launches Hermes — the Photos library database lives in a protected location.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Photos access stays denied

The setup text tells users to give Full Disk Access to the process that launches Hermes. If they grant access only to that launcher, the Photos tools can still be denied access: Hermes starts the server through npx, and the catalog’s Notes guidance says macOS checks the grant on the Node binary. Tell users which executable needs the grant.

How this was verified: The Photos instructions name the Hermes launcher, while the catalog’s Node-based permission guidance identifies the Node binary as the checked process.

Prompt To Fix With AI
This is a comment left during a code review.
Path: optional-mcps/apple-photos/manifest.yaml
Line: 76-77

Comment:
**Photos access stays denied**

The setup text tells users to give Full Disk Access to the process that launches Hermes. If they grant access only to that launcher, the Photos tools can still be denied access: Hermes starts the server through `npx`, and the catalog’s Notes guidance says macOS checks the grant on the Node binary. Tell users which executable needs the grant.

**How this was verified:** The Photos instructions name the Hermes launcher, while the catalog’s Node-based permission guidance identifies the Node binary as the checked process.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 651163e. "The Node binary" is only part of the answer, though: macOS checks Full Disk Access on the responsible process. When Hermes runs from a terminal (the usual case), the terminal app is responsible for everything it spawns, npx and node included, so granting Terminal/iTerm is correct there and a grant on node alone would not be what is checked. The Node binary becomes the checked identity only when the launcher disclaims responsibility (Claude Desktop does; that is the case the apple-notes #220 note describes) or there is no terminal in the chain. post_install now names both cases: grant the terminal, or grant the path from realpath "$(command -v node)", noting that a version-managed or ad-hoc-signed Node loses that grant on upgrade. It also says how to read the checked binary (responsible_path) from the TCC log. The apple-notes #220 note is reworded so the catalog no longer says the Node binary is always the one checked, and apple-notes' post_install carries the same guidance for its optional FDA reads.

Comment thread optional-mcps/apple-notes/manifest.yaml Outdated
Comment on lines +17 to +22
# On macOS, `npx -y apple-notes-mcp@2.9.30`:
# - completes an MCP `initialize` handshake reporting serverInfo.version
# 2.9.30 — i.e. the bytes npx resolved are the bytes pinned here;
# - returns a full `tools/list` of 83 tools, every one carrying a description;
# - resolves all 20 `tools.default_enabled` entries below against that
# list, so no allow-listed name went stale across the bump.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Notes checks cover older version

The recorded macOS checks ran against apple-notes-mcp@2.9.30, but the manifest launches apple-notes-mcp@2.9.31. Those results do not show whether the version users install starts or exposes the listed tools. Run the checks against the pinned version and update the record.

Prompt To Fix With AI
This is a comment left during a code review.
Path: optional-mcps/apple-notes/manifest.yaml
Line: 17-22

Comment:
**Notes checks cover older version**

The recorded macOS checks ran against `apple-notes-mcp@2.9.30`, but the manifest launches `apple-notes-mcp@2.9.31`. Those results do not show whether the version users install starts or exposes the listed tools. Run the checks against the pinned version and update the record.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 651163e. Re-ran the checks against 2.9.31 exactly: serverInfo.version 2.9.31, 83 tools, all described, 20/20 default_enabled entries resolve. In the same pass the pin moved to 2.9.32, because 2.9.31 inlines fast-uri 3.1.6, the only 3.x release affected by GHSA-58mr-gqgx-xq4g (high, reachable via ajv on every tool call). The 2.9.32 bundle diff is confined to that module. The validation record now names 2.9.32 (same results: 83 tools, 20/20) and mentions both runs. apple-photos (2.1.12 -> 2.1.14) and apple-numbers (1.2.2 -> 1.2.4) had the same bundled fast-uri 3.1.6 and were re-pinned and validated the same way.

@alt-glitch alt-glitch added P4 Best-effort: we will get to it when we get to it (no commitment) and removed P3 Low — cosmetic, nice to have sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Oct 6, 2026
…fast-uri GHSA-58mr-gqgx-xq4g

Full Disk Access (review feedback): macOS checks the grant on the
responsible process, not on whatever executable happens to read the file.
Under a terminal - the usual way Hermes runs - the terminal app is
responsible for npx/node and is what needs the grant. Launched any other
way (GUI wrapper, launchd service), nothing passes a terminal's grant down
and the check can land on the node binary npx runs. apple-photos'
post_install now names both cases, how to find the real node path
(realpath "$(command -v node)"), that version-managed or ad-hoc-signed
Node loses the grant on upgrade, and how to read the authoritative answer
from the TCC log. apple-notes gets the same guidance for its optional FDA
reads, and its NousResearch#220 history note no longer says the Node binary is always
the one checked (that is Claude Desktop's case, whose launcher disclaims
responsibility). apple-mail (no FDA) and apple-numbers (no FDA claim)
already agree.

Re-pins (security footing, as with the earlier fast-uri re-pins):
apple-notes 2.9.31 -> 2.9.32, apple-photos 2.1.12 -> 2.1.14,
apple-numbers 1.2.2 -> 1.2.4. Each old pin inlines fast-uri 3.1.6 into
build/index.js - the only 3.x release affected by GHSA-58mr-gqgx-xq4g
(high), reachable via ajv on every tool call. Each new pin bundles 3.1.8,
and its build/index.js diff from the preceding release is confined to the
inlined fast-uri module. apple-mail already carries the fix (2.19.20).
Later releases are declined in the manifests with reasons.

Validated on macOS (npx -y <pkg>@<ver>, initialize + tools/list only):
apple-notes 2.9.31 and 2.9.32 both report their own serverInfo.version,
83 tools, all described, all 20 default_enabled resolve; apple-photos
2.1.14: 21 tools, 13/13; apple-numbers 1.2.4: 26 tools, 6/6.
test_mcp_catalog.py 39/39 on this branch and 42/42 against current main.

Host: robs-work-mbpromax
Fixes two defects in default_enabled tools, both on huge iCloud
mailboxes. By-id reads (get-message, get-thread's seed lookup, the
attachment tools' source reads) on a numeric id that missed fell back to
an unbounded every-mailbox AppleScript scan taking 21-53 s and timing out
(sweetrb/apple-mail-mcp#270, fixed in 2.20.4 via NousResearch#278): an explicit
account+mailbox miss now returns not-found immediately and the unscoped
fallback is bounded (APPLE_MAIL_MAX_BYID_SCAN_MAILBOX, 9 s budget). And
one slow IMAP search-messages held the serialized call queue for 130+ s
so every following call timed out behind it (NousResearch#276, fixed in 2.20.5 via
NousResearch#279): cancellation is honoured and a per-call deadline
(APPLE_MAIL_MCP_SEARCH_DEADLINE_MS, default 45 s) returns partial
results with timedOutMailboxes. Riding along: 2.20.2 Dependabot bump
(MCP SDK 1.31.0, nodemailer, lint tooling), 2.20.3 15 s fail-fast on
by-id reads, 2.20.4 dev-only source-map-js floor.

Validated on macOS: initialize handshake reports serverInfo.version
2.20.5, tools/list returns 52 tools (all described, unchanged from
2.20.1), all 18 default_enabled entries resolve; test_mcp_catalog.py
39/39 on this branch and 42/42 against current main.

Host: robs-work-mbpromax
@sweetrb

sweetrb commented Oct 7, 2026

Copy link
Copy Markdown
Author

Re-pinned apple-mail-mcp 2.20.1 → 2.20.5 (6c267e7): two defects in default_enabled tools, both on huge iCloud mailboxes. By-id reads (get-message, get-thread, and the attachment tools' source reads) on a numeric id that missed fell back to an unbounded every-mailbox AppleScript scan that took 21–53 s and timed out (#270, fixed in 2.20.4). An explicit account + mailbox miss now returns not-found immediately, and the unscoped fallback is bounded (APPLE_MAIL_MAX_BYID_SCAN_MAILBOX, 9 s budget). Separately, one slow IMAP search-messages held the server's call queue for 130+ s, so every following call, even list-accounts, timed out behind it (#276, fixed in 2.20.5). It now honours notifications/cancelled and a per-call deadline (APPLE_MAIL_MCP_SEARCH_DEADLINE_MS, default 45 s), returning partial results with timedOutMailboxes.

Validated on macOS: initialize handshake reports serverInfo.version 2.20.5, tools/list returns the same 52 tools, all 18 default_enabled entries resolve, test_mcp_catalog.py 39/39. notes/numbers/photos pins untouched in this push.

@alt-glitch alt-glitch added the Plugin Catalog Plugin catalog entries, discovery, metadata, and catalog management label Oct 7, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P4 Best-effort: we will get to it when we get to it (no commitment) Plugin Catalog Plugin catalog entries, discovery, metadata, and catalog management sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users tool/mcp MCP client and OAuth type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants