@heznpc/imcp 0.7.1 → 0.9.0

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.ko.md CHANGED
@@ -1,19 +1,20 @@
1
1
  # iMcp
2
2
 
3
- Apple 생태계 전체를 위한 MCP 서버 — Notes, Reminders, Calendar, Contacts, Mail, Music, Finder, Safari, System, Photos, Shortcuts, Apple Intelligence. AI를 Mac에 연결합니다.
3
+ Apple 생태계 전체를 위한 MCP 서버 — Notes, Reminders, Calendar, Contacts, Mail, Messages, Music, Finder, Safari, System, Photos, Shortcuts, Apple Intelligence. AI를 Mac에 연결합니다.
4
4
 
5
5
  > [English](README.md)
6
6
 
7
7
  ## 특징
8
8
 
9
- - **104개 도구** (12개 모듈) — Apple 앱 CRUD + 시스템 제어 + Apple Intelligence
9
+ - **110개 도구** (13개 모듈) — Apple 앱 CRUD + 시스템 제어 + Apple Intelligence
10
10
  - **20개 프롬프트** — 앱별 워크플로우 + 크로스 모듈 + 개발자 워크플로우 (dev-session, debug-loop, build-log)
11
11
  - **4개 MCP 리소스** — Notes, Calendar, Reminders 실시간 데이터 URI
12
12
  - **JXA + Swift 브릿지** — JXA로 기본 자동화, EventKit/PhotoKit으로 고급 기능
13
13
  - **반복 이벤트/리마인더** — EventKit으로 반복 규칙 생성 (macOS 26+ Swift 브릿지)
14
14
  - **사진 가져오기/삭제** — PhotoKit으로 사진 관리 (macOS 26+ Swift 브릿지)
15
15
  - **Apple Intelligence** — 온디바이스 요약, 재작성, 교정 (macOS 26+)
16
- - **원클릭 셋업**`setup_permissions` 도구로 모든 macOS 권한을 한번에 요청
16
+ - **네이티브 메뉴바 앱** SwiftUI 컴패니언 앱으로 상태 모니터링, 권한 설정, 설정 복사
17
+ - **원클릭 셋업** — `setup_permissions` 도구 또는 메뉴바 앱으로 모든 macOS 권한을 한번에 요청
17
18
  - **stdio 전송** — 안전한 로컬 통신, 네트워크 노출 없음
18
19
  - **Safety Annotations** — 모든 도구에 readOnly/destructive 힌트 적용
19
20
 
@@ -49,6 +50,17 @@ npm install
49
50
  npm run build
