mcp-macos 2.1.4 → 3.0.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.md +53 -230
- package/dist/config/index.d.ts +5 -32
- package/dist/config/index.js +5 -112
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +1 -144
- package/dist/config/schema.js +1 -34
- package/dist/config/schema.js.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.js +5 -46
- package/dist/index.js.map +1 -1
- package/dist/utils/errorHandling.js +1 -1
- package/dist/utils/errorHandling.js.map +1 -1
- package/dist/validation/schemas.d.ts +2 -1
- package/dist/validation/schemas.js +3 -2
- package/dist/validation/schemas.js.map +1 -1
- package/package.json +5 -10
- package/dist/server/transports/http/auth.d.ts +0 -34
- package/dist/server/transports/http/auth.js +0 -148
- package/dist/server/transports/http/auth.js.map +0 -1
- package/dist/server/transports/http/health.d.ts +0 -35
- package/dist/server/transports/http/health.js +0 -93
- package/dist/server/transports/http/health.js.map +0 -1
- package/dist/server/transports/http/index.d.ts +0 -43
- package/dist/server/transports/http/index.js +0 -147
- package/dist/server/transports/http/index.js.map +0 -1
- package/dist/server/transports/http/middleware.d.ts +0 -53
- package/dist/server/transports/http/middleware.js +0 -133
- package/dist/server/transports/http/middleware.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Based on [FradSer/mcp-server-apple-events](https://github.com/FradSer/mcp-server-apple-events)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Use with Claude Desktop locally, or Claude iOS/web remotely via Cloudflare Tunnel. **Requires a Mac** — for always-on remote access, a Mac Mini or Mac Studio is recommended.
|
|
5
|
+
MCP server for Reminders, Calendar, Notes, Mail, Messages, and Contacts on macOS. Local stdio transport for Claude Desktop, Claude Code, and Cursor.
|
|
8
6
|
|
|
9
7
|
## Quick Start
|
|
10
8
|
|
|
@@ -26,14 +24,12 @@ pnpm build
|
|
|
26
24
|
### Verify setup
|
|
27
25
|
|
|
28
26
|
```bash
|
|
29
|
-
|
|
27
|
+
macos-mcp --check # or: node dist/index.js --check
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
**Next step:** [Using Claude Desktop?](#local-setup-stdio) | [Using Claude iOS/web remotely?](#remote-setup-claude-iosweb)
|
|
30
|
+
Checks macOS version, Node.js, EventKit binary, Full Disk Access, and JXA automation permissions.
|
|
35
31
|
|
|
36
|
-
##
|
|
32
|
+
## Tools
|
|
37
33
|
|
|
38
34
|
| Tool | App | Bridge | Actions |
|
|
39
35
|
|------|-----|--------|---------|
|
|
@@ -47,22 +43,19 @@ The preflight check validates macOS version, Node.js, EventKit binary, Full Disk
|
|
|
47
43
|
| `messages_chat` | Messages | SQLite + JXA | read, create |
|
|
48
44
|
| `contacts_people` | Contacts | JXA | read, search, create, update, delete |
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
Both underscore (`reminders_tasks`) and dot (`reminders.tasks`) notation work.
|
|
51
47
|
|
|
52
|
-
##
|
|
48
|
+
## Setup
|
|
53
49
|
|
|
54
50
|
### Prerequisites
|
|
55
51
|
|
|
56
|
-
- **Node.js 20
|
|
57
|
-
- **macOS**
|
|
58
|
-
- **Xcode Command Line Tools** (
|
|
59
|
-
- **pnpm** (recommended for package management)
|
|
60
|
-
|
|
61
|
-
### Configure Your Client
|
|
52
|
+
- **Node.js 20+**
|
|
53
|
+
- **macOS**
|
|
54
|
+
- **Xcode Command Line Tools** (Swift compilation)
|
|
62
55
|
|
|
63
|
-
|
|
56
|
+
### Client Configuration
|
|
64
57
|
|
|
65
|
-
|
|
58
|
+
The JSON config is the same for all clients — just the location differs.
|
|
66
59
|
|
|
67
60
|
```json
|
|
68
61
|
{
|
|
@@ -75,115 +68,15 @@ Add to your `claude_desktop_config.json`:
|
|
|
75
68
|
}
|
|
76
69
|
```
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
"mcpServers": {
|
|
85
|
-
"macos-mcp": {
|
|
86
|
-
"command": "npx",
|
|
87
|
-
"args": ["mcp-macos"]
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
#### Claude Code
|
|
94
|
-
|
|
95
|
-
Add a `.mcp.json` to your project root:
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"mcpServers": {
|
|
100
|
-
"macos-mcp": {
|
|
101
|
-
"command": "npx",
|
|
102
|
-
"args": ["mcp-macos"]
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
71
|
+
| Client | Config location |
|
|
72
|
+
|--------|----------------|
|
|
73
|
+
| Claude Desktop | `claude_desktop_config.json` |
|
|
74
|
+
| Cursor | Settings > MCP > Add new global MCP server |
|
|
75
|
+
| Claude Code | `.mcp.json` in project root |
|
|
107
76
|
|
|
108
77
|
### Permissions
|
|
109
78
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- **Reminders & Calendar** — EventKit permission dialogs appear automatically.
|
|
113
|
-
- **Notes, Mail, Contacts** — Automation permission dialogs appear when `osascript` first controls each app. Grant access via **System Settings > Privacy & Security > Automation**.
|
|
114
|
-
- **Messages & Mail** — Require **Full Disk Access** for your terminal app (Terminal, iTerm2, etc.) since both read SQLite databases directly.
|
|
115
|
-
|
|
116
|
-
Run `node dist/index.js --check` to verify all permissions are granted. See [Troubleshooting](#troubleshooting) if anything fails.
|
|
117
|
-
|
|
118
|
-
## Remote Setup (Claude iOS/web)
|
|
119
|
-
|
|
120
|
-
Use this path to access your Mac's apps from Claude iOS or Claude web via a secure Cloudflare Tunnel.
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
124
|
-
│ Claude iOS │──────│ Cloudflare │──────│ Your Mac │
|
|
125
|
-
│ or Web │ HTTPS│ Edge + Access │tunnel│ macos-mcp │
|
|
126
|
-
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### What you'll set up
|
|
130
|
-
|
|
131
|
-
1. **Cloudflare Tunnel** — Secure outbound connection from your Mac to Cloudflare's edge
|
|
132
|
-
2. **Cloudflare Access** — Email OTP authentication so only you can connect
|
|
133
|
-
3. **LaunchAgents** — Auto-start on boot for both the server and tunnel
|
|
134
|
-
4. **Permissions** — Automation + Full Disk Access granted to the node binary
|
|
135
|
-
|
|
136
|
-
### Prerequisites
|
|
137
|
-
|
|
138
|
-
- **Cloudflare account** (free tier works)
|
|
139
|
-
- **Custom domain** in Cloudflare (or use `.cfargotunnel.com` subdomain)
|
|
140
|
-
- **Always-on Mac** (Mac Mini/Studio recommended)
|
|
141
|
-
- **macos-mcp built and working locally** (`pnpm build && node dist/index.js --check`)
|
|
142
|
-
|
|
143
|
-
### Full Setup Guide
|
|
144
|
-
|
|
145
|
-
Follow the step-by-step instructions in **[`docs/CLOUDFLARE_SETUP.md`](docs/CLOUDFLARE_SETUP.md)** — covers tunnel creation, Cloudflare Access configuration, LaunchAgent setup, permission granting, and registering in Claude iOS.
|
|
146
|
-
|
|
147
|
-
## Usage Examples
|
|
148
|
-
|
|
149
|
-
### Reminders
|
|
150
|
-
```
|
|
151
|
-
Create a reminder to "Buy groceries" for tomorrow at 5 PM.
|
|
152
|
-
Show all reminders in my "Work" list.
|
|
153
|
-
Organize my reminders by priority.
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Calendar
|
|
157
|
-
```
|
|
158
|
-
Create a meeting "Team Standup" tomorrow from 10 AM to 10:30 AM.
|
|
159
|
-
Show my calendar events for this week.
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Notes
|
|
163
|
-
```
|
|
164
|
-
Create a note titled "Meeting Notes" in the Work folder.
|
|
165
|
-
Search my notes for "project plan".
|
|
166
|
-
List all note folders.
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Mail
|
|
170
|
-
```
|
|
171
|
-
Show my inbox.
|
|
172
|
-
Read the email from John about the project.
|
|
173
|
-
Draft an email to alice@example.com about the meeting.
|
|
174
|
-
Reply to the last email from Bob.
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Messages
|
|
178
|
-
```
|
|
179
|
-
Show my recent iMessage chats.
|
|
180
|
-
Read messages from the chat with John.
|
|
181
|
-
Send "On my way!" to the group chat.
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Troubleshooting
|
|
185
|
-
|
|
186
|
-
### Permission Quick Reference
|
|
79
|
+
macOS prompts for access on first use. Click **Allow** when prompted.
|
|
187
80
|
|
|
188
81
|
| App | Permission | System Settings Path |
|
|
189
82
|
|-----|------------|---------------------|
|
|
@@ -194,6 +87,12 @@ Send "On my way!" to the group chat.
|
|
|
194
87
|
| Messages | Automation + Full Disk Access | Both locations |
|
|
195
88
|
| Contacts | Automation | Privacy & Security > Automation > Contacts |
|
|
196
89
|
|
|
90
|
+
Messages and Mail read SQLite databases directly, so your terminal app (Terminal, iTerm2, etc.) needs **Full Disk Access**.
|
|
91
|
+
|
|
92
|
+
Run `macos-mcp --check` to verify. See [Troubleshooting](#troubleshooting) if anything fails.
|
|
93
|
+
|
|
94
|
+
## Troubleshooting
|
|
95
|
+
|
|
197
96
|
### Quick-Fix Commands
|
|
198
97
|
|
|
199
98
|
```bash
|
|
@@ -202,154 +101,78 @@ open "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders"
|
|
|
202
101
|
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Calendars"
|
|
203
102
|
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation"
|
|
204
103
|
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"
|
|
205
|
-
|
|
206
|
-
# Run preflight check
|
|
207
|
-
node dist/index.js --check
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### EventKit (Reminders & Calendar)
|
|
211
|
-
|
|
212
|
-
Apple separates Reminders and Calendar permissions into *write-only* and *full-access* scopes. The Swift bridge declares the following privacy keys:
|
|
213
|
-
|
|
214
|
-
- `NSRemindersUsageDescription` / `NSRemindersFullAccessUsageDescription` / `NSRemindersWriteOnlyAccessUsageDescription`
|
|
215
|
-
- `NSCalendarsUsageDescription` / `NSCalendarsFullAccessUsageDescription` / `NSCalendarsWriteOnlyAccessUsageDescription`
|
|
216
|
-
|
|
217
|
-
If a permission failure occurs, the Node.js layer automatically runs a minimal AppleScript to surface the dialog and retries.
|
|
218
|
-
|
|
219
|
-
### JXA Automation (Notes, Mail, Contacts)
|
|
220
|
-
|
|
221
|
-
JXA-based tools require macOS Automation permissions. On first use, macOS will prompt you to allow `osascript` to control each app.
|
|
222
|
-
|
|
223
|
-
> **Headless / LaunchAgent:** Automation permission dialogs **cannot appear** through a LaunchAgent, SSH session, or any non-GUI context. You must grant them once from a local graphical Terminal session (physical access or Screen Sharing). See [`docs/CLOUDFLARE_SETUP.md`](docs/CLOUDFLARE_SETUP.md) Step 10 for the full procedure. Once granted, permissions persist across reboots.
|
|
224
|
-
|
|
225
|
-
**Verify all Automation permissions:**
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
/usr/bin/osascript -l JavaScript -e 'Application("Contacts").people().length'
|
|
229
|
-
/usr/bin/osascript -l JavaScript -e 'Application("Calendar").calendars().length'
|
|
230
|
-
/usr/bin/osascript -l JavaScript -e 'Application("Reminders").defaultList().name()'
|
|
231
|
-
/usr/bin/osascript -l JavaScript -e 'Application("Mail").inbox().messages().length'
|
|
232
|
-
/usr/bin/osascript -l JavaScript -e 'Application("Notes").notes().length'
|
|
233
104
|
```
|
|
234
105
|
|
|
235
|
-
Each command should return a value without errors or hanging. A hang means the permission dialog is trying (and failing) to appear.
|
|
236
|
-
|
|
237
106
|
### Full Disk Access (Messages & Mail)
|
|
238
107
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
- **stdio transport**: Grant FDA to your terminal app (Terminal, iTerm2, etc.)
|
|
242
|
-
- **HTTP transport / LaunchAgent**: Grant FDA to the **actual node binary**, not a version manager shim
|
|
243
|
-
|
|
244
|
-
To find and grant access to the correct binary:
|
|
108
|
+
Messages and Mail read SQLite databases (`~/Library/Messages/chat.db` and `~/Library/Mail/V10/MailData/Envelope Index`). These require Full Disk Access on your terminal app.
|
|
245
109
|
|
|
246
110
|
```bash
|
|
247
|
-
# Find
|
|
111
|
+
# Find your real node binary (version managers use shims)
|
|
248
112
|
node -e "console.log(process.execPath)"
|
|
249
113
|
|
|
250
|
-
# Reveal it in Finder
|
|
114
|
+
# Reveal it in Finder for drag-and-drop into FDA settings
|
|
251
115
|
open -R "$(node -e "console.log(process.execPath)")"
|
|
252
116
|
|
|
253
117
|
# Open Full Disk Access settings
|
|
254
118
|
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"
|
|
255
119
|
```
|
|
256
120
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
### Version Manager Shim Resolution
|
|
260
|
-
|
|
261
|
-
If you use **Volta**, **nvm**, or **fnm**, the `node` command is a shim/launcher. System Settings needs the real binary:
|
|
121
|
+
**Version manager users** (Volta, nvm, fnm): the `node` command is a shim. System Settings needs the real binary:
|
|
262
122
|
|
|
263
123
|
| Manager | Find real binary |
|
|
264
124
|
|---------|-----------------|
|
|
265
|
-
| Volta | `volta which node`
|
|
125
|
+
| Volta | `volta which node` |
|
|
266
126
|
| nvm | `nvm which current` |
|
|
267
127
|
| fnm | `fnm exec -- node -e "console.log(process.execPath)"` |
|
|
268
128
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
### Gmail Labels / Missing Inbox Messages
|
|
129
|
+
System Settings may not show binaries in hidden directories — use `open -R` above to reveal it in Finder, then drag into the FDA list.
|
|
272
130
|
|
|
273
|
-
|
|
131
|
+
### JXA Automation (Notes, Mail, Contacts)
|
|
274
132
|
|
|
275
|
-
|
|
133
|
+
On first use, macOS prompts for Automation access. Grant via **System Settings > Privacy & Security > Automation**.
|
|
276
134
|
|
|
277
|
-
|
|
135
|
+
Verify permissions:
|
|
278
136
|
|
|
279
137
|
```bash
|
|
280
|
-
|
|
281
|
-
|
|
138
|
+
osascript -l JavaScript -e 'Application("Contacts").people().length'
|
|
139
|
+
osascript -l JavaScript -e 'Application("Calendar").calendars().length'
|
|
140
|
+
osascript -l JavaScript -e 'Application("Reminders").defaultList().name()'
|
|
141
|
+
osascript -l JavaScript -e 'Application("Mail").inbox().messages().length'
|
|
142
|
+
osascript -l JavaScript -e 'Application("Notes").notes().length'
|
|
282
143
|
```
|
|
283
144
|
|
|
145
|
+
Each command should return a value. A hang means the permission dialog is trying (and failing) to appear.
|
|
146
|
+
|
|
147
|
+
### Gmail Labels / Missing Inbox Messages
|
|
148
|
+
|
|
149
|
+
Gmail stores all messages in `[Gmail]/All Mail` and uses labels for folder membership. The server checks both the direct mailbox and labels join table. If Gmail inbox messages are missing, verify the Mail app has fully synced.
|
|
150
|
+
|
|
284
151
|
## Development
|
|
285
152
|
|
|
286
153
|
```bash
|
|
287
154
|
pnpm install # Install dependencies
|
|
288
155
|
pnpm build # Build TypeScript + Swift binary
|
|
289
156
|
pnpm test # Run full test suite
|
|
290
|
-
pnpm lint # Lint and format
|
|
291
|
-
pnpm dev # Run from source via tsx
|
|
157
|
+
pnpm lint # Lint and format (Biome + TypeScript)
|
|
158
|
+
pnpm dev # Run from source via tsx
|
|
292
159
|
```
|
|
293
160
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
### End-to-End Testing
|
|
297
|
-
|
|
298
|
-
For HTTP transport testing, an E2E script is available:
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
./scripts/test-e2e.sh
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
This script:
|
|
305
|
-
- Starts the server in HTTP mode
|
|
306
|
-
- Tests health endpoints
|
|
307
|
-
- Verifies CORS headers and OPTIONS preflight
|
|
308
|
-
- Tests MCP endpoint availability
|
|
309
|
-
- Tests rate limit headers
|
|
310
|
-
- Verifies graceful shutdown
|
|
311
|
-
|
|
312
|
-
Requirements: `jq` (install with `brew install jq`)
|
|
161
|
+
Production entry point (`bin/run.cjs`) requires `pnpm build`. Use `pnpm dev` for local development.
|
|
313
162
|
|
|
314
163
|
### Architecture
|
|
315
164
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
- **EventKit (Swift binary)** — Reminders and Calendar. A compiled Swift CLI binary performs EventKit operations and returns JSON.
|
|
319
|
-
- **JXA (JavaScript for Automation)** — Notes, Mail, Contacts. Scripts run via `osascript -l JavaScript` with template-based parameter interpolation.
|
|
320
|
-
- **SQLite** — Messages reads (`~/Library/Messages/chat.db`) and Mail reads (`~/Library/Mail/V10/MailData/Envelope Index`). JXA message reading is broken on macOS Sonoma+; JXA mail reading is too slow for real inboxes. Writes still use JXA.
|
|
321
|
-
|
|
322
|
-
### HTTP Transport Configuration
|
|
323
|
-
|
|
324
|
-
The server supports HTTP transport for remote access. Set via environment variables or `macos-mcp.config.json`:
|
|
325
|
-
|
|
326
|
-
| Variable | Default | Description |
|
|
327
|
-
|----------|---------|-------------|
|
|
328
|
-
| `MCP_TRANSPORT` | `stdio` | Transport mode: `stdio`, `http`, or `both` |
|
|
329
|
-
| `MCP_HTTP_ENABLED` | `false` | Enable HTTP transport |
|
|
330
|
-
| `MCP_HTTP_PORT` | `3847` | HTTP server port |
|
|
331
|
-
|
|
332
|
-
Key design decisions:
|
|
333
|
-
- **Stateless mode** — required for multi-client support (Claude.ai serves multiple users)
|
|
334
|
-
- **Root endpoint** — MCP handler at `/` (Claude expects this, not `/mcp`)
|
|
335
|
-
- **JSON fallback** — `enableJsonResponse: true` for clients without SSE support
|
|
336
|
-
|
|
337
|
-
### Structured Prompt Library
|
|
338
|
-
|
|
339
|
-
The server ships with prompt templates exposed via MCP `ListPrompts` and `GetPrompt` endpoints:
|
|
340
|
-
|
|
341
|
-
- **daily-task-organizer** — optional `today_focus` input produces a same-day execution blueprint
|
|
342
|
-
- **smart-reminder-creator** — optional `task_idea` generates an optimally scheduled reminder
|
|
343
|
-
- **reminder-review-assistant** — optional `review_focus` to audit and optimize existing reminders
|
|
344
|
-
- **weekly-planning-workflow** — optional `user_ideas` guides a Monday-through-Sunday reset
|
|
165
|
+
Three bridges to Apple apps:
|
|
345
166
|
|
|
346
|
-
|
|
167
|
+
- **EventKit (Swift binary)** — Reminders, Calendar. Compiled Swift CLI, returns JSON.
|
|
168
|
+
- **JXA** — Notes, Mail writes, Contacts. Scripts run via `osascript -l JavaScript`.
|
|
169
|
+
- **SQLite** — Messages reads (`~/Library/Messages/chat.db`), Mail reads (`~/Library/Mail/V10/MailData/Envelope Index`). JXA message reading is broken on Sonoma+; JXA mail reading is too slow for real inboxes.
|
|
347
170
|
|
|
348
171
|
### Dependencies
|
|
349
172
|
|
|
350
|
-
**Runtime:** `@modelcontextprotocol/sdk`, `
|
|
173
|
+
**Runtime:** `@modelcontextprotocol/sdk`, `zod`
|
|
351
174
|
|
|
352
|
-
**Dev:** `typescript`, `tsx`, `jest`,
|
|
175
|
+
**Dev:** `typescript`, `tsx`, `jest`, `@biomejs/biome`
|
|
353
176
|
|
|
354
177
|
## License
|
|
355
178
|
|
|
@@ -357,4 +180,4 @@ MIT
|
|
|
357
180
|
|
|
358
181
|
## Contributing
|
|
359
182
|
|
|
360
|
-
|
|
183
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,36 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Configuration
|
|
2
|
+
* @fileoverview Configuration loader for macos-mcp server
|
|
3
3
|
* @module config
|
|
4
|
-
* @description
|
|
5
|
-
*/
|
|
6
|
-
import { type CloudflareAccessConfig, type FullServerConfig, type HttpConfig } from './schema.js';
|
|
7
|
-
/**
|
|
8
|
-
* Loads server configuration from file and environment variables
|
|
9
|
-
*
|
|
10
|
-
* Configuration is loaded in the following priority (highest to lowest):
|
|
11
|
-
* 1. Environment variables (MCP_TRANSPORT, MCP_HTTP_*, CF_ACCESS_*)
|
|
12
|
-
* 2. Configuration file (macos-mcp.config.json in project root)
|
|
13
|
-
* 3. Default values from schema
|
|
14
|
-
*
|
|
15
|
-
* Name and version are always auto-injected from package.json
|
|
16
|
-
*
|
|
17
|
-
* @returns Validated server configuration
|
|
18
|
-
* @throws Error if configuration is invalid
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* // Basic usage
|
|
22
|
-
* const config = loadConfig();
|
|
23
|
-
* console.log(config.transport); // 'stdio' (default)
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* // With environment variables
|
|
27
|
-
* // MCP_TRANSPORT=http
|
|
28
|
-
* // MCP_HTTP_ENABLED=true
|
|
29
|
-
* // MCP_HTTP_PORT=8080
|
|
30
|
-
* const config = loadConfig();
|
|
31
|
-
* console.log(config.transport); // 'http'
|
|
32
|
-
* console.log(config.http?.port); // 8080
|
|
4
|
+
* @description Auto-injects name + version from package.json
|
|
33
5
|
*/
|
|
6
|
+
import { type FullServerConfig } from './schema.js';
|
|
34
7
|
export declare function loadConfig(): FullServerConfig;
|
|
35
|
-
export type {
|
|
36
|
-
export {
|
|
8
|
+
export type { FullServerConfig };
|
|
9
|
+
export { ServerConfigSchema } from './schema.js';
|
package/dist/config/index.js
CHANGED
|
@@ -1,127 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Configuration
|
|
2
|
+
* @fileoverview Configuration loader for macos-mcp server
|
|
3
3
|
* @module config
|
|
4
|
-
* @description
|
|
4
|
+
* @description Auto-injects name + version from package.json
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { findProjectRoot } from '../utils/projectUtils.js';
|
|
9
|
-
import { ServerConfigSchema
|
|
10
|
-
/** Configuration file name */
|
|
11
|
-
const CONFIG_FILENAME = 'macos-mcp.config.json';
|
|
12
|
-
/**
|
|
13
|
-
* Loads server configuration from file and environment variables
|
|
14
|
-
*
|
|
15
|
-
* Configuration is loaded in the following priority (highest to lowest):
|
|
16
|
-
* 1. Environment variables (MCP_TRANSPORT, MCP_HTTP_*, CF_ACCESS_*)
|
|
17
|
-
* 2. Configuration file (macos-mcp.config.json in project root)
|
|
18
|
-
* 3. Default values from schema
|
|
19
|
-
*
|
|
20
|
-
* Name and version are always auto-injected from package.json
|
|
21
|
-
*
|
|
22
|
-
* @returns Validated server configuration
|
|
23
|
-
* @throws Error if configuration is invalid
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* // Basic usage
|
|
27
|
-
* const config = loadConfig();
|
|
28
|
-
* console.log(config.transport); // 'stdio' (default)
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* // With environment variables
|
|
32
|
-
* // MCP_TRANSPORT=http
|
|
33
|
-
* // MCP_HTTP_ENABLED=true
|
|
34
|
-
* // MCP_HTTP_PORT=8080
|
|
35
|
-
* const config = loadConfig();
|
|
36
|
-
* console.log(config.transport); // 'http'
|
|
37
|
-
* console.log(config.http?.port); // 8080
|
|
38
|
-
*/
|
|
9
|
+
import { ServerConfigSchema } from './schema.js';
|
|
39
10
|
export function loadConfig() {
|
|
40
11
|
const projectRoot = findProjectRoot();
|
|
41
|
-
const configPath = join(projectRoot, CONFIG_FILENAME);
|
|
42
|
-
// Load file configuration if it exists
|
|
43
|
-
let fileConfig = {};
|
|
44
|
-
if (existsSync(configPath)) {
|
|
45
|
-
const fileContent = readFileSync(configPath, 'utf-8');
|
|
46
|
-
fileConfig = JSON.parse(fileContent);
|
|
47
|
-
}
|
|
48
|
-
// Build environment variable configuration
|
|
49
|
-
const envConfig = buildEnvConfig();
|
|
50
|
-
// Deep merge file config with env config (env takes precedence)
|
|
51
|
-
const merged = deepMerge(fileConfig, envConfig);
|
|
52
|
-
// Load package.json for name and version
|
|
53
12
|
const packageJsonPath = join(projectRoot, 'package.json');
|
|
54
13
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
55
|
-
// Parse and validate configuration
|
|
56
14
|
return ServerConfigSchema.parse({
|
|
57
15
|
name: packageJson.name,
|
|
58
16
|
version: packageJson.version,
|
|
59
|
-
...merged,
|
|
60
17
|
});
|
|
61
18
|
}
|
|
62
|
-
|
|
63
|
-
* Builds configuration object from environment variables
|
|
64
|
-
* @returns Partial configuration from environment variables
|
|
65
|
-
*/
|
|
66
|
-
function buildEnvConfig() {
|
|
67
|
-
const config = {};
|
|
68
|
-
// Transport mode
|
|
69
|
-
if (process.env.MCP_TRANSPORT) {
|
|
70
|
-
config.transport = process.env.MCP_TRANSPORT;
|
|
71
|
-
}
|
|
72
|
-
// HTTP configuration (only if explicitly enabled)
|
|
73
|
-
if (process.env.MCP_HTTP_ENABLED === 'true') {
|
|
74
|
-
const httpConfig = {
|
|
75
|
-
enabled: true,
|
|
76
|
-
};
|
|
77
|
-
if (process.env.MCP_HTTP_HOST) {
|
|
78
|
-
httpConfig.host = process.env.MCP_HTTP_HOST;
|
|
79
|
-
}
|
|
80
|
-
if (process.env.MCP_HTTP_PORT) {
|
|
81
|
-
const port = Number.parseInt(process.env.MCP_HTTP_PORT, 10);
|
|
82
|
-
if (!Number.isNaN(port)) {
|
|
83
|
-
httpConfig.port = port;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// Cloudflare Access configuration
|
|
87
|
-
if (process.env.CF_ACCESS_TEAM_DOMAIN && process.env.CF_ACCESS_POLICY_AUD) {
|
|
88
|
-
const cfConfig = {
|
|
89
|
-
teamDomain: process.env.CF_ACCESS_TEAM_DOMAIN,
|
|
90
|
-
policyAUD: process.env.CF_ACCESS_POLICY_AUD,
|
|
91
|
-
};
|
|
92
|
-
if (process.env.CF_ACCESS_ALLOWED_EMAILS) {
|
|
93
|
-
cfConfig.allowedEmails = process.env.CF_ACCESS_ALLOWED_EMAILS.split(',').map((e) => e.trim());
|
|
94
|
-
}
|
|
95
|
-
httpConfig.cloudflareAccess = cfConfig;
|
|
96
|
-
}
|
|
97
|
-
config.http = httpConfig;
|
|
98
|
-
}
|
|
99
|
-
return config;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Deep merges two objects, with source taking precedence
|
|
103
|
-
* @param target - Base object
|
|
104
|
-
* @param source - Object to merge in (takes precedence)
|
|
105
|
-
* @returns Merged object
|
|
106
|
-
*/
|
|
107
|
-
function deepMerge(target, source) {
|
|
108
|
-
const result = { ...target };
|
|
109
|
-
for (const key of Object.keys(source)) {
|
|
110
|
-
const sourceValue = source[key];
|
|
111
|
-
const targetValue = result[key];
|
|
112
|
-
if (sourceValue !== null &&
|
|
113
|
-
typeof sourceValue === 'object' &&
|
|
114
|
-
!Array.isArray(sourceValue) &&
|
|
115
|
-
targetValue !== null &&
|
|
116
|
-
typeof targetValue === 'object' &&
|
|
117
|
-
!Array.isArray(targetValue)) {
|
|
118
|
-
result[key] = deepMerge(targetValue, sourceValue);
|
|
119
|
-
}
|
|
120
|
-
else if (sourceValue !== undefined) {
|
|
121
|
-
result[key] = sourceValue;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
export { CloudflareAccessConfigSchema, HttpConfigSchema, ServerConfigSchema, } from './schema.js';
|
|
19
|
+
export { ServerConfigSchema } from './schema.js';
|
|
127
20
|
//# sourceMappingURL=index.js.map
|
package/dist/config/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAyB,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,UAAU,UAAU;IACxB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAGpE,CAAC;IAEF,OAAO,kBAAkB,CAAC,KAAK,CAAC;QAC9B,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,OAAO,EAAE,WAAW,CAAC,OAAO;KAC7B,CAAC,CAAC;AACL,CAAC;AAGD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|