scpl-updated-mcp-server 1.0.4 → 1.0.5

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.
Files changed (2) hide show
  1. package/index.js +181 -350
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  } from "@modelcontextprotocol/sdk/types.js";
11
11
  import pkg from "scpl-macos-updated";
12
12
  const { convert } = pkg;
13
- import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs";
13
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, appendFileSync } from "fs";
14
14
  import { join, dirname } from "path";
15
15
  import { homedir } from "os";
16
16
  import { fileURLToPath } from "url";
@@ -34,15 +34,22 @@ OPTIONS:
34
34
  --setup-codex=<dir> Auto-install for Codex forks with custom directory
35
35
  --help, -h Show this help message
36
36
 
37
+ You can combine multiple flags to set up multiple tools at once:
38
+ npx scpl-updated-mcp-server --setup --setup-codex --setup-codex=~/.code
39
+
37
40
  EXAMPLES:
41
+ # Claude Code only
38
42
  npx scpl-updated-mcp-server --setup
43
+
44
+ # Codex only
39
45
  npx scpl-updated-mcp-server --setup-codex
40
- npx scpl-updated-mcp-server --setup-codex=~/.code
41
- npx scpl-updated-mcp-server --setup-codex=/path/to/code_config
42
46
 
43
- For Codex forks like just-every/code that use CODE_HOME or CODEX_HOME:
47
+ # Custom Codex directory (just-every/code, etc.)
44
48
  npx scpl-updated-mcp-server --setup-codex=$CODE_HOME
45
49
 
50
+ # All at once: Claude + Codex + custom fork
51
+ npx scpl-updated-mcp-server --setup --setup-codex --setup-codex=~/.code
52
+
46
53
  After setup, restart your AI coding tool and ask:
47
54
  "Create a shortcut that starts a timer and plays a sound"
