Skip to content

Commit 6986ad2

Browse files
charlieseayclaude
andcommitted
Add entitlements, Info.plist, and BinnacleCore module
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d0e313d commit 6986ad2

4 files changed

Lines changed: 313 additions & 6 deletions

File tree

Package.swift

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:6.0
1+
// swift-tools-version: 6.1
22

33
import PackageDescription
44

@@ -7,22 +7,41 @@ let package = Package(
77
platforms: [
88
.macOS(.v14)
99
],
10-
products: [
11-
.executable(name: "binnacle", targets: ["Binnacle"])
12-
],
1310
dependencies: [
14-
.package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", branch: "main")
11+
.package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.11.0")
1512
],
1613
targets: [
14+
.target(
15+
name: "BinnacleCore",
16+
dependencies: [
17+
.product(name: "MCP", package: "swift-sdk")
18+
],
19+
path: "Sources/BinnacleCore"
20+
),
1721
.executableTarget(
1822
name: "Binnacle",
1923
dependencies: [
24+
"BinnacleCore",
2025
.product(name: "MCP", package: "swift-sdk")
26+
],
27+
path: "Sources/Binnacle",
28+
exclude: ["Binnacle.entitlements", "Info.plist"],
29+
linkerSettings: [
30+
.unsafeFlags([
31+
"-Xlinker", "-sectcreate",
32+
"-Xlinker", "__TEXT",
33+
"-Xlinker", "__info_plist",
34+
"-Xlinker", "Sources/Binnacle/Info.plist"
35+
])
2136
]
2237
),
2338
.testTarget(
2439
name: "BinnacleTests",
25-
dependencies: ["Binnacle"]
40+
dependencies: [
41+
"BinnacleCore",
42+
.product(name: "MCP", package: "swift-sdk")
43+
],
44+
path: "Tests/BinnacleTests"
2645
)
2746
]
2847
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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>com.apple.security.personal-information.calendars</key>
6+
<true/>
7+
<key>com.apple.security.personal-information.reminders</key>
8+
<true/>
9+
<key>com.apple.security.app-sandbox</key>
10+
<false/>
11+
</dict>
12+
</plist>

Sources/Binnacle/Info.plist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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>CFBundleIdentifier</key>
6+
<string>com.seayniclabs.binnacle</string>
7+
<key>CFBundleName</key>
8+
<string>Binnacle</string>
9+
<key>CFBundleVersion</key>
10+
<string>0.1.0</string>
11+
<key>CFBundleShortVersionString</key>
12+
<string>0.1.0</string>
13+
<key>NSCalendarsUsageDescription</key>
14+
<string>Binnacle needs calendar access to read and manage your events.</string>
15+
<key>NSRemindersUsageDescription</key>
16+
<string>Binnacle needs reminders access to read and manage your reminders.</string>
17+
<key>NSCalendarsFullAccessUsageDescription</key>
18+
<string>Binnacle needs full calendar access to create, update, and delete events.</string>
19+
<key>NSRemindersFullAccessUsageDescription</key>
20+
<string>Binnacle needs full reminders access to create and complete reminders.</string>
21+
</dict>
22+
</plist>
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
import MCP
2+
3+
/// Binnacle server metadata and tool registry
4+
public enum Binnacle {
5+
public static let serverName = "binnacle"
6+
public static let serverVersion = "0.1.0"
7+
8+
/// All tool definitions for the Binnacle MCP server.
9+
/// Separated from the executable so they can be tested independently.
10+
public static let tools: [Tool] = [PingTool.tool]
11+
+ CalendarToolDefs.allTools
12+
+ ReminderToolDefs.allTools
13+
+ ShortcutToolDefs.allTools
14+
15+
/// Expected tool names in registration order
16+
public static let toolNames: [String] = tools.map(\.name)
17+
18+
/// The ping response text, including the current version
19+
public static var pingResponse: String {
20+
"""
21+
{"status":"ok","server":"binnacle","version":"\(serverVersion)"}
22+
"""
23+
}
24+
}
25+
26+
// MARK: - Ping Tool Definition
27+
28+
public enum PingTool {
29+
public static let tool = Tool(
30+
name: "ping",
31+
description: "Health check — returns server version and status",
32+
inputSchema: .object([
33+
"type": "object",
34+
"properties": .object([:])
35+
]),
36+
annotations: .init(readOnlyHint: true, openWorldHint: false)
37+
)
38+
}
39+
40+
// MARK: - Calendar Tool Definitions
41+
42+
public enum CalendarToolDefs {
43+
44+
public static let calendarList = Tool(
45+
name: "calendar_list",
46+
description: "List all calendars available on this Mac",
47+
inputSchema: .object([
48+
"type": "object",
49+
"properties": .object([:])
50+
]),
51+
annotations: .init(readOnlyHint: true, openWorldHint: false)
52+
)
53+
54+
public static let calendarToday = Tool(
55+
name: "calendar_today",
56+
description: "List today's calendar events",
57+
inputSchema: .object([
58+
"type": "object",
59+
"properties": .object([:])
60+
]),
61+
annotations: .init(readOnlyHint: true, openWorldHint: false)
62+
)
63+
64+
public static let calendarRange = Tool(
65+
name: "calendar_range",
66+
description: "List calendar events in a date range",
67+
inputSchema: .object([
68+
"type": "object",
69+
"properties": .object([
70+
"start": .object(["type": "string", "description": "Start date (ISO8601)"]),
71+
"end": .object(["type": "string", "description": "End date (ISO8601)"])
72+
]),
73+
"required": .array(["start", "end"])
74+
]),
75+
annotations: .init(readOnlyHint: true, openWorldHint: false)
76+
)
77+
78+
public static let calendarCreate = Tool(
79+
name: "calendar_create",
80+
description: "Create a calendar event",
81+
inputSchema: .object([
82+
"type": "object",
83+
"properties": .object([
84+
"title": .object(["type": "string", "description": "Event title"]),
85+
"start": .object(["type": "string", "description": "Start date (ISO8601)"]),
86+
"end": .object(["type": "string", "description": "End date (ISO8601)"]),
87+
"calendar_id": .object(["type": "string", "description": "Calendar identifier (optional)"]),
88+
"location": .object(["type": "string", "description": "Event location (optional)"]),
89+
"notes": .object(["type": "string", "description": "Event notes (optional)"])
90+
]),
91+
"required": .array(["title", "start", "end"])
92+
]),
93+
annotations: .init(
94+
readOnlyHint: false,
95+
destructiveHint: false,
96+
idempotentHint: false,
97+
openWorldHint: false
98+
)
99+
)
100+
101+
public static let calendarUpdate = Tool(
102+
name: "calendar_update",
103+
description: "Update an existing calendar event",
104+
inputSchema: .object([
105+
"type": "object",
106+
"properties": .object([
107+
"event_id": .object(["type": "string", "description": "Event identifier"]),
108+
"title": .object(["type": "string", "description": "New title (optional)"]),
109+
"start": .object(["type": "string", "description": "New start date ISO8601 (optional)"]),
110+
"end": .object(["type": "string", "description": "New end date ISO8601 (optional)"]),
111+
"location": .object(["type": "string", "description": "New location (optional)"]),
112+
"notes": .object(["type": "string", "description": "New notes (optional)"])
113+
]),
114+
"required": .array(["event_id"])
115+
]),
116+
annotations: .init(
117+
readOnlyHint: false,
118+
destructiveHint: false,
119+
idempotentHint: true,
120+
openWorldHint: false
121+
)
122+
)
123+
124+
public static let calendarDelete = Tool(
125+
name: "calendar_delete",
126+
description: "Delete a calendar event",
127+
inputSchema: .object([
128+
"type": "object",
129+
"properties": .object([
130+
"event_id": .object(["type": "string", "description": "Event identifier"])
131+
]),
132+
"required": .array(["event_id"])
133+
]),
134+
annotations: .init(
135+
readOnlyHint: false,
136+
destructiveHint: true,
137+
idempotentHint: true,
138+
openWorldHint: false
139+
)
140+
)
141+
142+
public static var allTools: [Tool] {
143+
[calendarList, calendarToday, calendarRange, calendarCreate, calendarUpdate, calendarDelete]
144+
}
145+
}
146+
147+
// MARK: - Reminder Tool Definitions
148+
149+
public enum ReminderToolDefs {
150+
151+
public static let remindersList = Tool(
152+
name: "reminders_list",
153+
description: "List reminders, optionally filtered by list name",
154+
inputSchema: .object([
155+
"type": "object",
156+
"properties": .object([
157+
"list_name": .object(["type": "string", "description": "Filter by reminder list name (optional)"]),
158+
"show_completed": .object(["type": "boolean", "description": "Include completed reminders (default: false)"])
159+
])
160+
]),
161+
annotations: .init(readOnlyHint: true, openWorldHint: false)
162+
)
163+
164+
public static let remindersCreate = Tool(
165+
name: "reminders_create",
166+
description: "Create a new reminder",
167+
inputSchema: .object([
168+
"type": "object",
169+
"properties": .object([
170+
"title": .object(["type": "string", "description": "Reminder title"]),
171+
"due_date": .object(["type": "string", "description": "Due date ISO8601 (optional)"]),
172+
"priority": .object(["type": "integer", "description": "Priority 0-9, 0=none (optional)"]),
173+
"list_name": .object(["type": "string", "description": "Reminder list name (optional)"])
174+
]),
175+
"required": .array(["title"])
176+
]),
177+
annotations: .init(
178+
readOnlyHint: false,
179+
destructiveHint: false,
180+
idempotentHint: false,
181+
openWorldHint: false
182+
)
183+
)
184+
185+
public static let remindersComplete = Tool(
186+
name: "reminders_complete",
187+
description: "Mark a reminder as complete",
188+
inputSchema: .object([
189+
"type": "object",
190+
"properties": .object([
191+
"reminder_id": .object(["type": "string", "description": "Reminder identifier"])
192+
]),
193+
"required": .array(["reminder_id"])
194+
]),
195+
annotations: .init(
196+
readOnlyHint: false,
197+
destructiveHint: false,
198+
idempotentHint: true,
199+
openWorldHint: false
200+
)
201+
)
202+
203+
public static var allTools: [Tool] {
204+
[remindersList, remindersCreate, remindersComplete]
205+
}
206+
}
207+
208+
// MARK: - Shortcut Tool Definitions
209+
210+
public enum ShortcutToolDefs {
211+
212+
public static let shortcutsList = Tool(
213+
name: "shortcuts_list",
214+
description: "List all Shortcuts available on this Mac",
215+
inputSchema: .object([
216+
"type": "object",
217+
"properties": .object([:])
218+
]),
219+
annotations: .init(readOnlyHint: true, openWorldHint: false)
220+
)
221+
222+
public static let shortcutsRun = Tool(
223+
name: "shortcuts_run",
224+
description: "Run a Shortcut by name with optional text input",
225+
inputSchema: .object([
226+
"type": "object",
227+
"properties": .object([
228+
"name": .object(["type": "string", "description": "Shortcut name"]),
229+
"input": .object(["type": "string", "description": "Text input to pass to the Shortcut (optional)"])
230+
]),
231+
"required": .array(["name"])
232+
]),
233+
annotations: .init(
234+
readOnlyHint: false,
235+
destructiveHint: false,
236+
idempotentHint: false,
237+
openWorldHint: true
238+
)
239+
)
240+
241+
public static let shortcutsFolders = Tool(
242+
name: "shortcuts_folders",
243+
description: "List Shortcut folders",
244+
inputSchema: .object([
245+
"type": "object",
246+
"properties": .object([:])
247+
]),
248+
annotations: .init(readOnlyHint: true, openWorldHint: false)
249+
)
250+
251+
public static var allTools: [Tool] {
252+
[shortcutsList, shortcutsRun, shortcutsFolders]
253+
}
254+
}

0 commit comments

Comments
 (0)