apple-notes-mcp 2.8.13 → 2.8.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -5
- package/build/index.js +30 -17
- package/package.json +1 -1
- package/shortcuts/README.md +9 -1
package/README.md
CHANGED
|
@@ -71,6 +71,16 @@ workflows. Confirm **Add Shortcut** in each macOS window, then verify with
|
|
|
71
71
|
support silent Shortcut import, so merely connecting an MCP client never opens
|
|
72
72
|
setup windows or bypasses these confirmations.
|
|
73
73
|
|
|
74
|
+
After install **and after every upgrade**, open Shortcuts.app and run each
|
|
75
|
+
bridge — `Apple Notes MCP - Native Tags` and
|
|
76
|
+
`Apple Notes MCP - Background Operations v5` — once in the foreground, choosing
|
|
77
|
+
**Always Allow** when Shortcuts asks for permission. The server runs these
|
|
78
|
+
Shortcuts in the background, where Shortcuts cannot display a first-run consent
|
|
79
|
+
prompt: an unanswered one stalls every native write on that bridge until it
|
|
80
|
+
times out, while `doctor` still reports the bridge installed. Quitting or
|
|
81
|
+
relaunching Shortcuts.app or Notes.app does not clear it; the foreground run
|
|
82
|
+
does, once per bridge.
|
|
83
|
+
|
|
74
84
|
### Using the Codex Marketplace
|
|
75
85
|
|
|
76
86
|
The same plugin is available for Codex. Add the marketplace and install the plugin:
|
|
@@ -225,6 +235,14 @@ Creates a new note in Apple Notes.
|
|
|
225
235
|
|
|
226
236
|
> **Note:** The title is automatically prepended as `<h1>` in both plaintext and HTML formats. Do not include a `<h1>` title tag in the `content` parameter, or the title will appear twice.
|
|
227
237
|
|
|
238
|
+
> **Known limitation:** `create-note` sets the note body directly via AppleScript's
|
|
239
|
+
> `body` property, which does not apply real Notes paragraph styles for interior
|
|
240
|
+
> content — an `<h2>`/`<h3>` tag or a `<span style="font-size: …px">` heading span
|
|
241
|
+
> in `content` renders as plain bold, styled text, not an actual Heading or
|
|
242
|
+
> Subheading ([#172](https://github.com/sweetrb/apple-notes-mcp/issues/172)). Real
|
|
243
|
+
> Heading/Subheading styles can currently only be added to a note that already
|
|
244
|
+
> exists, with [`append-native`](#append-native)'s `format: "markdown"`.
|
|
245
|
+
|
|
228
246
|
**Returns:** Confirmation message with note title and ID. Save the ID for subsequent operations like `update-note`, `delete-note`, etc.
|
|
229
247
|
|
|
230
248
|
---
|
|
@@ -339,7 +357,10 @@ Access.
|
|
|
339
357
|
#### `native-tags-status`
|
|
340
358
|
|
|
341
359
|
Checks whether exactly one configured Native Tags Shortcut is installed. An
|
|
342
|
-
installed workflow may still need macOS permission on its first execution
|
|
360
|
+
installed workflow may still need macOS permission on its first execution, and
|
|
361
|
+
installation does not show whether that consent was given: run it once in the
|
|
362
|
+
foreground in Shortcuts.app and choose **Always Allow** after install or upgrade
|
|
363
|
+
(see [Troubleshooting](#native-writes-time-out-or-report-an-uncertain-outcome)).
|
|
343
364
|
|
|
344
365
|
---
|
|
345
366
|
|
|
@@ -1048,7 +1069,10 @@ Lists all notes shared with collaborators.
|
|
|
1048
1069
|
### Native background operations
|
|
1049
1070
|
|
|
1050
1071
|
Install the signed workflows once as described in
|
|
1051
|
-
[`shortcuts/README.md`](shortcuts/README.md)
|
|
1072
|
+
[`shortcuts/README.md`](shortcuts/README.md), then run each once in the
|
|
1073
|
+
foreground in Shortcuts.app and choose **Always Allow** — again after every
|
|
1074
|
+
upgrade — so no first-run consent prompt is left for a background run that
|
|
1075
|
+
cannot display it. Native writes never use UI
|
|
1052
1076
|
automation or write directly to the Notes database. Every operation requires an
|
|
1053
1077
|
exact note ID, a fresh `expectedContentHash`, and a distinctive existing
|
|
1054
1078
|
`scopeText` so the Shortcut and server can independently resolve the same note.
|
|
@@ -1066,9 +1090,16 @@ when `scopeText` is supplied. Use a distinctive phrase of plain words without
|
|
|
1066
1090
|
punctuation, hashtags, or paths because Notes search may not resolve them
|
|
1067
1091
|
literally. `format: "html"` accepts the fixed subset tabulated under
|
|
1068
1092
|
[`append-to-note`](#append-to-note); content outside it is refused by name, with
|
|
1069
|
-
the accepted subset in the error.
|
|
1070
|
-
|
|
1071
|
-
|
|
1093
|
+
the accepted subset in the error. `format: "markdown"` accepts the same bounded
|
|
1094
|
+
subset as `format: "html"`'s Markdown-shaped content (`#`/`##`/`###` headings,
|
|
1095
|
+
flat lists, emphasis, and inline links) but is sent through Notes' own native
|
|
1096
|
+
Markdown importer rather than converted to HTML first, so `#`/`##`/`###`
|
|
1097
|
+
produce real Title/Heading/Subheading — Notes' HTML importer only
|
|
1098
|
+
distinguishes two heading levels and renders `###` the same as `##`. A
|
|
1099
|
+
transport failure names the Shortcut it was waiting on, so a missing or
|
|
1100
|
+
unapproved bridge is identified rather than guessed at; a timeout also says it
|
|
1101
|
+
may be an unanswered first-run consent prompt and names the Shortcut to run once
|
|
1102
|
+
in the foreground.
|
|
1072
1103
|
|
|
1073
1104
|
#### `create-checklist-item`
|
|
1074
1105
|
|
|
@@ -1383,6 +1414,12 @@ In a JSON string literal the two characters `\\` denote **one** literal backslas
|
|
|
1383
1414
|
- Go to System Settings > Privacy & Security > Automation
|
|
1384
1415
|
- Ensure your terminal/Claude has permission to control Notes
|
|
1385
1416
|
|
|
1417
|
+
### Native writes time out or report an uncertain outcome
|
|
1418
|
+
- Symptom: `add-native-tags`, `set-note-pinned`, `append-native` or another native write fails with "Shortcuts timed out waiting for …", "Operation outcome uncertain" or "readback was not verified", while `doctor` and `get-capabilities` report the bridges installed
|
|
1419
|
+
- Common cause, especially right after install or upgrade: the bridge Shortcut is waiting on a first-run consent prompt. The server runs it in the background, where Shortcuts cannot display that prompt, so the run stalls until it times out
|
|
1420
|
+
- Fix: open Shortcuts.app, run the Shortcut the error names (`Apple Notes MCP - Native Tags` or `Apple Notes MCP - Background Operations v5`) once in the foreground and choose **Always Allow**. Each bridge needs this once; quitting or relaunching Shortcuts.app or Notes.app does not clear it
|
|
1421
|
+
- Read the exact note before retrying — the write may have landed
|
|
1422
|
+
|
|
1386
1423
|
### "Note not found"
|
|
1387
1424
|
- Note titles must match exactly (case-sensitive)
|
|
1388
1425
|
- Check if the note is in a different account
|
package/build/index.js
CHANGED
|
@@ -39800,10 +39800,12 @@ function htmlLinks(html) {
|
|
|
39800
39800
|
}
|
|
39801
39801
|
return links;
|
|
39802
39802
|
}
|
|
39803
|
+
var BARE_HTTP_ORIGIN = /^https?:\/\/[^/?#]+$/i;
|
|
39804
|
+
var normalizedUrl = (url) => BARE_HTTP_ORIGIN.test(url) ? `${url}/` : url;
|
|
39803
39805
|
function linkSignature(links) {
|
|
39804
39806
|
return JSON.stringify(
|
|
39805
39807
|
links.flatMap(
|
|
39806
|
-
(link) => normalized(link.text).split("").map((char) => [char, link.url])
|
|
39808
|
+
(link) => normalized(link.text).split("").map((char) => [char, normalizedUrl(link.url)])
|
|
39807
39809
|
)
|
|
39808
39810
|
);
|
|
39809
39811
|
}
|
|
@@ -42734,6 +42736,14 @@ import { execFileSync as execFileSync6 } from "node:child_process";
|
|
|
42734
42736
|
import { mkdtempSync as mkdtempSync2, writeFileSync, rmSync as rmSync2 } from "node:fs";
|
|
42735
42737
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
42736
42738
|
import { join as join7 } from "node:path";
|
|
42739
|
+
|
|
42740
|
+
// src/services/shortcutConsent.ts
|
|
42741
|
+
function shortcutConsentHint(shortcut) {
|
|
42742
|
+
const target = shortcut ? `"${shortcut}"` : "the bridge Shortcut";
|
|
42743
|
+
return `This may be an unanswered first-run Shortcuts consent prompt, which a background run cannot display: run ${target} once in the foreground in Shortcuts.app and choose Always Allow.`;
|
|
42744
|
+
}
|
|
42745
|
+
|
|
42746
|
+
// src/services/nativeTags.ts
|
|
42737
42747
|
var NATIVE_TAGS_SHORTCUT = "Apple Notes MCP - Native Tags";
|
|
42738
42748
|
function normalizeNativeTags(tags) {
|
|
42739
42749
|
if (!tags.length || tags.length > 100) throw new Error("Provide between 1 and 100 tags");
|
|
@@ -42788,7 +42798,7 @@ function addNativeTags(request, deps) {
|
|
|
42788
42798
|
};
|
|
42789
42799
|
if (after.title !== before.title || allTags.some((tag) => !after.rich.nativeTags.includes(tag)) || textWithoutTags(before.rich.text) !== textWithoutTags(after.rich.text) || linkSignature(before.rich.links) !== linkSignature(after.rich.links) || before.rich.nativeObjectIds.some((id2) => !after.rich.nativeObjectIds.includes(id2)) || before.rich.hasChecklist !== after.rich.hasChecklist) {
|
|
42790
42800
|
throw new Error(
|
|
42791
|
-
"Shortcuts ran, but exact-ID tags/text/links readback was not verified. Read the note before any retry"
|
|
42801
|
+
transportWarning ? `Shortcuts did not complete cleanly, and exact-ID tags/text/links readback was not verified. Read the note before any retry. ${transportWarning}` : "Shortcuts ran, but exact-ID tags/text/links readback was not verified. Read the note before any retry"
|
|
42792
42802
|
);
|
|
42793
42803
|
}
|
|
42794
42804
|
return {
|
|
@@ -42831,9 +42841,12 @@ function runNativeTagsShortcut(input) {
|
|
|
42831
42841
|
maxBuffer: 1024 * 1024,
|
|
42832
42842
|
stdio: ["ignore", "pipe", "pipe"]
|
|
42833
42843
|
});
|
|
42834
|
-
} catch {
|
|
42835
|
-
throw
|
|
42836
|
-
|
|
42844
|
+
} catch (error2) {
|
|
42845
|
+
throw Object.assign(
|
|
42846
|
+
new Error(
|
|
42847
|
+
`Native tag operation did not complete cleanly. ${shortcutConsentHint(status.shortcut)} Do not retry automatically; read the exact note first`
|
|
42848
|
+
),
|
|
42849
|
+
{ shortcut: status.shortcut, code: error2?.code }
|
|
42837
42850
|
);
|
|
42838
42851
|
} finally {
|
|
42839
42852
|
rmSync2(directory, { recursive: true, force: true });
|
|
@@ -43117,7 +43130,7 @@ function mutateBackground(request, operation, data, verify, deps) {
|
|
|
43117
43130
|
transportUncertain = true;
|
|
43118
43131
|
const detail = error2;
|
|
43119
43132
|
const named = detail?.shortcut ? `the "${detail.shortcut}" Shortcut` : "the background Shortcut";
|
|
43120
|
-
transportMessage = detail?.code === "ETIMEDOUT" ? `Shortcuts timed out waiting for ${named}
|
|
43133
|
+
transportMessage = detail?.code === "ETIMEDOUT" ? `Shortcuts timed out waiting for ${named}. ${shortcutConsentHint(detail.shortcut)}` : `${named} failed: ${String(detail?.stderr || detail?.message || "no output").trim().slice(0, 400)}`;
|
|
43121
43134
|
}
|
|
43122
43135
|
const after = deps.read(request.id);
|
|
43123
43136
|
try {
|
|
@@ -43157,15 +43170,10 @@ function assertAppendedVisibleText(beforeHtml, afterHtml, expected) {
|
|
|
43157
43170
|
}
|
|
43158
43171
|
function appendNative(manager, request) {
|
|
43159
43172
|
validateAppendContent(request.content, request.format);
|
|
43160
|
-
if (request.format === "markdown")
|
|
43161
|
-
return appendNative(manager, {
|
|
43162
|
-
...request,
|
|
43163
|
-
content: appendMarkdownHtml(request.content),
|
|
43164
|
-
format: "html"
|
|
43165
|
-
});
|
|
43166
43173
|
if (request.format === "html" && /<table\b/i.test(request.content))
|
|
43167
43174
|
throw new Error("Use create-table for verified native table insertion");
|
|
43168
|
-
const
|
|
43175
|
+
const markdownHtml = request.format === "markdown" ? appendMarkdownHtml(request.content) : null;
|
|
43176
|
+
const op = request.format === "plaintext" ? "append-text" : request.format === "markdown" ? "append-markdown" : "append-html";
|
|
43169
43177
|
const text = request.format === "html" ? "<div><br></div>" + request.content : "\n\n" + request.content;
|
|
43170
43178
|
return mutateBackground(
|
|
43171
43179
|
request,
|
|
@@ -43173,10 +43181,11 @@ function appendNative(manager, request) {
|
|
|
43173
43181
|
{ text },
|
|
43174
43182
|
(before, after) => {
|
|
43175
43183
|
assertPreserved(before, after, { append: true });
|
|
43176
|
-
const
|
|
43184
|
+
const verifyHtml = markdownHtml ?? request.content;
|
|
43185
|
+
const expected = request.format === "plaintext" ? request.content : comparableVisibleText(verifyHtml);
|
|
43177
43186
|
if (expected) assertAppendedVisibleText(before.html, after.html, expected);
|
|
43178
|
-
if (request.format === "html")
|
|
43179
|
-
assertAppendedHtmlLinks(before.rich.links.length, after.rich.links,
|
|
43187
|
+
if (request.format === "html" || request.format === "markdown")
|
|
43188
|
+
assertAppendedHtmlLinks(before.rich.links.length, after.rich.links, verifyHtml);
|
|
43180
43189
|
},
|
|
43181
43190
|
backgroundDependencies(manager)
|
|
43182
43191
|
);
|
|
@@ -43241,6 +43250,7 @@ function runDoctor(manager) {
|
|
|
43241
43250
|
status: fda ? "ok" : "warn",
|
|
43242
43251
|
detail: fda ? "granted \u2014 the Notes database is readable (checklist state, note metadata, note links, sync detail)" : `not granted \u2014 get-checklist-state, get-note-metadata, and the checklist annotations in get-note-markdown won't work; get-note-link fails on macOS 26+ (macOS 12-15 falls back to AppleScript); get-sync-status still answers but cannot see pending uploads. Everything else is pure AppleScript and is unaffected. In System Settings > Privacy & Security > Full Disk Access, grant access to the app that launches this server (Claude Desktop / Terminal / iTerm2), then fully quit and relaunch it and re-run doctor. Setup guide: ${FULL_DISK_ACCESS_GUIDE_URL}`
|
|
43243
43252
|
});
|
|
43253
|
+
const consentReminder = "After install or upgrade, run each bridge Shortcut once in the foreground in Shortcuts.app and choose Always Allow: a background run cannot display a first-run consent prompt, so an unanswered one stalls that bridge's native writes until they time out while this check stays ok";
|
|
43244
43254
|
try {
|
|
43245
43255
|
const bridgeStatuses = [NATIVE_TAGS_SHORTCUT, BACKGROUND_SHORTCUT].map(
|
|
43246
43256
|
(name) => nativeTagsStatus(name)
|
|
@@ -43249,7 +43259,7 @@ function runDoctor(manager) {
|
|
|
43249
43259
|
checks.push({
|
|
43250
43260
|
name: "Native write Shortcuts",
|
|
43251
43261
|
status: missing.length ? "warn" : "ok",
|
|
43252
|
-
detail: missing.length ? `missing: ${missing.map((status) => status.shortcut).join(", ")}. Run apple-notes-mcp setup and approve Add Shortcut in macOS` :
|
|
43262
|
+
detail: missing.length ? `missing: ${missing.map((status) => status.shortcut).join(", ")}. Run apple-notes-mcp setup and approve Add Shortcut in macOS. ${consentReminder}` : `both native-write bridges are installed. ${consentReminder}`
|
|
43253
43263
|
});
|
|
43254
43264
|
} catch (error2) {
|
|
43255
43265
|
checks.push({
|
|
@@ -44263,6 +44273,9 @@ function formatShortcutSetup(report) {
|
|
|
44263
44273
|
lines.push(
|
|
44264
44274
|
"After approving the macOS dialogs, run `apple-notes-mcp setup --check` or the MCP doctor tool."
|
|
44265
44275
|
);
|
|
44276
|
+
lines.push(
|
|
44277
|
+
"After install or upgrade, run each bridge once in the foreground in Shortcuts.app and choose Always Allow; a background run cannot display a first-run consent prompt and stalls until it times out."
|
|
44278
|
+
);
|
|
44266
44279
|
return lines.join("\n");
|
|
44267
44280
|
}
|
|
44268
44281
|
|
package/package.json
CHANGED
package/shortcuts/README.md
CHANGED
|
@@ -15,6 +15,13 @@ Open the signed file and confirm **Add Shortcut** once. macOS may also request
|
|
|
15
15
|
Notes access on first execution. The `shortcuts` CLI can run an installed
|
|
16
16
|
workflow but cannot silently import one.
|
|
17
17
|
|
|
18
|
+
After install and after every upgrade, run each bridge once in the foreground in
|
|
19
|
+
Shortcuts.app and choose **Always Allow** when it asks for permission. The
|
|
20
|
+
server runs bridges in the background, where Shortcuts cannot display a
|
|
21
|
+
first-run consent prompt, so an unanswered one stalls that bridge's native
|
|
22
|
+
writes until they time out. Quitting or relaunching Shortcuts.app or Notes.app
|
|
23
|
+
does not clear it; one foreground run per bridge does.
|
|
24
|
+
|
|
18
25
|
The bridge receives a private temporary JSON file with a title, a distinctive
|
|
19
26
|
existing scope phrase, and normalized tags. Both the server and workflow refuse
|
|
20
27
|
ambiguous note selection. Server readback, rather than CLI output, establishes
|
|
@@ -38,6 +45,7 @@ shortcuts sign --mode anyone \
|
|
|
38
45
|
--output "shortcuts/Apple Notes MCP - Background Operations v5.shortcut"
|
|
39
46
|
```
|
|
40
47
|
|
|
41
|
-
Open the signed file and confirm **Add Shortcut** once
|
|
48
|
+
Open the signed file and confirm **Add Shortcut** once, then run it once in the
|
|
49
|
+
foreground in Shortcuts.app and choose **Always Allow** (see above). Do not install obsolete
|
|
42
50
|
workflow versions with the same display name; the server resolves one exact
|
|
43
51
|
installed UUID and refuses duplicates.
|