48
55
  `);
@@ -50,23 +57,126 @@ After setup, restart your AI coding tool and ask:
50
57
  }
51
58
 
52
59
  // ============================================================================
53
- // CODEX SETUP: Run with --setup-codex or --setup-codex=<dir>
60
+ // SETUP FUNCTIONS
54
61
  // ============================================================================
55
- const codexArg = process.argv.find(arg => arg.startsWith("--setup-codex"));
56
- if (codexArg) {
57
- // Check for custom directory: --setup-codex=/path/to/dir or --setup-codex=~/custom
58
- let codexDir = join(homedir(), ".codex"); // default
59
62
 
60
- if (codexArg.includes("=")) {
61
- let customDir = codexArg.split("=")[1];
62
- // Expand ~ to home directory
63
- if (customDir.startsWith("~")) {
64
- customDir = customDir.replace("~", homedir());
63
+ function setupClaudeCode() {
64
+ console.log("═══════════════════════════════════════════════════════════════");
65
+ console.log("🚀 Setting up ScPL Shortcuts for Claude Code...");
66
+ console.log("═══════════════════════════════════════════════════════════════\n");
67
+
68
+ const claudeJsonPath = join(homedir(), ".claude.json");
69
+ const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
70
+ const installedPluginsPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
71
+
72
+ // Step 1: Add MCP server to ~/.claude.json
73
+ console.log("📝 Step 1: Adding MCP server to ~/.claude.json...");
74
+ try {
75
+ let claudeConfig = {};
76
+ if (existsSync(claudeJsonPath)) {
77
+ claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
65
78
  }
66
- codexDir = customDir;
79
+
80
+ if (!claudeConfig.mcpServers) {
81
+ claudeConfig.mcpServers = {};
82
+ }
83
+
84
+ if (claudeConfig.mcpServers["scpl-shortcuts"]) {
85
+ console.log(" ⏭️ Already configured, skipping...\n");
86
+ } else {
87
+ claudeConfig.mcpServers["scpl-shortcuts"] = {
88
+ type: "stdio",
89
+ command: "npx",
90
+ args: ["-y", "scpl-updated-mcp-server"]
91
+ };
92
+ writeFileSync(claudeJsonPath, JSON.stringify(claudeConfig, null, 2));
93
+ console.log(" ✅ MCP server added!\n");
94
+ }
95
+ } catch (error) {
96
+ console.error(" ❌ Failed:", error.message, "\n");
67
97
  }
68
98
 
69
- console.log(`🚀 Setting up ScPL Shortcuts for Codex at ${codexDir}...\n`);
99
+ // Step 2: Create plugin directory and files
100
+ console.log("📁 Step 2: Installing plugin files...");
101
+ try {
102
+ mkdirSync(join(pluginsDir, "skills"), { recursive: true });
103
+
104
+ const pluginJson = {
105
+ name: "scpl-shortcuts",
106
+ version: "1.0.0",
107
+ description: "Create macOS Shortcuts using natural language and ScPL",
108
+ skills: [
109
+ {
110
+ name: "create-shortcut",
111
+ description: "Create a macOS Shortcut using natural language.",
112
+ path: "skills/create-shortcut.md"
113
+ }
114
+ ]
115
+ };
116
+ writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
117
+
118
+ const skillContent = `---
119
+ description: Create macOS Shortcuts using natural language.
120
+ tags: [shortcuts, automation, macos, scpl]
121
+ ---
122
+
123
+ # Create Shortcut Skill
124
+
125
+ You have access to the ScPL MCP server with 493 actions.
126
+
127
+ ## Tools: create_shortcut, validate_scpl, list_actions
128
+
129
+ ## ScPL Syntax
130
+ \`\`\`scpl
131
+ Text "Hello"
132
+ AskLLM model="Apple Intelligence" prompt="Make it fun"
133
+ ShowResult
134
+ \`\`\`
135
+
136
+ ## Categories
137
+ AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
138
+ `;
139
+ writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
140
+ console.log(" ✅ Plugin files created!\n");
141
+ } catch (error) {
142
+ console.error(" ❌ Failed:", error.message, "\n");
143
+ }
144
+
145
+ // Step 3: Register plugin
146
+ console.log("📋 Step 3: Registering plugin...");
147
+ try {
148
+ let installedPlugins = { version: 2, plugins: {} };
149
+ if (existsSync(installedPluginsPath)) {
150
+ installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
151
+ }
152
+
153
+ if (installedPlugins.plugins["scpl-shortcuts@local"]) {
154
+ console.log(" ⏭️ Already registered, skipping...\n");
155
+ } else {
156
+ installedPlugins.plugins["scpl-shortcuts@local"] = [
157
+ {
158
+ scope: "user",
159
+ installPath: pluginsDir,
160
+ version: "1.0.0",
161
+ installedAt: new Date().toISOString(),
162
+ lastUpdated: new Date().toISOString(),
163
+ isLocal: true
164
+ }
165
+ ];
166
+ writeFileSync(installedPluginsPath, JSON.stringify(installedPlugins, null, 2));
167
+ console.log(" ✅ Plugin registered!\n");
168
+ }
169
+ } catch (error) {
170
+ console.error(" ❌ Failed:", error.message, "\n");
171
+ }
172
+
173
+ console.log("✅ Claude Code setup complete!\n");
174
+ }
175
+
176
+ function setupCodex(codexDir) {
177
+ console.log("═══════════════════════════════════════════════════════════════");
178
+ console.log(`🚀 Setting up ScPL Shortcuts for Codex at ${codexDir}...`);
179
+ console.log("═══════════════════════════════════════════════════════════════\n");
70
180
 
71
181
  const codexConfigPath = join(codexDir, "config.toml");
72
182
  const skillDir = join(codexDir, "skills", "scpl-shortcuts");
@@ -79,7 +189,6 @@ if (codexArg) {
79
189
  config = readFileSync(codexConfigPath, "utf-8");
80
190
  }
81
191
 
82
- // Check if already configured
83
192
  if (config.includes('[mcp_servers."scpl-shortcuts"]') || config.includes('[mcp_servers.scpl-shortcuts]')) {
84
193
  console.log(" ⏭️ Already configured, skipping...\n");
85
194
  } else {
@@ -93,14 +202,7 @@ startup_timeout_sec = 60.0
93
202
  console.log(" ✅ MCP server added!\n");
94
203
  }
95
204
  } catch (error) {
96
- console.error(" ❌ Failed to update config:", error.message);
97
- console.log(" Add this to ~/.codex/config.toml manually:");
98
- console.log(`
99
- [mcp_servers.scpl-shortcuts]
100
- command = "npx"
101
- args = ["-y", "scpl-updated-mcp-server"]
102
- startup_timeout_sec = 60.0
103
- `);
205
+ console.error(" ❌ Failed:", error.message, "\n");
104
206
  }
105
207
 
106
208
  // Step 2: Install skill
@@ -110,243 +212,80 @@ startup_timeout_sec = 60.0
110
212
 