50
51
  ```
51
52
 
53
+ ### 메뉴바 앱 (선택)
54
+
55
+ 서버 상태 모니터링과 권한 설정을 위한 네이티브 SwiftUI 컴패니언 앱.
56
+
57
+ ```bash
58
+ cd app && swift build -c release
59
+ # 바이너리: app/.build/release/iMcpApp
60
+ ```
61
+
62
+ 기능: 서버 상태 표시, 원클릭 권한 설정, Claude 설정 클립보드 복사.
63
+
52
64
  ## 도구
53
65
 
54
66
  ### Notes (12개)
@@ -197,6 +209,17 @@ npm run build
197
209
  | `import_photo` | 파일에서 사진 가져오기 (Swift/PhotoKit) | 쓰기 |
198
210
  | `delete_photos` | ID로 사진 삭제 (Swift/PhotoKit) | 파괴적 |
199
211
 
212
+ ### Messages (6개)
213
+
214
+ | 도구 | 설명 | 타입 |
215
+ |------|------|------|
216
+ | `list_chats` | 최근 대화 목록 (참여자 포함) | 읽기 |
217
+ | `read_chat` | 대화 상세 조회 (참여자, 마지막 업데이트 포함) | 읽기 |
218
+ | `search_chats` | 이름/참여자/핸들로 검색 | 읽기 |
219
+ | `send_message` | iMessage/SMS 텍스트 전송 | 쓰기 |
220
+ | `send_file` | iMessage/SMS 파일 첨부 전송 | 쓰기 |
221
+ | `list_participants` | 대화 참여자 목록 | 읽기 |
222
+
200
223
  ### Shortcuts (4개)
201
224
 
202
225
  | 도구 | 설명 | 타입 |
@@ -319,6 +342,10 @@ AI 코딩 에이전트(Claude Code, Cursor, Copilot)가 MCP 프롬프트로 호
319
342
  ### Mail
320
343
  - 내용 기본 5000자 제한 (`maxLength` 파라미터로 조절 가능)
321
344
 
345
+ ### Messages
346
+ - 개별 메시지 내용(대화 기록)은 JXA로 접근 불가
347
+ - 전송 시 수신자가 Messages 서비스에 등록된 buddy여야 함
348
+
322
349
  ### Music
323
350
  - 스마트 재생목록 읽기 전용
324
351
  - 대기열 조작 불가
package/README.md CHANGED
@@ -1,19 +1,20 @@
1
1
  # iMcp
2
2
 
3
- MCP server for the entire Apple ecosystem — Notes, Reminders, Calendar, Contacts, Mail, Music, Finder, Safari, System, Photos, Shortcuts, and Apple Intelligence. Connect any AI to your Mac.
3
+ MCP server for the entire Apple ecosystem — Notes, Reminders, Calendar, Contacts, Mail, Messages, Music, Finder, Safari, System, Photos, Shortcuts, and Apple Intelligence. Connect any AI to your Mac.
4
4
 
5
5
  > [한국어](README.ko.md)
6
6
 
7
7
  ## Features
8
8
 
9
- - **104 tools** across 12 modules — full CRUD for Apple apps + system control + Apple Intelligence
9
+ - **110 tools** across 13 modules — full CRUD for Apple apps + system control + Apple Intelligence
10
10
  - **20 prompts** — per-app workflows + cross-module + developer workflows (dev-session, debug-loop, build-log)
11
11
  - **4 MCP Resources** — live data URIs for notes, calendar, and reminders
12
12
  - **JXA + Swift bridge** — JXA for core automation, EventKit/PhotoKit via Swift for advanced features
13
13
  - **Recurring events/reminders** — create recurrence rules via EventKit (macOS 26+ Swift bridge)
14
14
  - **Photos import/delete** — import and delete photos via PhotoKit (macOS 26+ Swift bridge)
15
15
  - **Apple Intelligence** — on-device summarization, rewriting, proofreading (macOS 26+)
16
- - **One-click setup** — `setup_permissions` tool triggers all macOS permission prompts at once
16
+ - **Native menubar app** — SwiftUI companion app for status monitoring, permission setup, config copy
17
+ - **One-click setup** — `setup_permissions` tool or menubar app triggers all macOS permission prompts at once
17
18
  - **stdio transport** — secure local communication, no network exposure
18
19
  - **Safety annotations** — every tool tagged with readOnly/destructive hints
19
20
 
@@ -49,6 +50,17 @@ npm install
49
50
  npm run build
50
51
  ```
51
52
 
53
+ ### Menubar App (Optional)
54
+
55
+ A native SwiftUI companion app for server status monitoring and permission setup.
56
+
57
+ ```bash
58
+ cd app && swift build -c release
59
+ # Binary: app/.build/release/iMcpApp
60
+ ```
61
+
62
+ Features: server status indicator, one-click permission setup, copy Claude config to clipboard.
63
+
52
64
  ## Tools
53
65
 
54
66
  ### Notes (12 tools)
@@ -197,6 +209,17 @@ npm run build
197
209
  | `import_photo` | Import from file path (Swift/PhotoKit) | write |
198
210
  | `delete_photos` | Delete photos by ID (Swift/PhotoKit) | destructive |
199
211
 
212
+ ### Messages (6 tools)
213
+
214
+ | Tool | Description | Type |
215
+ |------|-------------|------|
216
+ | `list_chats` | List recent chats with participants | read |
217
+ | `read_chat` | Read chat details including participants and last update | read |
218
+ | `search_chats` | Search by name, participant, or handle | read |
219
+ | `send_message` | Send text via iMessage/SMS | write |
220
+ | `send_file` | Send file attachment via iMessage/SMS | write |
221
+ | `list_participants` | List participants in a chat | read |
222
+
200
223
  ### Shortcuts (4 tools)
201
224
 
202
225
  | Tool | Description | Type |
@@ -319,6 +342,10 @@ These prompts are designed for AI coding agents (Claude Code, Cursor, Copilot) t
319
342
  ### Mail
320
343
  - Content truncated to 5000 characters by default (configurable via `maxLength` parameter)
321
344
 
345
+ ### Messages
346
+ - Chat message history (individual message content) is not accessible via JXA
347
+ - Send requires the recipient to be a known buddy in the Messages service
348
+
322
349
  ### Music
323
350
  - Smart playlists are read-only
324
351
  - No queue manipulation
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ import { registerSafariTools } from "./safari/tools.js";
15
15
  import { registerSystemTools } from "./system/tools.js";
