apple-notes-mcp 2.15.16 → 2.15.18
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 +7 -0
- package/build/index.js +96 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2444,6 +2444,13 @@ after it finishes. The result carries `verifiedBy: "database"`. Without Full
|
|
|
2444
2444
|
Disk Access a PDF attach reports "insertion outcome uncertain"; read the note
|
|
2445
2445
|
before retrying, because the attachment was probably created.
|
|
2446
2446
|
|
|
2447
|
+
Notes.app's AppleScript insertion places every new attachment in the note body
|
|
2448
|
+
twice (#321): one attachment, shown two times. The tool removes the extra copy
|
|
2449
|
+
in the same AppleScript call and checks that the note lists the attachment once.
|
|
2450
|
+
A PDF on macOS 27 cannot be listed, so its extra copy cannot be removed; when the
|
|
2451
|
+
database shows the PDF twice, the tool returns an error naming the attachment.
|
|
2452
|
+
Delete the extra copy in Notes.app and do not attach the file again.
|
|
2453
|
+
|
|
2447
2454
|
---
|
|
2448
2455
|
|
|
2449
2456
|
#### `create-note-with-attachment`
|
package/build/index.js
CHANGED
|
@@ -45558,7 +45558,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
45558
45558
|
return run(schema);
|
|
45559
45559
|
}
|
|
45560
45560
|
|
|
45561
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
45561
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
45562
45562
|
function isZ4Schema(s) {
|
|
45563
45563
|
const schema = s;
|
|
45564
45564
|
return !!schema._zod;
|
|
@@ -48573,7 +48573,7 @@ function date4(params) {
|
|
|
48573
48573
|
return _coercedDate(ZodDate2, params);
|
|
48574
48574
|
}
|
|
48575
48575
|
|
|
48576
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
48576
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
48577
48577
|
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
48578
48578
|
var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
|
|
48579
48579
|
var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
|
|
@@ -50104,7 +50104,7 @@ var UrlElicitationRequiredError = class extends McpError {
|
|
|
50104
50104
|
}
|
|
50105
50105
|
};
|
|
50106
50106
|
|
|
50107
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
50107
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
50108
50108
|
function isTerminal(status) {
|
|
50109
50109
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
50110
50110
|
}
|
|
@@ -51393,7 +51393,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
51393
51393
|
return combined;
|
|
51394
51394
|
};
|
|
51395
51395
|
|
|
51396
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
51396
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
51397
51397
|
function mapMiniTarget(t) {
|
|
51398
51398
|
if (!t)
|
|
51399
51399
|
return "draft-7";
|
|
@@ -51435,7 +51435,7 @@ function parseWithCompat(schema, data) {
|
|
|
51435
51435
|
return result.data;
|
|
51436
51436
|
}
|
|
51437
51437
|
|
|
51438
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
51438
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
51439
51439
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
51440
51440
|
var Protocol = class {
|
|
51441
51441
|
constructor(_options) {
|
|
@@ -52412,7 +52412,7 @@ function mergeCapabilities(base, additional) {
|
|
|
52412
52412
|
return result;
|
|
52413
52413
|
}
|
|
52414
52414
|
|
|
52415
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
52415
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
52416
52416
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
52417
52417
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
52418
52418
|
function createDefaultAjvInstance() {
|
|
@@ -52480,7 +52480,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
52480
52480
|
}
|
|
52481
52481
|
};
|
|
52482
52482
|
|
|
52483
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
52483
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
52484
52484
|
var ExperimentalServerTasks = class {
|
|
52485
52485
|
constructor(_server) {
|
|
52486
52486
|
this._server = _server;
|
|
@@ -52693,7 +52693,7 @@ var ExperimentalServerTasks = class {
|
|
|
52693
52693
|
}
|
|
52694
52694
|
};
|
|
52695
52695
|
|
|
52696
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
52696
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
52697
52697
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
52698
52698
|
if (!requests) {
|
|
52699
52699
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -52728,7 +52728,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
52728
52728
|
}
|
|
52729
52729
|
}
|
|
52730
52730
|
|
|
52731
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
52731
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
52732
52732
|
var Server = class extends Protocol {
|
|
52733
52733
|
/**
|
|
52734
52734
|
* Initializes this server with the given name and version information.
|
|
@@ -53099,7 +53099,7 @@ var Server = class extends Protocol {
|
|
|
53099
53099
|
}
|
|
53100
53100
|
};
|
|
53101
53101
|
|
|
53102
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
53102
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
53103
53103
|
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
53104
53104
|
function isCompletable(schema) {
|
|
53105
53105
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -53113,7 +53113,7 @@ var McpZodTypeKind;
|
|
|
53113
53113
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
53114
53114
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
53115
53115
|
|
|
53116
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
53116
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
|
|
53117
53117
|
var MAX_TEMPLATE_LENGTH = 1e6;
|
|
53118
53118
|
var MAX_VARIABLE_LENGTH = 1e6;
|
|
53119
53119
|
var MAX_TEMPLATE_EXPRESSIONS = 1e4;
|
|
@@ -53335,7 +53335,7 @@ var UriTemplate = class _UriTemplate {
|
|
|
53335
53335
|
}
|
|
53336
53336
|
};
|
|
53337
53337
|
|
|
53338
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
53338
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
53339
53339
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
53340
53340
|
function validateToolName(name) {
|
|
53341
53341
|
const warnings = [];
|
|
@@ -53393,7 +53393,7 @@ function validateAndWarnToolName(name) {
|
|
|
53393
53393
|
return result.isValid;
|
|
53394
53394
|
}
|
|
53395
53395
|
|
|
53396
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
53396
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
53397
53397
|
var ExperimentalMcpServerTasks = class {
|
|
53398
53398
|
constructor(_mcpServer) {
|
|
53399
53399
|
this._mcpServer = _mcpServer;
|
|
@@ -53408,7 +53408,7 @@ var ExperimentalMcpServerTasks = class {
|
|
|
53408
53408
|
}
|
|
53409
53409
|
};
|
|
53410
53410
|
|
|
53411
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
53411
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
53412
53412
|
function toolInputElementCount(value, max) {
|
|
53413
53413
|
let count = 0;
|
|
53414
53414
|
const stack = [value];
|
|
@@ -53457,6 +53457,15 @@ var McpServer = class {
|
|
|
53457
53457
|
this._promptHandlersInitialized = false;
|
|
53458
53458
|
this.server = new Server(serverInfo, options);
|
|
53459
53459
|
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
53460
|
+
if (options?.capabilities?.tools) {
|
|
53461
|
+
this.setToolRequestHandlers();
|
|
53462
|
+
}
|
|
53463
|
+
if (options?.capabilities?.resources) {
|
|
53464
|
+
this.setResourceRequestHandlers();
|
|
53465
|
+
}
|
|
53466
|
+
if (options?.capabilities?.prompts) {
|
|
53467
|
+
this.setPromptRequestHandlers();
|
|
53468
|
+
}
|
|
53460
53469
|
}
|
|
53461
53470
|
/**
|
|
53462
53471
|
* Access experimental features.
|
|
@@ -54264,10 +54273,10 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
54264
54273
|
}
|
|
54265
54274
|
};
|
|
54266
54275
|
|
|
54267
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
54276
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
54268
54277
|
import process2 from "node:process";
|
|
54269
54278
|
|
|
54270
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
54279
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
54271
54280
|
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
54272
54281
|
var ReadBuffer = class {
|
|
54273
54282
|
constructor(options) {
|
|
@@ -54304,7 +54313,7 @@ function serializeMessage(message) {
|
|
|
54304
54313
|
return JSON.stringify(message) + "\n";
|
|
54305
54314
|
}
|
|
54306
54315
|
|
|
54307
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.
|
|
54316
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
54308
54317
|
var StdioServerTransport = class {
|
|
54309
54318
|
constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) {
|
|
54310
54319
|
this._stdin = _stdin;
|
|
@@ -57545,25 +57554,35 @@ function parseAttachmentRows(json3) {
|
|
|
57545
57554
|
}
|
|
57546
57555
|
return rows.sort((a, b) => a.pk - b.pk);
|
|
57547
57556
|
}
|
|
57548
|
-
function
|
|
57557
|
+
function attachmentRunsFromNoteData(hex5) {
|
|
57549
57558
|
if (!hex5 || !/^[0-9a-f]+$/i.test(hex5)) return null;
|
|
57550
57559
|
try {
|
|
57551
57560
|
const data = gunzipSync5(Buffer.from(hex5, "hex"), { maxOutputLength: MAX_BODY_BYTES });
|
|
57552
57561
|
const wrapper = embeddedMessage(getField(decodeMessage(data), 2));
|
|
57553
57562
|
const body = wrapper && embeddedMessage(getField(wrapper, 3));
|
|
57554
57563
|
if (!body) return null;
|
|
57555
|
-
const
|
|
57564
|
+
const refs = [];
|
|
57556
57565
|
for (const run of getFields(body, 5)) {
|
|
57557
57566
|
const fields = embeddedMessage(run);
|
|
57558
57567
|
const info = fields && embeddedMessage(getField(fields, 12));
|
|
57559
57568
|
const id2 = info && stringValue(getField(info, 1));
|
|
57560
|
-
if (
|
|
57569
|
+
if (!id2) continue;
|
|
57570
|
+
const length = varintValue(getField(fields, 1)) ?? 1;
|
|
57571
|
+
for (let i = 0; i < Math.min(Math.max(length, 1), 64); i++) refs.push(id2);
|
|
57561
57572
|
}
|
|
57562
|
-
return
|
|
57573
|
+
return refs;
|
|
57563
57574
|
} catch {
|
|
57564
57575
|
return null;
|
|
57565
57576
|
}
|
|
57566
57577
|
}
|
|
57578
|
+
function attachmentOrderFromNoteData(hex5) {
|
|
57579
|
+
const refs = attachmentRunsFromNoteData(hex5);
|
|
57580
|
+
if (!refs) return null;
|
|
57581
|
+
const ids = [];
|
|
57582
|
+
for (const id2 of refs)
|
|
57583
|
+
if (!ids.some((seen) => seen.toLowerCase() === id2.toLowerCase())) ids.push(id2);
|
|
57584
|
+
return ids;
|
|
57585
|
+
}
|
|
57567
57586
|
function readNoteAttachmentRows(noteId3, dbPath2 = join9(NOTES_CONTAINER_DIR, "NoteStore.sqlite")) {
|
|
57568
57587
|
const { pk } = parseNoteId2(noteId3);
|
|
57569
57588
|
const columnList = runSqlite3(
|
|
@@ -57587,7 +57606,8 @@ function readNoteAttachmentRows(noteId3, dbPath2 = join9(NOTES_CONTAINER_DIR, "N
|
|
|
57587
57606
|
} catch {
|
|
57588
57607
|
throw new AttachmentStoreError("Attachment rows could not be parsed", "query_error");
|
|
57589
57608
|
}
|
|
57590
|
-
|
|
57609
|
+
const bodyRefs = attachmentRunsFromNoteData(lines[2]?.trim());
|
|
57610
|
+
return { rows, bodyOrder: attachmentOrderFromNoteData(lines[2]?.trim()), bodyRefs };
|
|
57591
57611
|
}
|
|
57592
57612
|
function safeComponent(value) {
|
|
57593
57613
|
if (typeof value !== "string" || !value || value.length > 255) return null;
|
|
@@ -57750,13 +57770,16 @@ function assetPathsFor(accountDir, row, onStale) {
|
|
|
57750
57770
|
add(file2);
|
|
57751
57771
|
return found;
|
|
57752
57772
|
}
|
|
57753
|
-
function assembleAttachmentAssets(allRows, bodyOrder, containerDir = NOTES_CONTAINER_DIR) {
|
|
57773
|
+
function assembleAttachmentAssets(allRows, bodyOrder, containerDir = NOTES_CONTAINER_DIR, bodyRefs = null) {
|
|
57754
57774
|
const rows = allRows.filter((r) => !r.parentDeleted);
|
|
57755
57775
|
const byPk = new Map(rows.map((r) => [r.pk, r]));
|
|
57756
57776
|
const roots = rows.filter((r) => r.parentPk === null || !byPk.has(r.parentPk));
|
|
57757
57777
|
const bodyIndex = /* @__PURE__ */ new Map();
|
|
57758
57778
|
(bodyOrder ?? []).forEach((id2, index) => bodyIndex.set(id2.toLowerCase(), index));
|
|
57759
57779
|
const indexOf = (r) => bodyIndex.get(r.identifier.toLowerCase()) ?? null;
|
|
57780
|
+
const refCount = /* @__PURE__ */ new Map();
|
|
57781
|
+
for (const id2 of bodyRefs ?? [])
|
|
57782
|
+
refCount.set(id2.toLowerCase(), (refCount.get(id2.toLowerCase()) ?? 0) + 1);
|
|
57760
57783
|
const inBody = roots.filter((r) => indexOf(r) !== null);
|
|
57761
57784
|
const orderSource = inBody.length > 0 ? "body" : "creation";
|
|
57762
57785
|
const orderedRoots = [
|
|
@@ -57790,6 +57813,7 @@ function assembleAttachmentAssets(allRows, bodyOrder, containerDir = NOTES_CONTA
|
|
|
57790
57813
|
parentIdentifier: parent?.identifier ?? null,
|
|
57791
57814
|
filename: row.filename ?? row.mediaFilename,
|
|
57792
57815
|
bodyIndex: parent ? null : indexOf(row),
|
|
57816
|
+
...!parent && (refCount.get(row.identifier.toLowerCase()) ?? 0) > 1 ? { bodyReferences: refCount.get(row.identifier.toLowerCase()) } : {},
|
|
57793
57817
|
assetPaths,
|
|
57794
57818
|
...fallbackStale ? { fallbackStale: true } : {},
|
|
57795
57819
|
previewPath,
|
|
@@ -60082,7 +60106,17 @@ var AppleNotesManager = class {
|
|
|
60082
60106
|
if (!result.success) throw new Error(result.error || "Could not check folder existence");
|
|
60083
60107
|
return result.output.trim() === "true";
|
|
60084
60108
|
}
|
|
60085
|
-
/**
|
|
60109
|
+
/**
|
|
60110
|
+
* Insert one file into an unchanged exact note and return Notes' attachment ID.
|
|
60111
|
+
*
|
|
60112
|
+
* Notes.app's `make new attachment` writes the new attachment into the note
|
|
60113
|
+
* body twice (#321): one attachment object, two body references, so the file
|
|
60114
|
+
* shows twice. Every form of the command does it (`at n`, `at end of
|
|
60115
|
+
* attachments of n`, `tell n to make`, an alias), and `every attachment of n`
|
|
60116
|
+
* then lists the same id twice. Deleting the extra entries by index removes
|
|
60117
|
+
* only their body references; the attachment object and its file stay. The
|
|
60118
|
+
* cleanup runs in the same AppleScript so no other edit can interleave.
|
|
60119
|
+
*/
|
|
60086
60120
|
addAttachmentById(id2, expectedBody, filePath) {
|
|
60087
60121
|
if (!/^x-coredata:\/\/[0-9a-f-]+\/ICNote\/p\d+$/i.test(id2))
|
|
60088
60122
|
throw new Error("Exact note ID required");
|
|
@@ -60094,7 +60128,16 @@ var AppleNotesManager = class {
|
|
|
60094
60128
|
if body of n is not ${quote(expectedBody)} and body of n is not (${quote(expectedBody)} & linefeed) then error "Note changed before attachment insertion"
|
|
60095
60129
|
end considering
|
|
60096
60130
|
set a to make new attachment at n with data (POSIX file ${quote(filePath)})
|
|
60097
|
-
|
|
60131
|
+
set newId to id of a
|
|
60132
|
+
set hits to {}
|
|
60133
|
+
set attachmentIds to id of every attachment of n
|
|
60134
|
+
repeat with i from 1 to count of attachmentIds
|
|
60135
|
+
if item i of attachmentIds is newId then set end of hits to i
|
|
60136
|
+
end repeat
|
|
60137
|
+
repeat with j from (count of hits) to 2 by -1
|
|
60138
|
+
delete attachment (item j of hits) of n
|
|
60139
|
+
end repeat
|
|
60140
|
+
return newId
|
|
60098
60141
|
end tell`);
|
|
60099
60142
|
if (!result.success)
|
|
60100
60143
|
throw new Error(
|
|
@@ -60102,6 +60145,27 @@ var AppleNotesManager = class {
|
|
|
60102
60145
|
);
|
|
60103
60146
|
return result.output.trim();
|
|
60104
60147
|
}
|
|
60148
|
+
/**
|
|
60149
|
+
* How many entries Notes' `every attachment` holds for one attachment id
|
|
60150
|
+
* (#321). Read-only. Notes on macOS 27 does not list PDF attachments, so a PDF
|
|
60151
|
+
* counts 0 here; the NoteStore database is the check for those.
|
|
60152
|
+
*/
|
|
60153
|
+
countAttachmentEntriesById(noteId3, attachmentId) {
|
|
60154
|
+
if (!/^x-coredata:\/\/[0-9a-f-]+\/ICAttachment\/p\d+$/i.test(attachmentId))
|
|
60155
|
+
throw new Error("Exact attachment ID required");
|
|
60156
|
+
const result = executeAppleScript(`tell application "Notes"
|
|
60157
|
+
set attachmentIds to id of every attachment of note id "${sanitizeId(noteId3)}"
|
|
60158
|
+
set hits to 0
|
|
60159
|
+
repeat with i from 1 to count of attachmentIds
|
|
60160
|
+
if item i of attachmentIds is "${attachmentId}" then set hits to hits + 1
|
|
60161
|
+
end repeat
|
|
60162
|
+
return hits as text
|
|
60163
|
+
end tell`);
|
|
60164
|
+
if (!result.success) throw new Error(result.error || "Could not count attachment entries");
|
|
60165
|
+
const hits = Number(result.output.trim());
|
|
60166
|
+
if (!Number.isInteger(hits) || hits < 0) throw new Error("Unexpected attachment count");
|
|
60167
|
+
return hits;
|
|
60168
|
+
}
|
|
60105
60169
|
/**
|
|
60106
60170
|
* Lists all folders in an account with full hierarchical paths.
|
|
60107
60171
|
*
|
|
@@ -61115,8 +61179,8 @@ var AppleNotesManager = class {
|
|
|
61115
61179
|
* @throws AttachmentStoreError (`no_fda`, `invalid_id`, `not_found`, `query_error`)
|
|
61116
61180
|
*/
|
|
61117
61181
|
getAttachmentAssetsById(noteId3) {
|
|
61118
|
-
const { rows, bodyOrder } = readNoteAttachmentRows(noteId3);
|
|
61119
|
-
return assembleAttachmentAssets(rows, bodyOrder);
|
|
61182
|
+
const { rows, bodyOrder, bodyRefs } = readNoteAttachmentRows(noteId3);
|
|
61183
|
+
return assembleAttachmentAssets(rows, bodyOrder, void 0, bodyRefs);
|
|
61120
61184
|
}
|
|
61121
61185
|
/**
|
|
61122
61186
|
* The note's lead visual: the first image in body order (even when its asset
|
|
@@ -71253,7 +71317,7 @@ function registerDirectOperations(server2, manager) {
|
|
|
71253
71317
|
};
|
|
71254
71318
|
tool(
|
|
71255
71319
|
"add-attachment",
|
|
71256
|
-
"Use when: adding one local file to an exact note without replacing its body.\nReturns: the new attachment id, byte count, attachment name, and post-write content hash after exact byte verification.\nDo not use when: reading or exporting an existing attachment.\nSafety: reads only a regular file in home, temp or /Volumes, refusing hidden paths (~/.ssh, .env) and ~/Library outside iCloud Drive and CloudStorage unless the server sets APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1; requires a fresh rich revision, copies at most 64 MiB through a private temporary file, never retries insertion, and verifies existing content plus fetched bytes. On macOS 27 Notes' AppleScript does not list PDF attachments; with Full Disk Access the new attachment is verified through the read-only NoteStore database instead (verifiedBy: database), otherwise the outcome is reported as uncertain.",
|
|
71320
|
+
"Use when: adding one local file to an exact note without replacing its body.\nReturns: the new attachment id, byte count, attachment name, and post-write content hash after exact byte verification.\nDo not use when: reading or exporting an existing attachment.\nSafety: reads only a regular file in home, temp or /Volumes, refusing hidden paths (~/.ssh, .env) and ~/Library outside iCloud Drive and CloudStorage unless the server sets APPLE_NOTES_MCP_ALLOW_PRIVATE_CONTENT_PATHS=1; requires a fresh rich revision, copies at most 64 MiB through a private temporary file, never retries insertion, removes the duplicate copy Notes.app's AppleScript inserts (#321), and verifies existing content plus fetched bytes. On macOS 27 Notes' AppleScript does not list PDF attachments; with Full Disk Access the new attachment is verified through the read-only NoteStore database instead (verifiedBy: database), otherwise the outcome is reported as uncertain. A PDF that Notes shows twice cannot be cleaned up and is reported as an error: delete the extra copy in Notes.app.",
|
|
71257
71321
|
{ id: noteId, expectedContentHash: revision, ...attachmentInput },
|
|
71258
71322
|
(args) => attachFile(manager, args)
|
|
71259
71323
|
);
|
|
@@ -71392,6 +71456,7 @@ function attachmentName(path10, filename) {
|
|
|
71392
71456
|
return filename;
|
|
71393
71457
|
}
|
|
71394
71458
|
var UNCERTAIN = "Attachment insertion outcome uncertain; read the exact note before retrying";
|
|
71459
|
+
var duplicated = (attachmentId, copies) => `Notes.app put new attachment ${attachmentId} into this note ${copies} times and the extra ${copies === 2 ? "copy" : "copies"} could not be removed automatically; ask the user to delete the extra ${copies === 2 ? "copy" : "copies"} in Notes.app, and do not attach the file again`;
|
|
71395
71460
|
var pause = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
71396
71461
|
var sha256 = (data) => createHash4("sha256").update(data).digest("hex");
|
|
71397
71462
|
function storedAttachmentIds(manager, id2) {
|
|
@@ -71447,6 +71512,7 @@ function storedInsertion(manager, id2, before, bytes, name, returnedId) {
|
|
|
71447
71512
|
throw new Error(
|
|
71448
71513
|
`Notes' database shows new attachment ${attachmentId} on this note, but the note body does not reference it; read the exact note and do not attach the file again`
|
|
71449
71514
|
);
|
|
71515
|
+
if ((row.bodyReferences ?? 1) > 1) throw new Error(duplicated(attachmentId, row.bodyReferences));
|
|
71450
71516
|
const expected = sha256(bytes);
|
|
71451
71517
|
const matches = row.assetPaths.some((path10) => fileMatches(path10, bytes.length, expected));
|
|
71452
71518
|
if (!matches)
|
|
@@ -71497,6 +71563,8 @@ function attachFile(manager, args, checked, progress = { insertionStarted: false
|
|
|
71497
71563
|
const saved = manager.saveAttachmentById(id2, attachmentId, verifyPath);
|
|
71498
71564
|
if (!saved.success || !fileMatches(saved.savedPath ?? verifyPath, bytes.length, sha256(bytes)))
|
|
71499
71565
|
throw new Error("Attachment bytes were not verified; read the exact note before retrying");
|
|
71566
|
+
const copies = manager.countAttachmentEntriesById(id2, attachmentId);
|
|
71567
|
+
if (copies > 1) throw new Error(duplicated(attachmentId, copies));
|
|
71500
71568
|
} else {
|
|
71501
71569
|
const stored = inserted.length === 0 && beforeStored ? storedInsertion(manager, id2, beforeStored, bytes, name, returnedId) : null;
|
|
71502
71570
|
if (!stored)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-notes-mcp",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.18",
|
|
4
4
|
"description": "MCP server for Apple Notes - read, search, create, edit, organize, and export notes on macOS via Claude and other AI assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|