111
213
  const skillContent = `---
112
214
  name: scpl-shortcuts
113
- description: Create macOS Shortcuts using natural language. Use when users want to create, generate, or build Apple Shortcuts. Converts requests to ScPL code and generates .shortcut files.
215
+ description: Create macOS Shortcuts using natural language.
114
216
  metadata:
115
217
  short-description: Create macOS Shortcuts with AI
116
218
  ---
117
219
 
118
220
  # ScPL Shortcuts Skill
119
221
 
120
- Create macOS Shortcuts using natural language with 493 available actions.
121
-
122
- ## MCP Tools Available
123
-
124
- You have access to the \`scpl-shortcuts\` MCP server with these tools:
125
-
126
- | Tool | Description |
127
- |------|-------------|
128
- | \`create_shortcut\` | Generate a .shortcut file from ScPL code |
129
- | \`validate_scpl\` | Check if ScPL code is valid before creating |
130
- | \`list_actions\` | Search available actions by category or keyword |
222
+ 493 actions available. Tools: create_shortcut, validate_scpl, list_actions
131
223
 
132
224
  ## ScPL Syntax
133
-
134
- ScPL is line-based. Each line is an action. Parameters use \`key=value\` or \`key="value"\`.
135
-
136
225
  \`\`\`scpl
137
- # Comments start with #
138
- Text "Hello World"
226
+ Text "Hello"
227
+ AskLLM model="Apple Intelligence" prompt="Make it fun"
139
228
  ShowResult
140
-
141
- # Variables
142
- Text "some value"
143
- SetVariable v:myVar
144
- ShowResult v:myVar
145
-
146
- # AI actions
147
- AskLLM model="Apple Intelligence" prompt="Summarize this"
148
- AskChatGPT prompt="Explain this"
149
229
  \`\`\`
150
230
 
151
- ## Popular Actions by Category
152
-
153
- **AI**: AskLLM, AskChatGPT, AskClaude
154
- **Clock**: StartStopwatch, StopStopwatch, CreateAlarm
155
- **Voice Memos**: CreateRecording, PlayRecording
156
- **System**: SetDarkMode, TakeScreenshot, LockScreen
157
- **Files**: GetFile, SaveFile, RenameFile, RevealInFinder
158
- **Scripting**: RunShellScript, RunAppleScript, RunJavaScriptForAutomation
159
- **Clipboard**: GetClipboard, SetClipboard
231
+ ## Categories
232
+ AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
160
233
 
161
234
  ## Workflow
162
-
163
- 1. User describes what shortcut they want
164
- 2. Use \`list_actions\` if you need to find specific actions
165
- 3. Write ScPL code for the shortcut
166
- 4. Use \`validate_scpl\` to check syntax
167
- 5. Use \`create_shortcut\` to generate the .shortcut file
168
- 6. Tell user to install via Shortcut Source Helper from RoutineHub
169
-
170
- ## Example: Timer with Notification
171
-
172
- \`\`\`scpl
173
- # Start a 25-minute Pomodoro timer
174
- StartTimer minutes=25
175
- ShowAlert title="Timer Started" message="Focus for 25 minutes!"
176
- \`\`\`
177
-
178
- ## Example: Clipboard AI Enhancement
179
-
180
- \`\`\`scpl
181
- GetClipboard
182
- SetVariable v:text
183
- AskChatGPT prompt="Improve this text: \\(v:text)"
184
- SetClipboard
185
- ShowAlert title="Done" message="Improved text copied!"
186
- \`\`\`
235
+ 1. Write ScPL code
236
+ 2. validate_scpl to check
237
+ 3. create_shortcut to generate .shortcut file
187
238
  `;
188
239
  writeFileSync(join(skillDir, "SKILL.md"), skillContent);
189
240
  console.log(" ✅ Skill installed!\n");
190
241
  } catch (error) {
191
- console.error(" ❌ Failed to install skill:", error.message, "\n");
242
+ console.error(" ❌ Failed:", error.message, "\n");
192
243
  }
193
244
 
194
- console.log("🎉 Setup complete! Restart Codex to use the shortcuts tools.\n");
195
- console.log("Usage: Just ask Codex to create a shortcut!");
196
- console.log(' Example: "Create a shortcut that starts a timer and plays a sound"\n');
197
- process.exit(0);
245
+ console.log(`✅ Codex setup complete for ${codexDir}!\n`);
198
246
  }