16
16
  import { registerPhotosTools } from "./photos/tools.js";
17
17
  import { registerShortcutsTools } from "./shortcuts/tools.js";
18
+ import { registerMessagesTools } from "./messages/tools.js";
18
19
  import { registerIntelligenceTools } from "./intelligence/tools.js";
19
20
  import { registerCrossPrompts } from "./cross/prompts.js";
20
21
  import { registerResources } from "./shared/resources.js";
@@ -23,7 +24,7 @@ import { parseConfig } from "./shared/config.js";
23
24
  const config = parseConfig();
24
25
  const server = new McpServer({
25
26
  name: "imcp",
26
- version: "0.7.1",
27
+ version: "0.9.0",
27
28
  });
28
29
  // Apple Apps
29
30
  registerNoteTools(server, config);
@@ -40,6 +41,7 @@ registerSafariTools(server, config);
40
41
  registerSystemTools(server, config);
41
42
  registerPhotosTools(server, config);
42
43
  registerShortcutsTools(server, config);
44
+ registerMessagesTools(server, config);
43
45
  // Apple Intelligence
44
46
  registerIntelligenceTools(server, config);
45
47
  // Cross-module workflows
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;AAE7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,aAAa;AACb,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACpC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,qBAAqB;AACrB,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1C,yBAAyB;AACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,gBAAgB;AAChB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,sBAAsB;AACtB,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,+CAA+C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AACvG,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function listChatsScript(limit: number): string;
2
+ export declare function readChatScript(chatId: string): string;
3
+ export declare function searchMessagesScript(query: string, limit: number): string;
4
+ export declare function sendMessageScript(target: string, text: string): string;
5
+ export declare function sendFileScript(target: string, filePath: string): string;
6
+ export declare function listParticipantsScript(chatId: string): string;
@@ -0,0 +1,103 @@
1
+ // JXA scripts for Apple Messages automation.
2
+ import { esc } from "../shared/esc.js";
3
+ export function listChatsScript(limit) {
4
+ return `
5
+ const Messages = Application('Messages');
6
+ const chats = Messages.chats();
7
+ const count = Math.min(chats.length, ${limit});
8
+ const result = [];
9
+ for (let i = 0; i < count; i++) {
10
+ const c = chats[i];
11
+ const participants = c.participants();
12
+ result.push({
13
+ id: c.id(),
14
+ name: c.name() || null,
15
+ participants: participants.map(p => ({
16
+ name: p.name(),
17
+ handle: p.handle()
18
+ })),
19
+ updated: c.updatedDate() ? c.updatedDate().toISOString() : null
20
+ });
21
+ }
22
+ JSON.stringify({total: chats.length, returned: count, chats: result});
23
+ `;
24
+ }
25
+ export function readChatScript(chatId) {
26
+ return `
27
+ const Messages = Application('Messages');
28
+ const chats = Messages.chats.whose({id: '${esc(chatId)}'})();
29
+ if (chats.length === 0) throw new Error('Chat not found: ${esc(chatId)}');
30
+ const chat = chats[0];
31
+ const participants = chat.participants();
32
+ JSON.stringify({
33
+ id: chat.id(),
34
+ name: chat.name() || null,
35
+ participants: participants.map(p => ({name: p.name(), handle: p.handle()})),
36
+ updated: chat.updatedDate() ? chat.updatedDate().toISOString() : null
37
+ });
38
+ `;
39
+ }
40
+ export function searchMessagesScript(query, limit) {
41
+ return `
42
+ const Messages = Application('Messages');
43
+ const chats = Messages.chats();
44
+ const q = '${esc(query)}'.toLowerCase();
45
+ const result = [];
46
+ for (const chat of chats) {
47
+ if (result.length >= ${limit}) break;
48
+ const name = chat.name() || '';
49
+ const participants = chat.participants();
50
+ const participantNames = participants.map(p => p.name() || '').join(' ');
51
+ const participantHandles = participants.map(p => p.handle() || '').join(' ');
52
+ if (name.toLowerCase().includes(q) ||
53
+ participantNames.toLowerCase().includes(q) ||
54
+ participantHandles.toLowerCase().includes(q)) {
55
+ result.push({
56
+ id: chat.id(),
57
+ name: name || null,
58
+ participants: participants.map(p => ({name: p.name(), handle: p.handle()})),
59
+ updated: chat.updatedDate() ? chat.updatedDate().toISOString() : null
60
+ });
61
+ }
62
+ }
63
+ JSON.stringify({returned: result.length, chats: result});
64
+ `;
65
+ }
66
+ export function sendMessageScript(target, text) {
67
+ return `
68
+ const Messages = Application('Messages');
69
+ const service = Messages.services().find(s => s.serviceType() === 'iMessage') || Messages.services()[0];
70
+ if (!service) throw new Error('No messaging service available');
71
+ const buddy = service.buddies.whose({handle: '${esc(target)}'})();
72
+ if (buddy.length === 0) throw new Error('Buddy not found for handle: ${esc(target)}');
73
+ Messages.send('${esc(text)}', {to: buddy[0]});
74
+ JSON.stringify({sent: true, to: '${esc(target)}', text: '${esc(text)}'.substring(0, 100)});
75
+ `;
76
+ }
77
+ export function sendFileScript(target, filePath) {
78
+ return `
79
+ const Messages = Application('Messages');
80
+ const service = Messages.services().find(s => s.serviceType() === 'iMessage') || Messages.services()[0];
81
+ if (!service) throw new Error('No messaging service available');
82
+ const buddy = service.buddies.whose({handle: '${esc(target)}'})();
83
+ if (buddy.length === 0) throw new Error('Buddy not found for handle: ${esc(target)}');
84
+ const file = Path('${esc(filePath)}');
85
+ Messages.send(file, {to: buddy[0]});
86
+ JSON.stringify({sent: true, to: '${esc(target)}', file: '${esc(filePath)}'});
87
+ `;
88
+ }
89
+ export function listParticipantsScript(chatId) {
90
+ return `
91
+ const Messages = Application('Messages');
92
+ const chats = Messages.chats.whose({id: '${esc(chatId)}'})();
93
+ if (chats.length === 0) throw new Error('Chat not found: ${esc(chatId)}');
94
+ const chat = chats[0];
95
+ const participants = chat.participants();
96
+ const result = participants.map(p => ({
97
+ name: p.name(),
98
+ handle: p.handle()
99
+ }));
100
+ JSON.stringify({chatId: '${esc(chatId)}', chatName: chat.name() || null, participants: result});
101
+ `;
102
+ }
103
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../src/messages/scripts.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO;;;2CAGkC,KAAK;;;;;;;;;;;;;;;;GAgB7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO;;+CAEsC,GAAG,CAAC,MAAM,CAAC;+DACK,GAAG,CAAC,MAAM,CAAC;;;;;;;;;GASvE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAAa,EACb,KAAa;IAEb,OAAO;;;iBAGQ,GAAG,CAAC,KAAK,CAAC;;;6BAGE,KAAK;;;;;;;;;;;;;;;;;GAiB/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,IAAY;IAEZ,OAAO;;;;oDAI2C,GAAG,CAAC,MAAM,CAAC;2EACY,GAAG,CAAC,MAAM,CAAC;qBACjE,GAAG,CAAC,IAAI,CAAC;uCACS,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC;GACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,QAAgB;IAEhB,OAAO;;;;oDAI2C,GAAG,CAAC,MAAM,CAAC;2EACY,GAAG,CAAC,MAAM,CAAC;yBAC7D,GAAG,CAAC,QAAQ,CAAC;;uCAEC,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,CAAC,QAAQ,CAAC;GACzE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,OAAO;;+CAEsC,GAAG,CAAC,MAAM,CAAC;+DACK,GAAG,CAAC,MAAM,CAAC;;;;;;;+BAO3C,GAAG,CAAC,MAAM,CAAC;GACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ImcpConfig } from "../shared/config.js";
3
+ export declare function registerMessagesTools(server: McpServer, _config: ImcpConfig): void;
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { runJxa } from "../shared/jxa.js";
3
+ import { ok, err } from "../shared/result.js";
4
+ import { listChatsScript, readChatScript, searchMessagesScript, sendMessageScript, sendFileScript, listParticipantsScript, } from "./scripts.js";
5
+ export function registerMessagesTools(server, _config) {
6
+ server.registerTool("list_chats", {
7
+ title: "List Chats",
8
+ description: "List recent chats in Messages with participants and last update time.",
9
+ inputSchema: {
10
+ limit: z.number().int().min(1).max(200).optional().default(50).describe("Max chats to return (default: 50)"),
11
+ },
12
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
13
+ }, async ({ limit }) => {
14
+ try {
15
+ return ok(await runJxa(listChatsScript(limit)));
16
+ }
17
+ catch (e) {
18
+ return err(`Failed to list chats: ${e instanceof Error ? e.message : String(e)}`);
19
+ }
20
+ });
21
+ server.registerTool("read_chat", {
22
+ title: "Read Chat",
23
+ description: "Read chat details including participants and last update time by chat ID.",
24
+ inputSchema: {
25
+ chatId: z.string().describe("Chat ID"),
26
+ },
27
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
28
+ }, async ({ chatId }) => {
29
+ try {
30
+ return ok(await runJxa(readChatScript(chatId)));
31
+ }
32
+ catch (e) {
33
+ return err(`Failed to read chat: ${e instanceof Error ? e.message : String(e)}`);
34
+ }
35
+ });
36
+ server.registerTool("search_chats", {
37
+ title: "Search Chats",
38
+ description: "Search chats by participant name, handle, or chat name.",
39
+ inputSchema: {
40
+ query: z.string().describe("Search keyword (matches chat name, participant name, or handle)"),
41
+ limit: z.number().int().min(1).max(100).optional().default(20).describe("Max results (default: 20)"),
42
+ },
43
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
44
+ }, async ({ query, limit }) => {
45
+ try {
46
+ return ok(await runJxa(searchMessagesScript(query, limit)));
47
+ }
48
+ catch (e) {
49
+ return err(`Failed to search chats: ${e instanceof Error ? e.message : String(e)}`);
50
+ }
51
+ });
52
+ server.registerTool("send_message", {
53
+ title: "Send Message",
54
+ description: "Send a text message via iMessage/SMS. Requires a phone number or email as the target handle.",
55
+ inputSchema: {
56
+ target: z.string().describe("Recipient handle (phone number or email, e.g. '+821012345678' or 'user@example.com')"),
57
+ text: z.string().min(1).max(10000).describe("Message text to send"),
58
+ },
59
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
60
+ }, async ({ target, text }) => {
61
+ try {
62
+ return ok(await runJxa(sendMessageScript(target, text)));
63
+ }
64
+ catch (e) {
65
+ return err(`Failed to send message: ${e instanceof Error ? e.message : String(e)}`);
66
+ }
67
+ });
68
+ server.registerTool("send_file", {
69
+ title: "Send File",
70
+ description: "Send a file attachment via iMessage/SMS. Requires absolute file path and recipient handle.",
71
+ inputSchema: {
72
+ target: z.string().describe("Recipient handle (phone number or email)"),
73
+ filePath: z.string().describe("Absolute path to the file to send"),
74
+ },
75
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
76
+ }, async ({ target, filePath }) => {
77
+ try {
78
+ return ok(await runJxa(sendFileScript(target, filePath)));
79
+ }
80
+ catch (e) {
81
+ return err(`Failed to send file: ${e instanceof Error ? e.message : String(e)}`);
82
+ }
83
+ });
84
+ server.registerTool("list_participants", {
85
+ title: "List Chat Participants",
86
+ description: "List all participants in a specific chat.",
87
+ inputSchema: {
88
+ chatId: z.string().describe("Chat ID"),
89
+ },
90
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
91
+ }, async ({ chatId }) => {
92
+ try {
93
+ return ok(await runJxa(listParticipantsScript(chatId)));
94
+ }
95
+ catch (e) {
96
+ return err(`Failed to list participants: ${e instanceof Error ? e.message : String(e)}`);
97
+ }
98
+ });
99
+ }
100
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/messages/tools.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@heznpc/imcp",
3
- "version": "0.7.1",
4
- "description": "MCP server for the entire Apple ecosystem — Notes, Reminders, Calendar, Contacts, Mail, Music, Finder, Safari, Photos, Shortcuts, System, and Apple Intelligence. Connect any AI to your Mac.",
3
+ "version": "0.9.0",
4
+ "description": "MCP server for the entire Apple ecosystem — Notes, Reminders, Calendar, Contacts, Mail, Messages, Music, Finder, Safari, Photos, Shortcuts, System, and Apple Intelligence. Connect any AI to your Mac.",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "model-context-protocol",
@@ -17,6 +17,8 @@
17
17
  "apple-contacts",
18
18
  "mail",
19
19
  "apple-mail",
20
+ "messages",
21
+ "imessage",
20
22
  "music",
21
23
  "apple-music",
22
24
  "finder",
@@ -56,6 +58,7 @@
56
58
  "scripts": {
57
59
  "build": "tsc",
58
60
  "swift-build": "cd swift && swift build -c release",
61
+ "app-build": "cd app && swift build -c release",
59
62
  "clean": "rm -rf dist",
60
63
  "dev": "tsx src/index.ts",
61
64
  "lint": "eslint src/",