apple-mail-mcp 2.10.11 → 2.10.12

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
@@ -1427,6 +1427,11 @@ The `\\\\` in JSON becomes `\\` in the actual string, which represents a single
1427
1427
  - Verify Mail.app can send emails manually
1428
1428
  - Check if the account is configured correctly in Mail.app
1429
1429
 
1430
+ ### "invalid outputSchema … unsupported dialect" — every tool is refused
1431
+ - Full text: `Tool '<name>' has an invalid outputSchema: JSON Schema declares an unsupported dialect ("$schema": "http://json-schema.org/draft-07/schema#"). The default validator supports JSON Schema 2020-12 only.` The server connects, but **no tool is usable**.
1432
+ - **Upgrade to 2.10.12 or later.** Earlier versions advertised their tool schemas in JSON Schema **draft-07** (the MCP SDK's converter default); MCP has since standardized on **2020-12** and clients reject anything else. 2.10.12 normalizes every advertised `inputSchema`/`outputSchema` to 2020-12 on the way out. See [issue #147](https://github.com/sweetrb/apple-mail-mcp/issues/147).
1433
+ - Nothing to configure — restart your host app after upgrading so it re-reads the tool list.
1434
+
1430
1435
  ### `apple-mail` server fails to connect when run from a clone
1431
1436
  - The root `.mcp.json` resolves its entrypoint via `${CLAUDE_PROJECT_DIR:-.}/build/index.js`. **Launch `claude` from inside the repo directory** — `CLAUDE_PROJECT_DIR` only resolves to the repo root in that case; the bare `.` fallback uses the launching shell's working directory and will point at the wrong place otherwise.
1432
1437
  - If you've been editing the source, rerun `npm run build` — the server is `build/index.js`, and the committed bundle only reflects your changes after a rebuild.
package/build/index.js CHANGED
@@ -83329,6 +83329,117 @@ function isOrphaned(ppid = process.ppid) {
83329
83329
  return ppid === 1;
83330
83330
  }
83331
83331
 
83332
+ // src/utils/jsonSchemaDialect.ts
83333
+ var JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
83334
+ var DEFINITIONS_REF_PREFIX = "#/definitions/";
83335
+ var SCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([
83336
+ "properties",
83337
+ "patternProperties",
83338
+ "$defs",
83339
+ "dependentSchemas"
83340
+ ]);
83341
+ var DATA_KEYWORDS = /* @__PURE__ */ new Set([
83342
+ "enum",
83343
+ "const",
83344
+ "default",
83345
+ "examples",
83346
+ "required",
83347
+ "dependentRequired"
83348
+ ]);
83349
+ function isPlainObject3(value) {
83350
+ return typeof value === "object" && value !== null && !Array.isArray(value);
83351
+ }
83352
+ function convertSchemaMap(node) {
83353
+ if (!isPlainObject3(node)) return node;
83354
+ const out = {};
83355
+ for (const [name, subschema] of Object.entries(node)) out[name] = convertNode(subschema);
83356
+ return out;
83357
+ }
83358
+ function convertNode(node) {
83359
+ if (Array.isArray(node)) return node.map(convertNode);
83360
+ if (!isPlainObject3(node)) return node;
83361
+ const hasTupleItems = Array.isArray(node.items);
83362
+ const out = {};
83363
+ for (const [key, value] of Object.entries(node)) {
83364
+ switch (key) {
83365
+ case "$schema":
83366
+ break;
83367
+ case "definitions":
83368
+ out.$defs = convertSchemaMap(value);
83369
+ break;
83370
+ case "$ref":
83371
+ out.$ref = typeof value === "string" && value.startsWith(DEFINITIONS_REF_PREFIX) ? "#/$defs/" + value.slice(DEFINITIONS_REF_PREFIX.length) : value;
83372
+ break;
83373
+ case "items":
83374
+ if (hasTupleItems) out.prefixItems = value.map(convertNode);
83375
+ else out.items = convertNode(value);
83376
+ break;
83377
+ case "additionalItems":
83378
+ if (hasTupleItems) out.items = convertNode(value);
83379
+ break;
83380
+ case "dependencies": {
83381
+ const dependentRequired = {};
83382
+ const dependentSchemas = {};
83383
+ if (isPlainObject3(value)) {
83384
+ for (const [property, dependency] of Object.entries(value)) {
83385
+ if (Array.isArray(dependency)) dependentRequired[property] = dependency;
83386
+ else dependentSchemas[property] = convertNode(dependency);
83387
+ }
83388
+ }
83389
+ if (Object.keys(dependentRequired).length > 0) out.dependentRequired = dependentRequired;
83390
+ if (Object.keys(dependentSchemas).length > 0) out.dependentSchemas = dependentSchemas;
83391
+ break;
83392
+ }
83393
+ case "exclusiveMinimum":
83394
+ case "exclusiveMaximum": {
83395
+ const bound = key === "exclusiveMinimum" ? node.minimum : node.maximum;
83396
+ if (value === true && typeof bound === "number") out[key] = bound;
83397
+ else if (value !== false) out[key] = convertNode(value);
83398
+ break;
83399
+ }
83400
+ case "minimum":
83401
+ if (node.exclusiveMinimum === true) break;
83402
+ out.minimum = convertNode(value);
83403
+ break;
83404
+ case "maximum":
83405
+ if (node.exclusiveMaximum === true) break;
83406
+ out.maximum = convertNode(value);
83407
+ break;
83408
+ default:
83409
+ if (DATA_KEYWORDS.has(key)) out[key] = value;
83410
+ else if (SCHEMA_MAP_KEYWORDS.has(key)) out[key] = convertSchemaMap(value);
83411
+ else out[key] = convertNode(value);
83412
+ }
83413
+ }
83414
+ return out;
83415
+ }
83416
+ function toJsonSchema2020_12(schema) {
83417
+ if (!isPlainObject3(schema)) return schema;
83418
+ return {
83419
+ $schema: JSON_SCHEMA_2020_12,
83420
+ ...convertNode(schema)
83421
+ };
83422
+ }
83423
+ function normalizeOutgoingMessage(message) {
83424
+ if (!isPlainObject3(message)) return message;
83425
+ const result = message.result;
83426
+ if (!isPlainObject3(result) || !Array.isArray(result.tools)) return message;
83427
+ const tools = result.tools.map((tool) => {
83428
+ if (!isPlainObject3(tool)) return tool;
83429
+ const next = { ...tool };
83430
+ if (isPlainObject3(tool.inputSchema)) next.inputSchema = toJsonSchema2020_12(tool.inputSchema);
83431
+ if (isPlainObject3(tool.outputSchema))
83432
+ next.outputSchema = toJsonSchema2020_12(tool.outputSchema);
83433
+ return next;
83434
+ });
83435
+ return { ...message, result: { ...result, tools } };
83436
+ }
83437
+ function withJsonSchema2020_12(transport2) {
83438
+ const originalSend = transport2.send.bind(transport2);
83439
+ transport2.send = (message, options) => originalSend(normalizeOutgoingMessage(message), options);
83440
+ return transport2;
83441
+ }
83442
+
83332
83443
  // src/index.ts
83333
83444
  loadFileConfig();
83334
83445
  var MESSAGE_ID_SCHEMA = external_exports.string().regex(/^(\d+|imap:[A-Za-z0-9_-]+)$/, "Message ID must be numeric or an IMAP id (imap:\u2026)");
@@ -85569,7 +85680,7 @@ process.on("uncaughtException", (err) => {
85569
85680
  process.on("unhandledRejection", (reason) => {
85570
85681
  console.error("[unhandledRejection]", reason);
85571
85682
  });
85572
- var transport = new StdioServerTransport();
85683
+ var transport = withJsonSchema2020_12(new StdioServerTransport());
85573
85684
  await server.connect(transport);
85574
85685
  var idleWatcher;
85575
85686
  if (/^(1|true|yes|on)$/i.test(process.env.APPLE_MAIL_MCP_IMAP_IDLE?.trim() ?? "")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.10.11",
3
+ "version": "2.10.12",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",