199
247
 
200
248
  // ============================================================================
201
- // CLAUDE CODE SETUP: Run with --setup to install everything automatically
249
+ // PROCESS SETUP FLAGS
202
250
  // ============================================================================
203
- if (process.argv.includes("--setup")) {
204
- console.log("🚀 Setting up ScPL Shortcuts for Claude Code...\n");
205
-
206
- const claudeJsonPath = join(homedir(), ".claude.json");
207
- const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
208
- const installedPluginsPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
209
-
210
- // Step 1: Add MCP server to ~/.claude.json
211
- console.log("📝 Step 1: Adding MCP server to ~/.claude.json...");
212
- try {
213
- let claudeConfig = {};
214
- if (existsSync(claudeJsonPath)) {
215
- claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
216
- }
217
251
 
218
- if (!claudeConfig.mcpServers) {
219
- claudeConfig.mcpServers = {};
220
- }
221
-
222
- claudeConfig.mcpServers["scpl-shortcuts"] = {
223
- type: "stdio",
224
- command: "npx",
225
- args: ["-y", "scpl-updated-mcp-server"]
226
- };
227
-
228
- writeFileSync(claudeJsonPath, JSON.stringify(claudeConfig, null, 2));
229
- console.log(" ✅ MCP server added!\n");
230
- } catch (error) {
231
- console.error(" ❌ Failed to update ~/.claude.json:", error.message);
232
- console.log(" You can manually add this to ~/.claude.json under mcpServers:");
233
- console.log(` "scpl-shortcuts": { "type": "stdio", "command": "npx", "args": ["-y", "scpl-updated-mcp-server"] }\n`);
234
- }
235
-
236
- // Step 2: Create plugin directory and files
237
- console.log("📁 Step 2: Installing plugin files...");
238
- try {
239
- mkdirSync(join(pluginsDir, "skills"), { recursive: true });
252
+ let didSetup = false;
240
253
 
241
- // Write plugin.json
242
- const pluginJson = {
243
- name: "scpl-shortcuts",
244
- version: "1.0.0",
245
- description: "Create macOS Shortcuts using natural language and ScPL",
246
- skills: [
247
- {
248
- name: "create-shortcut",
249
- description: "Create a macOS Shortcut using natural language. Guides you through the process and generates a .shortcut file.",
250
- path: "skills/create-shortcut.md"
251
- }
252
- ]
253
- };
254
- writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
255
-
256
- // Write skill file
257
- const skillContent = `---
258
- description: Create macOS Shortcuts using natural language. Converts your request into ScPL code and generates a .shortcut file.
259
- tags: [shortcuts, automation, macos, scpl]
260
- ---
261
-
262
- # Create Shortcut Skill
263
-
264
- You have access to the ScPL MCP server with 493 actions for creating macOS Shortcuts.
265
-
266
- ## Available Tools
267
-
268
- 1. **create_shortcut** - Generate a .shortcut file from ScPL code
269
- 2. **validate_scpl** - Check if ScPL code is valid before creating
270
- 3. **list_actions** - Search available actions by category or keyword
271
-
272
- ## Popular Action Categories
273
-
274
- - **AI**: AskLLM (Apple Intelligence), AskChatGPT, AskClaude
275
- - **Clock**: StartStopwatch, CreateAlarm, GetCurrentTime
276
- - **Voice Memos**: CreateRecording, PlayRecording
277
- - **System**: SetDarkMode, TakeScreenshot, LockScreen
278
- - **Files**: GetFile, SaveFile, RenameFile, RevealInFinder
279
- - **Scripting**: RunShellScript, RunAppleScript
280
-
281
- ## ScPL Syntax Examples
282
-
283
- \`\`\`scpl
284
- # Simple notification
285
- ShowResult "Hello World!"
286
-
287
- # Use Apple Intelligence
288
- Text "Summarize this for me"
289
- AskLLM model="Apple Intelligence" prompt="Make it shorter"
290
- ShowResult
291
-
292
- # Shell script
293
- RunShellScript shell="/bin/zsh" script="echo Hello"
294
- ShowResult
295
-
296
- # Variables
297
- Text "Hello"
298
- SetVariable v:greeting
299
- ShowResult v:greeting
300
- \`\`\`
301
-
302
- ## Workflow
254
+ // Claude Code setup
255
+ if (process.argv.includes("--setup")) {
256
+ setupClaudeCode();
257
+ didSetup = true;
258
+ }
303
259
 
304
- 1. User describes what they want
305
- 2. Use \`list_actions\` if you need to find specific actions
306
- 3. Write ScPL code for the shortcut
307
- 4. Use \`validate_scpl\` to check syntax
308
- 5. Use \`create_shortcut\` to generate the .shortcut file
309
- 6. Tell user to drag the file onto Shortcut Source Helper to install
310
- `;
311
- writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
312
- console.log(" ✅ Plugin files created!\n");
313
- } catch (error) {
314
- console.error(" ❌ Failed to create plugin files:", error.message, "\n");
315
- }
260
+ // Codex setups (can have multiple --setup-codex and --setup-codex=<dir>)
261
+ const codexArgs = process.argv.filter(arg => arg.startsWith("--setup-codex"));
262
+ for (const codexArg of codexArgs) {
263
+ let codexDir = join(homedir(), ".codex"); // default
316
264
 
317
- // Step 3: Register plugin in installed_plugins.json
318
- console.log("📋 Step 3: Registering plugin...");
319
- try {
320
- let installedPlugins = { version: 2, plugins: {} };
321
- if (existsSync(installedPluginsPath)) {
322
- installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
265
+ if (codexArg.includes("=")) {
266
+ let customDir = codexArg.split("=")[1];
267
+ if (customDir.startsWith("~")) {
268
+ customDir = customDir.replace("~", homedir());
323
269
  }
324
-
325
- installedPlugins.plugins["scpl-shortcuts@local"] = [
326
- {
327
- scope: "user",
328
- installPath: pluginsDir,
329
- version: "1.0.0",
330
- installedAt: new Date().toISOString(),
331
- lastUpdated: new Date().toISOString(),
332
- isLocal: true
333
- }
334
- ];
335
-
336
- writeFileSync(installedPluginsPath, JSON.stringify(installedPlugins, null, 2));
337
- console.log(" ✅ Plugin registered!\n");
338
- } catch (error) {
339
- console.error(" ❌ Failed to register plugin:", error.message, "\n");
270
+ codexDir = customDir;
340
271
  }
341
272
 
342
- console.log("🎉 Setup complete! Restart Claude Code to use the shortcuts tools.\n");
343
- console.log("Usage: Just ask Claude to create a shortcut!");
344
- console.log(' Example: "Create a shortcut that starts a timer and plays a sound"\n');
273
+ setupCodex(codexDir);
274
+ didSetup = true;
275
+ }
276
+
277
+ // Exit after setup(s)
278
+ if (didSetup) {
279
+ console.log("═══════════════════════════════════════════════════════════════");
280
+ console.log("🎉 All setups complete! Restart your AI tool(s) to use shortcuts.");
281
+ console.log("═══════════════════════════════════════════════════════════════");
282
+ console.log('\nUsage: Just ask to create a shortcut!');
283
+ console.log(' Example: "Create a shortcut that starts a timer"\n');
345
284
  process.exit(0);
346
285
  }
347
286
 
348
287
  // ============================================================================
349
- // MCP SERVER
288
+ // MCP SERVER (runs if no setup flags)
350
289
  // ============================================================================
351
290
 
352
291
  const server = new Server(
@@ -430,24 +369,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
430
369
  if (name === "create_shortcut") {
431
370
  const { scpl_code, output_name, output_dir } = args;
432
371
 
433
- // Convert ScPL to shortcut
434
372
  const shortcutBuffer = convert(scpl_code, {
435
373
  makePlist: true,
436
374
  makeShortcut: true,
437
375
  });
438
376
 
439
- // Determine output path (default to ~/Documents)
440
377
  const dir = output_dir || join(homedir(), "Documents");
441
378
  const outputPath = join(dir, `${output_name}.shortcut`);
442
379
 
443
- // Write the file
444
380
  writeFileSync(outputPath, shortcutBuffer);
445
381
 
446
382
  return {
447
383
  content: [
448
384
  {
449
385
  type: "text",
450
- text: `✅ Shortcut created successfully!\n\nPath: ${outputPath}\n\n📝 To install:\n1. Download "Shortcut Source Helper" from RoutineHub\n2. Drag ${output_name}.shortcut onto it\n3. Follow the prompts to sign and import\n\nThe shortcut will be added to your Shortcuts app!`,
386
+ text: `✅ Shortcut created!\n\nPath: ${outputPath}\n\nTo install: Drag onto Shortcut Source Helper from RoutineHub`,
451
387
  },
452
388
  ],
453
389
  };
@@ -457,69 +393,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
457
393
  const { scpl_code } = args;
458
394
 
459
395
  try {
460
- convert(scpl_code, {
461
- makePlist: false,
462
- makeShortcut: false,
463
- });
464
-
465
- return {
466
- content: [
467
- {
468
- type: "text",
469
- text: "✅ ScPL code is valid!",
470
- },
471
- ],
472
- };
396
+ convert(scpl_code, { makePlist: false, makeShortcut: false });
397
+ return { content: [{ type: "text", text: "✅ ScPL code is valid!" }] };
473
398
  } catch (error) {
474
- return {
475
- content: [
476
- {
477
- type: "text",
478
- text: `❌ ScPL validation failed:\n\n${error.message}`,
479
- },
480
- ],
481
- isError: true,
482
- };
399
+ return { content: [{ type: "text", text: `❌ Invalid: ${error.message}` }], isError: true };
483
400
  }
484
401
  }
485
402
 
486
403
  if (name === "list_actions") {
487
404
  const { category, search } = args || {};
488
405
 
489
- // Embedded action list (top actions for quick reference)
490
406
  const topActions = {
491
- // AI
492
407
  "is.workflow.actions.askllm": { Name: "Ask LLM", Category: "AI" },
493
408
  "is.workflow.actions.askchatgpt": { Name: "Ask ChatGPT", Category: "AI" },
494
409
  "com.anthropic.claudeforipad.AskClaudeIntentExtension": { Name: "Ask Claude", Category: "AI" },
495
- // Clock
496
410
  "com.apple.clock.StartStopwatchIntent": { Name: "Start Stopwatch", Category: "Clock" },
497
411
  "com.apple.clock.StopStopwatchIntent": { Name: "Stop Stopwatch", Category: "Clock" },
498
412
  "com.apple.clock.CreateAlarmIntent": { Name: "Create Alarm", Category: "Clock" },
499
- // Voice Memos
500
413
  "com.apple.VoiceMemos.CreateRecordingIntent": { Name: "Create Recording", Category: "Voice Memos" },
501
414
  "com.apple.VoiceMemos.PlayRecordingIntent": { Name: "Play Recording", Category: "Voice Memos" },
502
- // System
503
415
  "is.workflow.actions.appearance": { Name: "Set Dark/Light Mode", Category: "System" },
504
416
  "is.workflow.actions.takescreenshot": { Name: "Take Screenshot", Category: "System" },
505
417
  "is.workflow.actions.lockscreen": { Name: "Lock Screen", Category: "System" },
506
- // Scripting
507
418
  "is.workflow.actions.runshellscript": { Name: "Run Shell Script", Category: "Scripting" },
508
419
  "is.workflow.actions.runapplescript": { Name: "Run AppleScript", Category: "Scripting" },
509
420
  "is.workflow.actions.runjavascriptforautomation": { Name: "Run JavaScript", Category: "Scripting" },
510
- // Files
511
421
  "is.workflow.actions.file.getfile": { Name: "Get File", Category: "Files" },
512
422
  "is.workflow.actions.file.savefile": { Name: "Save File", Category: "Files" },
513
- "is.workflow.actions.file.renamefile": { Name: "Rename File", Category: "Files" },
514
- "is.workflow.actions.file.revealfile": { Name: "Reveal in Finder", Category: "Files" },
515
- // Text
516
- "is.workflow.actions.gettext": { Name: "Get Text", Category: "Text" },
517
423
  "is.workflow.actions.showresult": { Name: "Show Result", Category: "Text" },
518
424
  "is.workflow.actions.alert": { Name: "Show Alert", Category: "Text" },
519
- // Variables
520
425
  "is.workflow.actions.setvariable": { Name: "Set Variable", Category: "Variables" },
521
- "is.workflow.actions.getvariable": { Name: "Get Variable", Category: "Variables" },
522
- // Clipboard
523
426
  "is.workflow.actions.getclipboard": { Name: "Get Clipboard", Category: "Clipboard" },
524
427
  "is.workflow.actions.setclipboard": { Name: "Set Clipboard", Category: "Clipboard" },
525
428
  };
@@ -527,108 +430,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
527
430
  let filtered = Object.entries(topActions);
528
431
 
529
432
  if (category) {
530
- filtered = filtered.filter(
531
- ([_, action]) => action.Category?.toLowerCase() === category.toLowerCase()
532
- );
433
+ filtered = filtered.filter(([_, a]) => a.Category?.toLowerCase() === category.toLowerCase());
533
434
  }
534
-
535
435
  if (search) {
536
- const searchLower = search.toLowerCase();
537
- filtered = filtered.filter(
538
- ([id, action]) =>
539
- id.toLowerCase().includes(searchLower) ||
540
- action.Name?.toLowerCase().includes(searchLower) ||
541
- action.Category?.toLowerCase().includes(searchLower)
436
+ const s = search.toLowerCase();
437
+ filtered = filtered.filter(([id, a]) =>
438
+ id.toLowerCase().includes(s) || a.Name?.toLowerCase().includes(s)
542
439
  );
543
440
  }
544
441
 
545
- const results = filtered
546
- .map(([id, action]) => `• **${action.Name}** - \`${id}\` (${action.Category})`)
547
- .join("\n");
548
-
549
- return {
550
- content: [
551
- {
552
- type: "text",
553
- text: `Found ${filtered.length} actions:\n\n${results}\n\n💡 This is a subset of 493 total actions. For the full list, see: https://github.com/cavingraves/scpl-macos-updated`,
554
- },
555
- ],
556
- };
442
+ const results = filtered.map(([id, a]) => `• **${a.Name}** - \`${id}\``).join("\n");
443
+ return { content: [{ type: "text", text: `${filtered.length} actions:\n\n${results}\n\n(493 total available)` }] };
557
444
  }
558
445
 
559
446
  throw new Error(`Unknown tool: ${name}`);
560
447
  } catch (error) {
561
- return {
562
- content: [
563
- {
564
- type: "text",
565
- text: `Error: ${error.message}`,
566
- },
567
- ],
568
- isError: true,
569
- };
448
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
570
449
  }
571
450
  });
572
451
 
573
- // Resource handlers
574
452
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
575
- return {
576
- resources: [
577
- {
578
- uri: "scpl://examples",
579
- name: "ScPL Examples",
580
- description: "Example shortcuts written in ScPL",
581
- mimeType: "text/markdown",
582
- },
583
- ],
584
- };
453
+ return { resources: [{ uri: "scpl://examples", name: "ScPL Examples", mimeType: "text/markdown" }] };
585
454
  });
