apple-notes-mcp 2.8.7 → 2.8.8
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
CHANGED
|
@@ -323,6 +323,24 @@ Access.
|
|
|
323
323
|
|
|
324
324
|
---
|
|
325
325
|
|
|
326
|
+
#### `native-tags-status`
|
|
327
|
+
|
|
328
|
+
Checks whether exactly one configured Native Tags Shortcut is installed. An
|
|
329
|
+
installed workflow may still need macOS permission on its first execution.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
#### `add-native-tags`
|
|
334
|
+
|
|
335
|
+
Adds actual native Notes tag objects to one exact note using `id`, a fresh
|
|
336
|
+
`expectedContentHash`, a distinctive existing `scopeText`, and `tags`. The
|
|
337
|
+
operation verifies the note's original text, links, and native objects after the
|
|
338
|
+
Shortcut runs. It refuses ambiguous title-and-scope matches and never retries an
|
|
339
|
+
uncertain write. Install the signed workflow as described in
|
|
340
|
+
[`shortcuts/README.md`](shortcuts/README.md).
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
326
344
|
#### `get-note-plaintext`
|
|
327
345
|
|
|
328
346
|
Retrieves a note's body as plain text, with no HTML markup.
|
package/build/index.js
CHANGED
|
@@ -24465,14 +24465,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
24465
24465
|
} else if (node.nodeType === 1) {
|
|
24466
24466
|
replacement = replacementForNode.call(self, node);
|
|
24467
24467
|
}
|
|
24468
|
-
return
|
|
24468
|
+
return join10(output, replacement);
|
|
24469
24469
|
}, "");
|
|
24470
24470
|
}
|
|
24471
24471
|
function postProcess(output) {
|
|
24472
24472
|
var self = this;
|
|
24473
24473
|
this.rules.forEach(function(rule) {
|
|
24474
24474
|
if (typeof rule.append === "function") {
|
|
24475
|
-
output =
|
|
24475
|
+
output = join10(output, rule.append(self.options));
|
|
24476
24476
|
}
|
|
24477
24477
|
});
|
|
24478
24478
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -24484,7 +24484,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
24484
24484
|
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
|
24485
24485
|
return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
|
|
24486
24486
|
}
|
|
24487
|
-
function
|
|
24487
|
+
function join10(output, replacement) {
|
|
24488
24488
|
var s1 = trimTrailingNewlines(output);
|
|
24489
24489
|
var s2 = trimLeadingNewlines(replacement);
|
|
24490
24490
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -39350,10 +39350,10 @@ function hasFullDiskAccess() {
|
|
|
39350
39350
|
return false;
|
|
39351
39351
|
}
|
|
39352
39352
|
}
|
|
39353
|
-
function queryNoteData(
|
|
39354
|
-
const pkMatch =
|
|
39353
|
+
function queryNoteData(noteId3) {
|
|
39354
|
+
const pkMatch = noteId3.match(/\/p(\d+)$/);
|
|
39355
39355
|
if (!pkMatch) {
|
|
39356
|
-
console.error(`Invalid note ID format: ${
|
|
39356
|
+
console.error(`Invalid note ID format: ${noteId3}`);
|
|
39357
39357
|
return { hex: null, error: "invalid_id" };
|
|
39358
39358
|
}
|
|
39359
39359
|
const pk = pkMatch[1];
|
|
@@ -39438,13 +39438,13 @@ function parseChecklistFromProtobuf(data) {
|
|
|
39438
39438
|
return null;
|
|
39439
39439
|
}
|
|
39440
39440
|
}
|
|
39441
|
-
function getChecklistItems(
|
|
39442
|
-
const { hex: hexData, error: queryError } = queryNoteData(
|
|
39441
|
+
function getChecklistItems(noteId3) {
|
|
39442
|
+
const { hex: hexData, error: queryError } = queryNoteData(noteId3);
|
|
39443
39443
|
if (queryError === "invalid_id") {
|
|
39444
39444
|
return {
|
|
39445
39445
|
items: null,
|
|
39446
39446
|
error: "invalid_id",
|
|
39447
|
-
message: `Invalid note ID format: "${
|
|
39447
|
+
message: `Invalid note ID format: "${noteId3}". Expected format: x-coredata://UUID/ICNote/pNNN`
|
|
39448
39448
|
};
|
|
39449
39449
|
}
|
|
39450
39450
|
if (queryError === "no_fda") {
|
|
@@ -40281,20 +40281,20 @@ var AppleNotesManager = class {
|
|
|
40281
40281
|
return null;
|
|
40282
40282
|
}
|
|
40283
40283
|
const rawOutput = result.output.trim();
|
|
40284
|
-
const
|
|
40285
|
-
if (!
|
|
40284
|
+
const noteId3 = extractCoreDataId(rawOutput, "note") || rawOutput;
|
|
40285
|
+
if (!noteId3) {
|
|
40286
40286
|
console.error(`Created note "${title}" but Notes.app returned no canonical note ID`);
|
|
40287
40287
|
return null;
|
|
40288
40288
|
}
|
|
40289
40289
|
try {
|
|
40290
|
-
sanitizeNoteId(
|
|
40290
|
+
sanitizeNoteId(noteId3);
|
|
40291
40291
|
} catch {
|
|
40292
40292
|
console.error(`Created note "${title}" but Notes.app returned an invalid note ID`);
|
|
40293
40293
|
return null;
|
|
40294
40294
|
}
|
|
40295
40295
|
const now = /* @__PURE__ */ new Date();
|
|
40296
40296
|
return {
|
|
40297
|
-
id:
|
|
40297
|
+
id: noteId3,
|
|
40298
40298
|
title,
|
|
40299
40299
|
content,
|
|
40300
40300
|
tags,
|
|
@@ -40408,11 +40408,11 @@ var AppleNotesManager = class {
|
|
|
40408
40408
|
for (const item of items) {
|
|
40409
40409
|
const [title, id, folder2, created, modified] = item.split(FIELD_SEP);
|
|
40410
40410
|
if (!title?.trim()) continue;
|
|
40411
|
-
const
|
|
40412
|
-
if (seenIds.has(
|
|
40413
|
-
seenIds.add(
|
|
40411
|
+
const noteId3 = id?.trim() || generateFallbackId();
|
|
40412
|
+
if (seenIds.has(noteId3)) continue;
|
|
40413
|
+
seenIds.add(noteId3);
|
|
40414
40414
|
notes.push({
|
|
40415
|
-
id:
|
|
40415
|
+
id: noteId3,
|
|
40416
40416
|
title: title.trim(),
|
|
40417
40417
|
content: "",
|
|
40418
40418
|
// Not fetched in search
|
|
@@ -40780,10 +40780,10 @@ var AppleNotesManager = class {
|
|
|
40780
40780
|
for (const item of output.split(RECORD_SEP)) {
|
|
40781
40781
|
const [title, id] = item.split(FIELD_SEP);
|
|
40782
40782
|
if (!title?.trim()) continue;
|
|
40783
|
-
const
|
|
40784
|
-
if (seenIds.has(
|
|
40785
|
-
seenIds.add(
|
|
40786
|
-
refs.push({ title: title.trim(), id:
|
|
40783
|
+
const noteId3 = id?.trim() || generateFallbackId();
|
|
40784
|
+
if (seenIds.has(noteId3)) continue;
|
|
40785
|
+
seenIds.add(noteId3);
|
|
40786
|
+
refs.push({ title: title.trim(), id: noteId3 });
|
|
40787
40787
|
if (safeLimit !== void 0 && refs.length >= safeLimit) break;
|
|
40788
40788
|
}
|
|
40789
40789
|
return refs;
|
|
@@ -41435,8 +41435,8 @@ var AppleNotesManager = class {
|
|
|
41435
41435
|
* @param separately - Open in a separate window when supported by Notes.app
|
|
41436
41436
|
* @returns true if Notes.app revealed the attachment, false otherwise
|
|
41437
41437
|
*/
|
|
41438
|
-
showAttachmentById(
|
|
41439
|
-
const safeNoteId = sanitizeId(
|
|
41438
|
+
showAttachmentById(noteId3, attachmentId, separately = false) {
|
|
41439
|
+
const safeNoteId = sanitizeId(noteId3);
|
|
41440
41440
|
const safeAttId = escapePlainStringForAppleScript(attachmentId);
|
|
41441
41441
|
const separatelyClause = separately ? " separately true" : "";
|
|
41442
41442
|
const script = `
|
|
@@ -41456,13 +41456,13 @@ var AppleNotesManager = class {
|
|
|
41456
41456
|
const result = executeMutationAppleScript(script);
|
|
41457
41457
|
if (!result.success) {
|
|
41458
41458
|
console.error(
|
|
41459
|
-
`Failed to show attachment "${attachmentId}" on note "${
|
|
41459
|
+
`Failed to show attachment "${attachmentId}" on note "${noteId3}":`,
|
|
41460
41460
|
result.error
|
|
41461
41461
|
);
|
|
41462
41462
|
return false;
|
|
41463
41463
|
}
|
|
41464
41464
|
if ((result.output ?? "").trim().startsWith("ERR")) {
|
|
41465
|
-
console.error(`Attachment "${attachmentId}" not found on note "${
|
|
41465
|
+
console.error(`Attachment "${attachmentId}" not found on note "${noteId3}"`);
|
|
41466
41466
|
return false;
|
|
41467
41467
|
}
|
|
41468
41468
|
return true;
|
|
@@ -41862,7 +41862,7 @@ var AppleNotesManager = class {
|
|
|
41862
41862
|
* @param savePath - absolute destination file path (within home / temp / /Volumes)
|
|
41863
41863
|
* @returns { success, savedPath?, name?, contentType?, error? }
|
|
41864
41864
|
*/
|
|
41865
|
-
saveAttachmentById(
|
|
41865
|
+
saveAttachmentById(noteId3, attachmentId, savePath) {
|
|
41866
41866
|
let abs;
|
|
41867
41867
|
try {
|
|
41868
41868
|
abs = assertSafeSavePath(savePath);
|
|
@@ -41870,7 +41870,7 @@ var AppleNotesManager = class {
|
|
|
41870
41870
|
} catch (e) {
|
|
41871
41871
|
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
41872
41872
|
}
|
|
41873
|
-
const safeNoteId = sanitizeId(
|
|
41873
|
+
const safeNoteId = sanitizeId(noteId3);
|
|
41874
41874
|
const safeAttId = escapePlainStringForAppleScript(attachmentId);
|
|
41875
41875
|
const safePath = escapePlainStringForAppleScript(abs);
|
|
41876
41876
|
const script = `
|
|
@@ -41934,11 +41934,11 @@ var AppleNotesManager = class {
|
|
|
41934
41934
|
* @param attachmentId - id of the attachment
|
|
41935
41935
|
* @returns { success, name?, contentType?, base64?, bytes?, error? }
|
|
41936
41936
|
*/
|
|
41937
|
-
getAttachmentBase64ById(
|
|
41937
|
+
getAttachmentBase64ById(noteId3, attachmentId) {
|
|
41938
41938
|
const dir = makeTempDir();
|
|
41939
41939
|
try {
|
|
41940
41940
|
const dest = `${dir}/attachment.bin`;
|
|
41941
|
-
const saved = this.saveAttachmentById(
|
|
41941
|
+
const saved = this.saveAttachmentById(noteId3, attachmentId, dest);
|
|
41942
41942
|
if (!saved.success || !saved.savedPath) {
|
|
41943
41943
|
return { success: false, error: saved.error };
|
|
41944
41944
|
}
|
|
@@ -42438,13 +42438,13 @@ function presentColumns() {
|
|
|
42438
42438
|
}
|
|
42439
42439
|
return cols;
|
|
42440
42440
|
}
|
|
42441
|
-
function getNoteMetadata(
|
|
42442
|
-
const pkMatch =
|
|
42441
|
+
function getNoteMetadata(noteId3) {
|
|
42442
|
+
const pkMatch = noteId3.match(/\/p(\d+)$/);
|
|
42443
42443
|
if (!pkMatch) {
|
|
42444
42444
|
return {
|
|
42445
42445
|
metadata: null,
|
|
42446
42446
|
error: "invalid_id",
|
|
42447
|
-
message: `Invalid note ID format: "${
|
|
42447
|
+
message: `Invalid note ID format: "${noteId3}". Expected format: x-coredata://UUID/ICNote/pNNN`
|
|
42448
42448
|
};
|
|
42449
42449
|
}
|
|
42450
42450
|
const pk = pkMatch[1];
|
|
@@ -42465,7 +42465,7 @@ function getNoteMetadata(noteId2) {
|
|
|
42465
42465
|
return {
|
|
42466
42466
|
metadata: null,
|
|
42467
42467
|
error: "not_found",
|
|
42468
|
-
message: `No note found in the database for ID "${
|
|
42468
|
+
message: `No note found in the database for ID "${noteId3}".`
|
|
42469
42469
|
};
|
|
42470
42470
|
}
|
|
42471
42471
|
const raw = JSON.parse(row);
|
|
@@ -43191,6 +43191,201 @@ function registerDirectOperations(server2, manager) {
|
|
|
43191
43191
|
);
|
|
43192
43192
|
}
|
|
43193
43193
|
|
|
43194
|
+
// src/services/nativeTags.ts
|
|
43195
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
43196
|
+
import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync2, rmSync as rmSync3 } from "node:fs";
|
|
43197
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
43198
|
+
import { join as join9 } from "node:path";
|
|
43199
|
+
var NATIVE_TAGS_SHORTCUT = "Apple Notes MCP - Native Tags";
|
|
43200
|
+
function normalizeNativeTags(tags) {
|
|
43201
|
+
if (!tags.length || tags.length > 100) throw new Error("Provide between 1 and 100 tags");
|
|
43202
|
+
return [
|
|
43203
|
+
...new Set(
|
|
43204
|
+
tags.map((value) => {
|
|
43205
|
+
const tag = value.normalize("NFC").replace(/^#/, "");
|
|
43206
|
+
if (tag.length > 100 || !new RegExp("^(?=.*\\p{L})[\\p{L}\\p{N}_-]+$", "u").test(tag))
|
|
43207
|
+
throw new Error(
|
|
43208
|
+
"Tags must contain a letter and only letters, digits, hyphens or underscores"
|
|
43209
|
+
);
|
|
43210
|
+
return tag;
|
|
43211
|
+
})
|
|
43212
|
+
)
|
|
43213
|
+
];
|
|
43214
|
+
}
|
|
43215
|
+
function addNativeTags(request, deps) {
|
|
43216
|
+
if (!/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i.test(request.id))
|
|
43217
|
+
throw new Error("An exact CoreData note ID is required");
|
|
43218
|
+
if (request.scopeText.length < 12 || request.scopeText.length > 500 || /[\r\n\0]/u.test(request.scopeText))
|
|
43219
|
+
throw new Error("scopeText must be a stable, single-line project marker of 12\u2013500 characters");
|
|
43220
|
+
const tags = normalizeNativeTags(request.tags);
|
|
43221
|
+
const before = deps.read(request.id);
|
|
43222
|
+
if (before.contentHash !== request.expectedContentHash)
|
|
43223
|
+
throw new Error("Note revision changed; read it again");
|
|
43224
|
+
if (before.title !== request.title || !before.plaintext.includes(request.scopeText))
|
|
43225
|
+
throw new Error("The exact note does not match the title and project marker");
|
|
43226
|
+
const missing = tags.filter((tag) => !before.rich.nativeTags.includes(tag));
|
|
43227
|
+
if (!missing.length)
|
|
43228
|
+
return { nativeTags: before.rich.nativeTags, added: [], contentHash: before.contentHash };
|
|
43229
|
+
const candidates = deps.candidates(request.title, request.scopeText);
|
|
43230
|
+
if (candidates.length !== 1 || candidates[0] !== request.id)
|
|
43231
|
+
throw new Error(
|
|
43232
|
+
"Shortcuts selection is ambiguous or points to a different note; nothing was changed"
|
|
43233
|
+
);
|
|
43234
|
+
if (deps.read(request.id).contentHash !== request.expectedContentHash)
|
|
43235
|
+
throw new Error("Note revision changed during preflight; nothing was changed");
|
|
43236
|
+
let transportWarning;
|
|
43237
|
+
try {
|
|
43238
|
+
deps.run({ title: request.title, scopeText: request.scopeText, tags: missing });
|
|
43239
|
+
} catch (error2) {
|
|
43240
|
+
transportWarning = error2 instanceof Error ? error2.message : "Shortcuts completion was uncertain";
|
|
43241
|
+
}
|
|
43242
|
+
const after = deps.read(request.id);
|
|
43243
|
+
const allTags = [.../* @__PURE__ */ new Set([...before.rich.nativeTags, ...tags])];
|
|
43244
|
+
const textWithoutTags = (text) => {
|
|
43245
|
+
for (const tag of [...allTags].sort((a, b) => b.length - a.length)) {
|
|
43246
|
+
const escaped = tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
43247
|
+
text = text.replace(new RegExp(`#${escaped}(?![\\p{L}\\p{N}_-])`, "gu"), "");
|
|
43248
|
+
}
|
|
43249
|
+
return text.replace(/[\s\ufffc]/gu, "");
|
|
43250
|
+
};
|
|
43251
|
+
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((id) => !after.rich.nativeObjectIds.includes(id)) || before.rich.hasChecklist !== after.rich.hasChecklist) {
|
|
43252
|
+
throw new Error(
|
|
43253
|
+
"Shortcuts ran, but exact-ID tags/text/links readback was not verified. Read the note before any retry"
|
|
43254
|
+
);
|
|
43255
|
+
}
|
|
43256
|
+
return {
|
|
43257
|
+
nativeTags: after.rich.nativeTags,
|
|
43258
|
+
added: missing,
|
|
43259
|
+
contentHash: after.contentHash,
|
|
43260
|
+
...transportWarning ? {
|
|
43261
|
+
transportWarning: "Shortcuts completion was uncertain, but all requested native tags and preserved content were verified by exact ID."
|
|
43262
|
+
} : {}
|
|
43263
|
+
};
|
|
43264
|
+
}
|
|
43265
|
+
function nativeTagsStatus(shortcut = process.env.APPLE_NOTES_MCP_TAGS_SHORTCUT || NATIVE_TAGS_SHORTCUT) {
|
|
43266
|
+
const lines = execFileSync6("/usr/bin/shortcuts", ["list", "--show-identifiers"], {
|
|
43267
|
+
encoding: "utf8",
|
|
43268
|
+
timeout: 15e3,
|
|
43269
|
+
maxBuffer: 1024 * 1024,
|
|
43270
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
43271
|
+
}).split(/\r?\n/u);
|
|
43272
|
+
const matches = lines.flatMap((line) => {
|
|
43273
|
+
const match = /^(.*) \(([0-9A-Fa-f-]{36})\)$/.exec(line);
|
|
43274
|
+
return match && (match[1] === shortcut || match[2].toLowerCase() === shortcut.toLowerCase()) ? [{ name: match[1], identifier: match[2] }] : [];
|
|
43275
|
+
});
|
|
43276
|
+
return {
|
|
43277
|
+
shortcut,
|
|
43278
|
+
installed: matches.length === 1,
|
|
43279
|
+
identifier: matches.length === 1 ? matches[0].identifier : void 0
|
|
43280
|
+
};
|
|
43281
|
+
}
|
|
43282
|
+
function runNativeTagsShortcut(input) {
|
|
43283
|
+
const status = nativeTagsStatus();
|
|
43284
|
+
if (!status.installed)
|
|
43285
|
+
throw new Error(`Import the supplied ${status.shortcut}.shortcut in Shortcuts first`);
|
|
43286
|
+
const directory = mkdtempSync3(join9(tmpdir3(), "apple-notes-native-tags-"));
|
|
43287
|
+
try {
|
|
43288
|
+
const path4 = join9(directory, "request.json");
|
|
43289
|
+
writeFileSync2(path4, JSON.stringify(input), { mode: 384 });
|
|
43290
|
+
execFileSync6("/usr/bin/shortcuts", ["run", status.identifier, "--input-path", path4], {
|
|
43291
|
+
encoding: "utf8",
|
|
43292
|
+
timeout: 6e4,
|
|
43293
|
+
maxBuffer: 1024 * 1024,
|
|
43294
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
43295
|
+
});
|
|
43296
|
+
} catch {
|
|
43297
|
+
throw new Error(
|
|
43298
|
+
"Native tag operation did not complete cleanly (possibly waiting for macOS permission). Do not retry automatically; read the exact note and check Shortcuts"
|
|
43299
|
+
);
|
|
43300
|
+
} finally {
|
|
43301
|
+
rmSync3(directory, { recursive: true, force: true });
|
|
43302
|
+
}
|
|
43303
|
+
}
|
|
43304
|
+
|
|
43305
|
+
// src/tools/nativeTagsBridge.ts
|
|
43306
|
+
var noteId2 = external_exports.string().regex(/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i);
|
|
43307
|
+
var revision2 = external_exports.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
43308
|
+
function registerNativeTagsBridge(server2, manager) {
|
|
43309
|
+
function tool(name, description, inputSchema, handler) {
|
|
43310
|
+
server2.registerTool(
|
|
43311
|
+
name,
|
|
43312
|
+
{
|
|
43313
|
+
description,
|
|
43314
|
+
inputSchema,
|
|
43315
|
+
outputSchema: external_exports.object({ ok: external_exports.boolean().optional() }).passthrough()
|
|
43316
|
+
},
|
|
43317
|
+
(async (args) => {
|
|
43318
|
+
try {
|
|
43319
|
+
const result = handler(args);
|
|
43320
|
+
return {
|
|
43321
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
43322
|
+
structuredContent: result
|
|
43323
|
+
};
|
|
43324
|
+
} catch (error2) {
|
|
43325
|
+
return {
|
|
43326
|
+
content: [
|
|
43327
|
+
{
|
|
43328
|
+
type: "text",
|
|
43329
|
+
text: error2 instanceof Error ? error2.message : String(error2)
|
|
43330
|
+
}
|
|
43331
|
+
],
|
|
43332
|
+
isError: true
|
|
43333
|
+
};
|
|
43334
|
+
}
|
|
43335
|
+
})
|
|
43336
|
+
);
|
|
43337
|
+
}
|
|
43338
|
+
const read = (id) => {
|
|
43339
|
+
const note = manager.getNoteById(id);
|
|
43340
|
+
if (!note) throw new Error("Note not found");
|
|
43341
|
+
if (note.passwordProtected) throw new Error("Locked notes cannot receive native tags");
|
|
43342
|
+
const body = manager.getNoteContentById(id);
|
|
43343
|
+
if (!body) throw new Error("Note content is unavailable");
|
|
43344
|
+
const enriched = enrichNoteRead(id, body);
|
|
43345
|
+
const rich = readRichNote(id);
|
|
43346
|
+
if (!enriched.complete || enriched.revision !== rich.revision)
|
|
43347
|
+
throw new Error("Native metadata changed during read; read the note again");
|
|
43348
|
+
return {
|
|
43349
|
+
contentHash: richContentHash(body, enriched),
|
|
43350
|
+
title: note.title,
|
|
43351
|
+
plaintext: manager.getNotePlaintextById(id),
|
|
43352
|
+
rich
|
|
43353
|
+
};
|
|
43354
|
+
};
|
|
43355
|
+
tool(
|
|
43356
|
+
"native-tags-status",
|
|
43357
|
+
"Use when: checking whether the Native Tags Shortcut is installed before a tag write.\nReturns: the configured Shortcut name, unique installed identifier, and installed state.\nDo not use when: listing tags on notes (list-native-tags).\nSafety: read-only; installation does not by itself prove Notes permission or a successful live mutation.",
|
|
43358
|
+
{},
|
|
43359
|
+
() => nativeTagsStatus()
|
|
43360
|
+
);
|
|
43361
|
+
tool(
|
|
43362
|
+
"add-native-tags",
|
|
43363
|
+
"Use when: adding real clickable Apple Notes tags to one exact, freshly read note.\nReturns: verified native tags, additions, and the post-write content hash.\nDo not use when: textual #hashtags are sufficient or the note cannot be selected uniquely by its existing title and scope text.\nSafety: requires exact ID, fresh revision, and a distinctive existing scope phrase; verifies original text, links, and native objects after the Shortcut runs and never retries automatically.",
|
|
43364
|
+
{
|
|
43365
|
+
id: noteId2,
|
|
43366
|
+
expectedContentHash: revision2,
|
|
43367
|
+
scopeText: external_exports.string().min(12).max(500),
|
|
43368
|
+
tags: external_exports.array(external_exports.string().min(1).max(101)).min(1).max(100)
|
|
43369
|
+
},
|
|
43370
|
+
({ id, expectedContentHash, scopeText, tags }) => {
|
|
43371
|
+
const initial = read(id);
|
|
43372
|
+
const result = addNativeTags(
|
|
43373
|
+
{ id, expectedContentHash, scopeText, tags, title: initial.title },
|
|
43374
|
+
{
|
|
43375
|
+
read,
|
|
43376
|
+
candidates: (title, scope) => manager.listAccounts().flatMap(
|
|
43377
|
+
(account) => manager.searchNotes(title, false, account.name).filter(
|
|
43378
|
+
(note) => !note.passwordProtected && manager.getNotePlaintextById(note.id).toLocaleLowerCase().includes(scope.toLocaleLowerCase())
|
|
43379
|
+
).map((note) => note.id)
|
|
43380
|
+
),
|
|
43381
|
+
run: runNativeTagsShortcut
|
|
43382
|
+
}
|
|
43383
|
+
);
|
|
43384
|
+
return { ok: true, id, ...result };
|
|
43385
|
+
}
|
|
43386
|
+
);
|
|
43387
|
+
}
|
|
43388
|
+
|
|
43194
43389
|
// src/index.ts
|
|
43195
43390
|
loadFileConfig();
|
|
43196
43391
|
var require2 = createRequire(import.meta.url);
|
|
@@ -43202,6 +43397,7 @@ var server = new McpServer({
|
|
|
43202
43397
|
});
|
|
43203
43398
|
var notesManager = new AppleNotesManager();
|
|
43204
43399
|
registerDirectOperations(server, notesManager);
|
|
43400
|
+
registerNativeTagsBridge(server, notesManager);
|
|
43205
43401
|
function successResponse(message, structured) {
|
|
43206
43402
|
const res = { content: [{ type: "text", text: message }] };
|
|
43207
43403
|
if (structured) res.structuredContent = structured;
|
|
@@ -44697,8 +44893,8 @@ registerTool(
|
|
|
44697
44893
|
contentType: external_exports.string().optional()
|
|
44698
44894
|
}
|
|
44699
44895
|
},
|
|
44700
|
-
withErrorHandling(({ noteId:
|
|
44701
|
-
const r = notesManager.saveAttachmentById(
|
|
44896
|
+
withErrorHandling(({ noteId: noteId3, attachmentId, savePath }) => {
|
|
44897
|
+
const r = notesManager.saveAttachmentById(noteId3, attachmentId, savePath);
|
|
44702
44898
|
if (!r.success) {
|
|
44703
44899
|
return errorResponse(`Failed to save attachment: ${r.error ?? "unknown error"}`);
|
|
44704
44900
|
}
|
|
@@ -44724,8 +44920,8 @@ registerTool(
|
|
|
44724
44920
|
base64: external_exports.string().optional()
|
|
44725
44921
|
}
|
|
44726
44922
|
},
|
|
44727
|
-
withErrorHandling(({ noteId:
|
|
44728
|
-
const r = notesManager.getAttachmentBase64ById(
|
|
44923
|
+
withErrorHandling(({ noteId: noteId3, attachmentId }) => {
|
|
44924
|
+
const r = notesManager.getAttachmentBase64ById(noteId3, attachmentId);
|
|
44729
44925
|
if (!r.success || !r.base64) {
|
|
44730
44926
|
return errorResponse(`Failed to fetch attachment: ${r.error ?? "unknown error"}`);
|
|
44731
44927
|
}
|
|
@@ -44750,13 +44946,13 @@ registerTool(
|
|
|
44750
44946
|
separately: external_exports.boolean().optional()
|
|
44751
44947
|
}
|
|
44752
44948
|
},
|
|
44753
|
-
withErrorHandling(({ noteId:
|
|
44754
|
-
const success = notesManager.showAttachmentById(
|
|
44949
|
+
withErrorHandling(({ noteId: noteId3, attachmentId, separately = false }) => {
|
|
44950
|
+
const success = notesManager.showAttachmentById(noteId3, attachmentId, separately);
|
|
44755
44951
|
if (!success) {
|
|
44756
|
-
return errorResponse(`Failed to show attachment "${attachmentId}" on note "${
|
|
44952
|
+
return errorResponse(`Failed to show attachment "${attachmentId}" on note "${noteId3}"`);
|
|
44757
44953
|
}
|
|
44758
44954
|
return successResponse(`Shown attachment "${attachmentId}" in Notes.app`, {
|
|
44759
|
-
noteId:
|
|
44955
|
+
noteId: noteId3,
|
|
44760
44956
|
attachmentId,
|
|
44761
44957
|
separately
|
|
44762
44958
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-notes-mcp",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.8",
|
|
4
4
|
"description": "MCP server for Apple Notes - create, search, update, and manage notes via Claude and other AI assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"build",
|
|
13
13
|
"docs",
|
|
14
|
+
"shortcuts",
|
|
14
15
|
"README.md",
|
|
15
16
|
"LICENSE"
|
|
16
17
|
],
|
|
Binary file
|
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>WFWorkflowName</key>
|
|
6
|
+
<string>Apple Notes MCP - Native Tags</string>
|
|
7
|
+
<key>WFWorkflowActions</key>
|
|
8
|
+
<array>
|
|
9
|
+
<dict>
|
|
10
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
11
|
+
<string>is.workflow.actions.comment</string>
|
|
12
|
+
<key>WFWorkflowActionParameters</key>
|
|
13
|
+
<dict>
|
|
14
|
+
<key>UUID</key>
|
|
15
|
+
<string>0098B800-B098-5A38-8E5B-4D2491ACD95D</string>
|
|
16
|
+
<key>WFCommentActionText</key>
|
|
17
|
+
<string>Adds native tags to one note selected by title and existing project scope text. Refuses zero/multiple results. Input: JSON {title, scopeText, tags}. No scripts, network, deletion or body replacement. The MCP checks exact ID/revision before and verifies native tags/text/links afterward.</string>
|
|
18
|
+
</dict>
|
|
19
|
+
</dict>
|
|
20
|
+
<dict>
|
|
21
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
22
|
+
<string>is.workflow.actions.detect.dictionary</string>
|
|
23
|
+
<key>WFWorkflowActionParameters</key>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>UUID</key>
|
|
26
|
+
<string>FC6F66A2-7C9E-5A6C-A530-61B12F8030DC</string>
|
|
27
|
+
<key>WFInput</key>
|
|
28
|
+
<dict>
|
|
29
|
+
<key>Value</key>
|
|
30
|
+
<dict>
|
|
31
|
+
<key>Type</key>
|
|
32
|
+
<string>ExtensionInput</string>
|
|
33
|
+
</dict>
|
|
34
|
+
<key>WFSerializationType</key>
|
|
35
|
+
<string>WFTextTokenAttachment</string>
|
|
36
|
+
</dict>
|
|
37
|
+
</dict>
|
|
38
|
+
</dict>
|
|
39
|
+
<dict>
|
|
40
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
41
|
+
<string>is.workflow.actions.getvalueforkey</string>
|
|
42
|
+
<key>WFWorkflowActionParameters</key>
|
|
43
|
+
<dict>
|
|
44
|
+
<key>UUID</key>
|
|
45
|
+
<string>56F624A3-B9C4-59B9-9BD5-B0A3D539EB60</string>
|
|
46
|
+
<key>WFInput</key>
|
|
47
|
+
<dict>
|
|
48
|
+
<key>Value</key>
|
|
49
|
+
<dict>
|
|
50
|
+
<key>Type</key>
|
|
51
|
+
<string>ActionOutput</string>
|
|
52
|
+
<key>OutputUUID</key>
|
|
53
|
+
<string>FC6F66A2-7C9E-5A6C-A530-61B12F8030DC</string>
|
|
54
|
+
<key>OutputName</key>
|
|
55
|
+
<string>request</string>
|
|
56
|
+
</dict>
|
|
57
|
+
<key>WFSerializationType</key>
|
|
58
|
+
<string>WFTextTokenAttachment</string>
|
|
59
|
+
</dict>
|
|
60
|
+
<key>WFDictionaryKey</key>
|
|
61
|
+
<string>title</string>
|
|
62
|
+
<key>WFGetDictionaryValueType</key>
|
|
63
|
+
<string>Value</string>
|
|
64
|
+
</dict>
|
|
65
|
+
</dict>
|
|
66
|
+
<dict>
|
|
67
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
68
|
+
<string>is.workflow.actions.getvalueforkey</string>
|
|
69
|
+
<key>WFWorkflowActionParameters</key>
|
|
70
|
+
<dict>
|
|
71
|
+
<key>UUID</key>
|
|
72
|
+
<string>ECA164BD-137A-567C-87AF-C5F3F32F84BF</string>
|
|
73
|
+
<key>WFInput</key>
|
|
74
|
+
<dict>
|
|
75
|
+
<key>Value</key>
|
|
76
|
+
<dict>
|
|
77
|
+
<key>Type</key>
|
|
78
|
+
<string>ActionOutput</string>
|
|
79
|
+
<key>OutputUUID</key>
|
|
80
|
+
<string>FC6F66A2-7C9E-5A6C-A530-61B12F8030DC</string>
|
|
81
|
+
<key>OutputName</key>
|
|
82
|
+
<string>request</string>
|
|
83
|
+
</dict>
|
|
84
|
+
<key>WFSerializationType</key>
|
|
85
|
+
<string>WFTextTokenAttachment</string>
|
|
86
|
+
</dict>
|
|
87
|
+
<key>WFDictionaryKey</key>
|
|
88
|
+
<string>scopeText</string>
|
|
89
|
+
<key>WFGetDictionaryValueType</key>
|
|
90
|
+
<string>Value</string>
|
|
91
|
+
</dict>
|
|
92
|
+
</dict>
|
|
93
|
+
<dict>
|
|
94
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
95
|
+
<string>is.workflow.actions.getvalueforkey</string>
|
|
96
|
+
<key>WFWorkflowActionParameters</key>
|
|
97
|
+
<dict>
|
|
98
|
+
<key>UUID</key>
|
|
99
|
+
<string>40662BA1-53A6-58B0-A54E-A9174F25AB48</string>
|
|
100
|
+
<key>WFInput</key>
|
|
101
|
+
<dict>
|
|
102
|
+
<key>Value</key>
|
|
103
|
+
<dict>
|
|
104
|
+
<key>Type</key>
|
|
105
|
+
<string>ActionOutput</string>
|
|
106
|
+
<key>OutputUUID</key>
|
|
107
|
+
<string>FC6F66A2-7C9E-5A6C-A530-61B12F8030DC</string>
|
|
108
|
+
<key>OutputName</key>
|
|
109
|
+
<string>request</string>
|
|
110
|
+
</dict>
|
|
111
|
+
<key>WFSerializationType</key>
|
|
112
|
+
<string>WFTextTokenAttachment</string>
|
|
113
|
+
</dict>
|
|
114
|
+
<key>WFDictionaryKey</key>
|
|
115
|
+
<string>tags</string>
|
|
116
|
+
<key>WFGetDictionaryValueType</key>
|
|
117
|
+
<string>Value</string>
|
|
118
|
+
</dict>
|
|
119
|
+
</dict>
|
|
120
|
+
<dict>
|
|
121
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
122
|
+
<string>is.workflow.actions.filter.notes</string>
|
|
123
|
+
<key>WFWorkflowActionParameters</key>
|
|
124
|
+
<dict>
|
|
125
|
+
<key>UUID</key>
|
|
126
|
+
<string>DFF87C25-7AF8-55BC-BA5F-4F08CC05A668</string>
|
|
127
|
+
<key>WFContentItemLimitEnabled</key>
|
|
128
|
+
<false/>
|
|
129
|
+
<key>WFContentItemFilter</key>
|
|
130
|
+
<dict>
|
|
131
|
+
<key>WFSerializationType</key>
|
|
132
|
+
<string>WFContentPredicateTableTemplate</string>
|
|
133
|
+
<key>Value</key>
|
|
134
|
+
<dict>
|
|
135
|
+
<key>WFActionParameterFilterPrefix</key>
|
|
136
|
+
<integer>1</integer>
|
|
137
|
+
<key>WFContentPredicateBoundedDate</key>
|
|
138
|
+
<false/>
|
|
139
|
+
<key>WFActionParameterFilterTemplates</key>
|
|
140
|
+
<array>
|
|
141
|
+
<dict>
|
|
142
|
+
<key>Property</key>
|
|
143
|
+
<string>Name</string>
|
|
144
|
+
<key>Operator</key>
|
|
145
|
+
<integer>99</integer>
|
|
146
|
+
<key>Removable</key>
|
|
147
|
+
<true/>
|
|
148
|
+
<key>Values</key>
|
|
149
|
+
<dict>
|
|
150
|
+
<key>String</key>
|
|
151
|
+
<dict>
|
|
152
|
+
<key>WFSerializationType</key>
|
|
153
|
+
<string>WFTextTokenString</string>
|
|
154
|
+
<key>Value</key>
|
|
155
|
+
<dict>
|
|
156
|
+
<key>string</key>
|
|
157
|
+
<string></string>
|
|
158
|
+
<key>attachmentsByRange</key>
|
|
159
|
+
<dict>
|
|
160
|
+
<key>{0, 1}</key>
|
|
161
|
+
<dict>
|
|
162
|
+
<key>Type</key>
|
|
163
|
+
<string>ActionOutput</string>
|
|
164
|
+
<key>OutputUUID</key>
|
|
165
|
+
<string>56F624A3-B9C4-59B9-9BD5-B0A3D539EB60</string>
|
|
166
|
+
<key>OutputName</key>
|
|
167
|
+
<string>title</string>
|
|
168
|
+
</dict>
|
|
169
|
+
</dict>
|
|
170
|
+
</dict>
|
|
171
|
+
</dict>
|
|
172
|
+
</dict>
|
|
173
|
+
</dict>
|
|
174
|
+
<dict>
|
|
175
|
+
<key>Property</key>
|
|
176
|
+
<string>Body</string>
|
|
177
|
+
<key>Operator</key>
|
|
178
|
+
<integer>99</integer>
|
|
179
|
+
<key>Removable</key>
|
|
180
|
+
<true/>
|
|
181
|
+
<key>Values</key>
|
|
182
|
+
<dict>
|
|
183
|
+
<key>String</key>
|
|
184
|
+
<dict>
|
|
185
|
+
<key>WFSerializationType</key>
|
|
186
|
+
<string>WFTextTokenString</string>
|
|
187
|
+
<key>Value</key>
|
|
188
|
+
<dict>
|
|
189
|
+
<key>string</key>
|
|
190
|
+
<string></string>
|
|
191
|
+
<key>attachmentsByRange</key>
|
|
192
|
+
<dict>
|
|
193
|
+
<key>{0, 1}</key>
|
|
194
|
+
<dict>
|
|
195
|
+
<key>Type</key>
|
|
196
|
+
<string>ActionOutput</string>
|
|
197
|
+
<key>OutputUUID</key>
|
|
198
|
+
<string>ECA164BD-137A-567C-87AF-C5F3F32F84BF</string>
|
|
199
|
+
<key>OutputName</key>
|
|
200
|
+
<string>scopeText</string>
|
|
201
|
+
</dict>
|
|
202
|
+
</dict>
|
|
203
|
+
</dict>
|
|
204
|
+
</dict>
|
|
205
|
+
</dict>
|
|
206
|
+
</dict>
|
|
207
|
+
</array>
|
|
208
|
+
</dict>
|
|
209
|
+
</dict>
|
|
210
|
+
</dict>
|
|
211
|
+
</dict>
|
|
212
|
+
<dict>
|
|
213
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
214
|
+
<string>is.workflow.actions.count</string>
|
|
215
|
+
<key>WFWorkflowActionParameters</key>
|
|
216
|
+
<dict>
|
|
217
|
+
<key>UUID</key>
|
|
218
|
+
<string>48769A7C-915C-5339-9CD4-09D8E576EA11</string>
|
|
219
|
+
<key>Input</key>
|
|
220
|
+
<dict>
|
|
221
|
+
<key>Value</key>
|
|
222
|
+
<dict>
|
|
223
|
+
<key>Type</key>
|
|
224
|
+
<string>ActionOutput</string>
|
|
225
|
+
<key>OutputUUID</key>
|
|
226
|
+
<string>DFF87C25-7AF8-55BC-BA5F-4F08CC05A668</string>
|
|
227
|
+
<key>OutputName</key>
|
|
228
|
+
<string>target</string>
|
|
229
|
+
</dict>
|
|
230
|
+
<key>WFSerializationType</key>
|
|
231
|
+
<string>WFTextTokenAttachment</string>
|
|
232
|
+
</dict>
|
|
233
|
+
<key>WFCountType</key>
|
|
234
|
+
<string>Items</string>
|
|
235
|
+
</dict>
|
|
236
|
+
</dict>
|
|
237
|
+
<dict>
|
|
238
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
239
|
+
<string>is.workflow.actions.gettext</string>
|
|
240
|
+
<key>WFWorkflowActionParameters</key>
|
|
241
|
+
<dict>
|
|
242
|
+
<key>UUID</key>
|
|
243
|
+
<string>506724BB-49FB-5E33-A2DB-C392798691A7</string>
|
|
244
|
+
<key>WFTextActionText</key>
|
|
245
|
+
<dict>
|
|
246
|
+
<key>WFSerializationType</key>
|
|
247
|
+
<string>WFTextTokenString</string>
|
|
248
|
+
<key>Value</key>
|
|
249
|
+
<dict>
|
|
250
|
+
<key>string</key>
|
|
251
|
+
<string></string>
|
|
252
|
+
<key>attachmentsByRange</key>
|
|
253
|
+
<dict>
|
|
254
|
+
<key>{0, 1}</key>
|
|
255
|
+
<dict>
|
|
256
|
+
<key>Type</key>
|
|
257
|
+
<string>ActionOutput</string>
|
|
258
|
+
<key>OutputUUID</key>
|
|
259
|
+
<string>48769A7C-915C-5339-9CD4-09D8E576EA11</string>
|
|
260
|
+
<key>OutputName</key>
|
|
261
|
+
<string>count</string>
|
|
262
|
+
</dict>
|
|
263
|
+
</dict>
|
|
264
|
+
</dict>
|
|
265
|
+
</dict>
|
|
266
|
+
</dict>
|
|
267
|
+
</dict>
|
|
268
|
+
<dict>
|
|
269
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
270
|
+
<string>is.workflow.actions.conditional</string>
|
|
271
|
+
<key>WFWorkflowActionParameters</key>
|
|
272
|
+
<dict>
|
|
273
|
+
<key>UUID</key>
|
|
274
|
+
<string>2DAAA123-EDA6-573F-B64C-0BE13A7920F1</string>
|
|
275
|
+
<key>GroupingIdentifier</key>
|
|
276
|
+
<string>9DEBBB46-882B-5977-87B4-3E4E05678705</string>
|
|
277
|
+
<key>WFControlFlowMode</key>
|
|
278
|
+
<integer>0</integer>
|
|
279
|
+
<key>WFInput</key>
|
|
280
|
+
<dict>
|
|
281
|
+
<key>Type</key>
|
|
282
|
+
<string>Variable</string>
|
|
283
|
+
<key>Variable</key>
|
|
284
|
+
<dict>
|
|
285
|
+
<key>Value</key>
|
|
286
|
+
<dict>
|
|
287
|
+
<key>Type</key>
|
|
288
|
+
<string>ActionOutput</string>
|
|
289
|
+
<key>OutputUUID</key>
|
|
290
|
+
<string>506724BB-49FB-5E33-A2DB-C392798691A7</string>
|
|
291
|
+
<key>OutputName</key>
|
|
292
|
+
<string>count-text</string>
|
|
293
|
+
</dict>
|
|
294
|
+
<key>WFSerializationType</key>
|
|
295
|
+
<string>WFTextTokenAttachment</string>
|
|
296
|
+
</dict>
|
|
297
|
+
</dict>
|
|
298
|
+
<key>WFCondition</key>
|
|
299
|
+
<integer>4</integer>
|
|
300
|
+
<key>WFConditionalActionString</key>
|
|
301
|
+
<string>1</string>
|
|
302
|
+
</dict>
|
|
303
|
+
</dict>
|
|
304
|
+
<dict>
|
|
305
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
306
|
+
<string>is.workflow.actions.repeat.each</string>
|
|
307
|
+
<key>WFWorkflowActionParameters</key>
|
|
308
|
+
<dict>
|
|
309
|
+
<key>UUID</key>
|
|
310
|
+
<string>603F0BDF-C041-5AA4-BE51-B62DD785A079</string>
|
|
311
|
+
<key>GroupingIdentifier</key>
|
|
312
|
+
<string>3D602350-7BF4-5B87-A104-B5DB7C320E26</string>
|
|
313
|
+
<key>WFControlFlowMode</key>
|
|
314
|
+
<integer>0</integer>
|
|
315
|
+
<key>WFInput</key>
|
|
316
|
+
<dict>
|
|
317
|
+
<key>Value</key>
|
|
318
|
+
<dict>
|
|
319
|
+
<key>Type</key>
|
|
320
|
+
<string>ActionOutput</string>
|
|
321
|
+
<key>OutputUUID</key>
|
|
322
|
+
<string>40662BA1-53A6-58B0-A54E-A9174F25AB48</string>
|
|
323
|
+
<key>OutputName</key>
|
|
324
|
+
<string>tags</string>
|
|
325
|
+
</dict>
|
|
326
|
+
<key>WFSerializationType</key>
|
|
327
|
+
<string>WFTextTokenAttachment</string>
|
|
328
|
+
</dict>
|
|
329
|
+
</dict>
|
|
330
|
+
</dict>
|
|
331
|
+
<dict>
|
|
332
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
333
|
+
<string>com.apple.Notes.CreateTagLinkAction</string>
|
|
334
|
+
<key>WFWorkflowActionParameters</key>
|
|
335
|
+
<dict>
|
|
336
|
+
<key>UUID</key>
|
|
337
|
+
<string>5AE3DC80-27B3-56AC-9668-94AC6AF3F57F</string>
|
|
338
|
+
<key>AppIntentDescriptor</key>
|
|
339
|
+
<dict>
|
|
340
|
+
<key>AppIntentIdentifier</key>
|
|
341
|
+
<string>CreateTagLinkAction</string>
|
|
342
|
+
<key>BundleIdentifier</key>
|
|
343
|
+
<string>com.apple.Notes</string>
|
|
344
|
+
<key>TeamIdentifier</key>
|
|
345
|
+
<string>0000000000</string>
|
|
346
|
+
<key>Name</key>
|
|
347
|
+
<string>Notes</string>
|
|
348
|
+
</dict>
|
|
349
|
+
<key>ShowWhenRun</key>
|
|
350
|
+
<false/>
|
|
351
|
+
<key>name</key>
|
|
352
|
+
<dict>
|
|
353
|
+
<key>WFSerializationType</key>
|
|
354
|
+
<string>WFTextTokenString</string>
|
|
355
|
+
<key>Value</key>
|
|
356
|
+
<dict>
|
|
357
|
+
<key>string</key>
|
|
358
|
+
<string></string>
|
|
359
|
+
<key>attachmentsByRange</key>
|
|
360
|
+
<dict>
|
|
361
|
+
<key>{0, 1}</key>
|
|
362
|
+
<dict>
|
|
363
|
+
<key>Type</key>
|
|
364
|
+
<string>Variable</string>
|
|
365
|
+
<key>VariableName</key>
|
|
366
|
+
<string>Repeat Item</string>
|
|
367
|
+
</dict>
|
|
368
|
+
</dict>
|
|
369
|
+
</dict>
|
|
370
|
+
</dict>
|
|
371
|
+
</dict>
|
|
372
|
+
</dict>
|
|
373
|
+
<dict>
|
|
374
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
375
|
+
<string>com.apple.Notes.AddTagsToNotesLinkAction</string>
|
|
376
|
+
<key>WFWorkflowActionParameters</key>
|
|
377
|
+
<dict>
|
|
378
|
+
<key>UUID</key>
|
|
379
|
+
<string>8C0C4D73-5555-5FC6-BD29-D5B9EE299698</string>
|
|
380
|
+
<key>AppIntentDescriptor</key>
|
|
381
|
+
<dict>
|
|
382
|
+
<key>AppIntentIdentifier</key>
|
|
383
|
+
<string>AddTagsToNotesLinkAction</string>
|
|
384
|
+
<key>BundleIdentifier</key>
|
|
385
|
+
<string>com.apple.Notes</string>
|
|
386
|
+
<key>TeamIdentifier</key>
|
|
387
|
+
<string>0000000000</string>
|
|
388
|
+
<key>Name</key>
|
|
389
|
+
<string>Notes</string>
|
|
390
|
+
</dict>
|
|
391
|
+
<key>ShowWhenRun</key>
|
|
392
|
+
<false/>
|
|
393
|
+
<key>notes</key>
|
|
394
|
+
<dict>
|
|
395
|
+
<key>Value</key>
|
|
396
|
+
<dict>
|
|
397
|
+
<key>Type</key>
|
|
398
|
+
<string>ActionOutput</string>
|
|
399
|
+
<key>OutputUUID</key>
|
|
400
|
+
<string>DFF87C25-7AF8-55BC-BA5F-4F08CC05A668</string>
|
|
401
|
+
<key>OutputName</key>
|
|
402
|
+
<string>target</string>
|
|
403
|
+
</dict>
|
|
404
|
+
<key>WFSerializationType</key>
|
|
405
|
+
<string>WFTextTokenAttachment</string>
|
|
406
|
+
</dict>
|
|
407
|
+
<key>tags</key>
|
|
408
|
+
<dict>
|
|
409
|
+
<key>Value</key>
|
|
410
|
+
<dict>
|
|
411
|
+
<key>Type</key>
|
|
412
|
+
<string>ActionOutput</string>
|
|
413
|
+
<key>OutputUUID</key>
|
|
414
|
+
<string>5AE3DC80-27B3-56AC-9668-94AC6AF3F57F</string>
|
|
415
|
+
<key>OutputName</key>
|
|
416
|
+
<string>native-tag</string>
|
|
417
|
+
</dict>
|
|
418
|
+
<key>WFSerializationType</key>
|
|
419
|
+
<string>WFTextTokenAttachment</string>
|
|
420
|
+
</dict>
|
|
421
|
+
</dict>
|
|
422
|
+
</dict>
|
|
423
|
+
<dict>
|
|
424
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
425
|
+
<string>is.workflow.actions.repeat.each</string>
|
|
426
|
+
<key>WFWorkflowActionParameters</key>
|
|
427
|
+
<dict>
|
|
428
|
+
<key>UUID</key>
|
|
429
|
+
<string>B9B919AF-4E05-5B76-B70B-E8EE6B502A92</string>
|
|
430
|
+
<key>GroupingIdentifier</key>
|
|
431
|
+
<string>3D602350-7BF4-5B87-A104-B5DB7C320E26</string>
|
|
432
|
+
<key>WFControlFlowMode</key>
|
|
433
|
+
<integer>2</integer>
|
|
434
|
+
</dict>
|
|
435
|
+
</dict>
|
|
436
|
+
<dict>
|
|
437
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
438
|
+
<string>is.workflow.actions.gettext</string>
|
|
439
|
+
<key>WFWorkflowActionParameters</key>
|
|
440
|
+
<dict>
|
|
441
|
+
<key>UUID</key>
|
|
442
|
+
<string>95DA2053-00CE-52E9-95AC-CA17A0DC7031</string>
|
|
443
|
+
<key>WFTextActionText</key>
|
|
444
|
+
<string>APPLE_NOTES_TAGS_OK</string>
|
|
445
|
+
</dict>
|
|
446
|
+
</dict>
|
|
447
|
+
<dict>
|
|
448
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
449
|
+
<string>is.workflow.actions.output</string>
|
|
450
|
+
<key>WFWorkflowActionParameters</key>
|
|
451
|
+
<dict>
|
|
452
|
+
<key>UUID</key>
|
|
453
|
+
<string>62F50E9C-D6C6-557C-A037-0E9B4D9661BC</string>
|
|
454
|
+
<key>WFOutput</key>
|
|
455
|
+
<dict>
|
|
456
|
+
<key>Value</key>
|
|
457
|
+
<dict>
|
|
458
|
+
<key>Type</key>
|
|
459
|
+
<string>ActionOutput</string>
|
|
460
|
+
<key>OutputUUID</key>
|
|
461
|
+
<string>95DA2053-00CE-52E9-95AC-CA17A0DC7031</string>
|
|
462
|
+
<key>OutputName</key>
|
|
463
|
+
<string>success</string>
|
|
464
|
+
</dict>
|
|
465
|
+
<key>WFSerializationType</key>
|
|
466
|
+
<string>WFTextTokenAttachment</string>
|
|
467
|
+
</dict>
|
|
468
|
+
</dict>
|
|
469
|
+
</dict>
|
|
470
|
+
<dict>
|
|
471
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
472
|
+
<string>is.workflow.actions.conditional</string>
|
|
473
|
+
<key>WFWorkflowActionParameters</key>
|
|
474
|
+
<dict>
|
|
475
|
+
<key>UUID</key>
|
|
476
|
+
<string>F0968167-BF41-5F06-9942-A281BA37A28B</string>
|
|
477
|
+
<key>GroupingIdentifier</key>
|
|
478
|
+
<string>9DEBBB46-882B-5977-87B4-3E4E05678705</string>
|
|
479
|
+
<key>WFControlFlowMode</key>
|
|
480
|
+
<integer>1</integer>
|
|
481
|
+
</dict>
|
|
482
|
+
</dict>
|
|
483
|
+
<dict>
|
|
484
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
485
|
+
<string>is.workflow.actions.gettext</string>
|
|
486
|
+
<key>WFWorkflowActionParameters</key>
|
|
487
|
+
<dict>
|
|
488
|
+
<key>UUID</key>
|
|
489
|
+
<string>38E0C0FA-E82D-55C4-BB5F-59BE5D2CDB96</string>
|
|
490
|
+
<key>WFTextActionText</key>
|
|
491
|
+
<string>APPLE_NOTES_TAGS_AMBIGUOUS_OR_MISSING</string>
|
|
492
|
+
</dict>
|
|
493
|
+
</dict>
|
|
494
|
+
<dict>
|
|
495
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
496
|
+
<string>is.workflow.actions.output</string>
|
|
497
|
+
<key>WFWorkflowActionParameters</key>
|
|
498
|
+
<dict>
|
|
499
|
+
<key>UUID</key>
|
|
500
|
+
<string>370488B5-ABAD-5A7F-9FDF-05328430A849</string>
|
|
501
|
+
<key>WFOutput</key>
|
|
502
|
+
<dict>
|
|
503
|
+
<key>Value</key>
|
|
504
|
+
<dict>
|
|
505
|
+
<key>Type</key>
|
|
506
|
+
<string>ActionOutput</string>
|
|
507
|
+
<key>OutputUUID</key>
|
|
508
|
+
<string>38E0C0FA-E82D-55C4-BB5F-59BE5D2CDB96</string>
|
|
509
|
+
<key>OutputName</key>
|
|
510
|
+
<string>refusal</string>
|
|
511
|
+
</dict>
|
|
512
|
+
<key>WFSerializationType</key>
|
|
513
|
+
<string>WFTextTokenAttachment</string>
|
|
514
|
+
</dict>
|
|
515
|
+
</dict>
|
|
516
|
+
</dict>
|
|
517
|
+
<dict>
|
|
518
|
+
<key>WFWorkflowActionIdentifier</key>
|
|
519
|
+
<string>is.workflow.actions.conditional</string>
|
|
520
|
+
<key>WFWorkflowActionParameters</key>
|
|
521
|
+
<dict>
|
|
522
|
+
<key>UUID</key>
|
|
523
|
+
<string>882D0A92-5ACB-5731-B3A1-B132714EB158</string>
|
|
524
|
+
<key>GroupingIdentifier</key>
|
|
525
|
+
<string>9DEBBB46-882B-5977-87B4-3E4E05678705</string>
|
|
526
|
+
<key>WFControlFlowMode</key>
|
|
527
|
+
<integer>2</integer>
|
|
528
|
+
</dict>
|
|
529
|
+
</dict>
|
|
530
|
+
</array>
|
|
531
|
+
<key>WFWorkflowClientVersion</key>
|
|
532
|
+
<string>2600</string>
|
|
533
|
+
<key>WFWorkflowMinimumClientVersion</key>
|
|
534
|
+
<integer>900</integer>
|
|
535
|
+
<key>WFWorkflowMinimumClientVersionString</key>
|
|
536
|
+
<string>900</string>
|
|
537
|
+
<key>WFWorkflowTypes</key>
|
|
538
|
+
<array/>
|
|
539
|
+
<key>WFWorkflowHasShortcutInputVariables</key>
|
|
540
|
+
<true/>
|
|
541
|
+
<key>WFWorkflowHasOutputAction</key>
|
|
542
|
+
<true/>
|
|
543
|
+
<key>WFWorkflowInputContentItemClasses</key>
|
|
544
|
+
<array>
|
|
545
|
+
<string>WFStringContentItem</string>
|
|
546
|
+
<string>WFDictionaryContentItem</string>
|
|
547
|
+
<string>WFGenericFileContentItem</string>
|
|
548
|
+
</array>
|
|
549
|
+
<key>WFWorkflowOutputContentItemClasses</key>
|
|
550
|
+
<array>
|
|
551
|
+
<string>WFStringContentItem</string>
|
|
552
|
+
</array>
|
|
553
|
+
<key>WFWorkflowIcon</key>
|
|
554
|
+
<dict>
|
|
555
|
+
<key>WFWorkflowIconStartColor</key>
|
|
556
|
+
<integer>4251333119</integer>
|
|
557
|
+
<key>WFWorkflowIconGlyphNumber</key>
|
|
558
|
+
<integer>59507</integer>
|
|
559
|
+
</dict>
|
|
560
|
+
<key>WFWorkflowImportQuestions</key>
|
|
561
|
+
<array/>
|
|
562
|
+
</dict>
|
|
563
|
+
</plist>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Native Tags bridge
|
|
2
|
+
|
|
3
|
+
`Apple Notes MCP - Native Tags.shortcut` adds actual native Apple Notes tags.
|
|
4
|
+
It contains no note contents or credentials. The unsigned source is committed
|
|
5
|
+
beside it and can be regenerated with:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
python3 scripts/build-native-tags-shortcut.py
|
|
9
|
+
shortcuts sign --mode anyone \
|
|
10
|
+
--input "shortcuts/Apple Notes MCP - Native Tags.unsigned.shortcut" \
|
|
11
|
+
--output "shortcuts/Apple Notes MCP - Native Tags.shortcut"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Open the signed file and confirm **Add Shortcut** once. macOS may also request
|
|
15
|
+
Notes access on first execution. The `shortcuts` CLI can run an installed
|
|
16
|
+
workflow but cannot silently import one.
|
|
17
|
+
|
|
18
|
+
The bridge receives a private temporary JSON file with a title, a distinctive
|
|
19
|
+
existing scope phrase, and normalized tags. Both the server and workflow refuse
|
|
20
|
+
ambiguous note selection. Server readback, rather than CLI output, establishes
|
|
21
|
+
success and verifies that existing content survived.
|