586
455
 
587
456
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
588
- const { uri } = request.params;
589
-
590
- if (uri === "scpl://examples") {
591
- const examples = `# ScPL Examples
592
-
593
- ## Apple Intelligence
594
- \`\`\`scpl
595
- Text "Summarize this document"
596
- AskLLM model="Apple Intelligence" prompt="Make it concise"
597
- ShowResult
598
- \`\`\`
599
-
600
- ## Timer with Sound
601
- \`\`\`scpl
602
- # Start a 5-minute timer
603
- StartTimer minutes=5
604
- ShowAlert title="Timer Started" message="5 minutes"
605
- \`\`\`
606
-
607
- ## Shell Script
608
- \`\`\`scpl
609
- RunShellScript shell="/bin/zsh" script="echo Hello World"
610
- ShowResult
611
- \`\`\`
612
-
613
- ## Clipboard Workflow
614
- \`\`\`scpl
615
- GetClipboard
616
- SetVariable v:text
617
- AskChatGPT prompt="Improve this: \\(v:text)"
618
- SetClipboard
619
- ShowAlert title="Done" message="Improved text copied!"
620
- \`\`\`
621
- `;
622
-
623
- return {
624
- contents: [{ uri, mimeType: "text/markdown", text: examples }],
625
- };
457
+ if (request.params.uri === "scpl://examples") {
458
+ return { contents: [{ uri: "scpl://examples", mimeType: "text/markdown", text: "# Examples\n\n```scpl\nShowResult \"Hello!\"\n```" }] };
626
459
  }
627
-
628
- throw new Error(`Unknown resource: ${uri}`);
460
+ throw new Error("Unknown resource");
629
461
  });
630
462
 
631
- // Start server
632
463
  async function main() {
633
464
  const transport = new StdioServerTransport();
634
465
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scpl-updated-mcp-server",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "AI-powered Apple Shortcuts creation with Claude Code! Generate macOS shortcuts using natural language. 493 actions available. MCP server for text-based shortcut programming. Vibe code your automation workflows.",
5
5
  "type": "module",
6
6
  "main": "index.js",