scpl-updated-mcp-server 1.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.
Files changed (3) hide show
  1. package/README.md +324 -0
  2. package/index.js +342 -0
  3. package/package.json +26 -0
package/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # ScPL MCP Server
2
+
3
+ Model Context Protocol server for creating macOS Shortcuts using ScPL (Shortcuts Programming Language).
4
+
5
+ ## Features
6
+
7
+ - **Create Shortcuts**: Convert ScPL code to .shortcut files
8
+ - **Validate Syntax**: Check ScPL code without creating files
9
+ - **Discover Actions**: Browse 294 available actions with descriptions
10
+ - **Documentation**: Access action reference and examples
11
+
12
+ ## ⚠️ Shortcut Signing & Installation
13
+
14
+ Generated .shortcut files need to be signed before macOS will allow you to run them. You have two options:
15
+
16
+ ### Option 1: Shortcut Source Helper (Free - Recommended)
17
+
18
+ **Setup (one-time):**
19
+ 1. Install required shortcuts from RoutineHub:
20
+ - [Shortcut Source Helper](https://routinehub.co/shortcut/10060/)
21
+ - [Shortcut Source Tool](https://routinehub.co/shortcut/5256/)
22
+ - [Tinycut Builder](https://routinehub.co/shortcut/5217/)
23
+ 2. Add **Shortcut Source Helper** to your Dock for easy access
24
+
25
+ **To install a generated shortcut:**
26
+ 1. Drag and drop the `.shortcut` file onto Shortcut Source Helper in your Dock
27
+ 2. Follow the prompts to sign and import
28
+ 3. The shortcut will be added to your Shortcuts app and ready to use!
29
+
30
+ ### Option 2: Apple Developer Account
31
+
32
+ If you have an Apple Developer account ($99/year), you can sign shortcuts with your developer certificate for distribution.
33
+
34
+ **Disclaimer**: We are not associated with Shortcut Source Tool/Helper or their creators. Use third-party tools at your own risk. Always review shortcuts before running them.
35
+
36
+ ## Installation
37
+
38
+ ### Step 1: Install the Package
39
+
40
+ ```bash
41
+ npm install -g scpl-updated-mcp-server
42
+ ```
43
+
44
+ ### Step 2: Register with Your AI Assistant
45
+
46
+ Choose your platform below:
47
+
48
+ #### Claude Code
49
+
50
+ **Option 1: CLI command** (may not always work):
51
+
52
+ ```bash
53
+ claude mcp add scpl-shortcuts npx scpl-updated-mcp-server
54
+ ```
55
+
56
+ **Option 2: Manual config** (recommended):
57
+
58
+ Add this to the `mcpServers` section in `~/.claude.json`:
59
+
60
+ ```json
61
+ "scpl-shortcuts": {
62
+ "type": "stdio",
63
+ "command": "npx",
64
+ "args": [
65
+ "-y",
66
+ "scpl-updated-mcp-server"
67
+ ]
68
+ }
69
+ ```
70
+
71
+ Or for project-specific config, add to `.claude/mcp.json` in your project directory.
72
+
73
+ #### Claude Desktop
74
+
75
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "scpl-shortcuts": {
81
+ "command": "npx",
82
+ "args": ["scpl-updated-mcp-server"]
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ #### Codex / Code (and forks)
89
+
90
+ Add to `~/.code/config.toml` (or `~/.codex/config.toml`):
91
+
92
+ ```toml
93
+ [mcp_servers.scpl-shortcuts]
94
+ command = "npx"
95
+ args = ["scpl-updated-mcp-server"]
96
+ startup_timeout_sec = 60.0
97
+ tool_timeout_sec = 120
98
+ ```
99
+
100
+ **For local development:**
101
+
102
+ ```toml
103
+ [mcp_servers.scpl-shortcuts]
104
+ command = "node"
105
+ args = ["/path/to/scpl-updated/mcp-server/index.js"]
106
+ cwd = "/path/to/scpl-updated/mcp-server"
107
+ startup_timeout_sec = 60.0
108
+ tool_timeout_sec = 120
109
+ ```
110
+
111
+ ## Tools
112
+
113
+ ### `create_shortcut`
114
+
115
+ Create a macOS Shortcut from ScPL code.
116
+
117
+ **Parameters:**
118
+ - `scpl_code` (required): The ScPL code to convert
119
+ - `output_name` (required): Name for the .shortcut file
120
+ - `output_dir` (optional): Output directory (defaults to ~/Documents)
121
+
122
+ **Example:**
123
+ ```json
124
+ {
125
+ "scpl_code": "Text \"Hello World\"\nShowResult",
126
+ "output_name": "HelloWorld",
127
+ "output_dir": "~/Desktop"
128
+ }
129
+ ```
130
+
131
+ ### `validate_scpl`
132
+
133
+ Validate ScPL code syntax without creating a file.
134
+
135
+ **Parameters:**
136
+ - `scpl_code` (required): The ScPL code to validate
137
+
138
+ **Example:**
139
+ ```json
140
+ {
141
+ "scpl_code": "GetClipboard\nShowResult"
142
+ }
143
+ ```
144
+
145
+ ### `list_actions`
146
+
147
+ List available ScPL actions with descriptions.
148
+
149
+ **Parameters:**
150
+ - `category` (optional): Filter by category (e.g., "Scripting", "Files")
151
+ - `search` (optional): Search term to filter actions
152
+
153
+ **Example:**
154
+ ```json
155
+ {
156
+ "category": "Scripting",
157
+ "search": "shell"
158
+ }
159
+ ```
160
+
161
+ ## Resources
162
+
163
+ ### `scpl://actions/tahoe`
164
+
165
+ Documentation for 22 new macOS Tahoe actions.
166
+
167
+ ### `scpl://examples`
168
+
169
+ Example shortcuts demonstrating various ScPL features.
170
+
171
+ ## Usage with Claude Code
172
+
173
+ Once registered, Claude can create shortcuts for you:
174
+
175
+ ```
176
+ Claude, create a shortcut that:
177
+ 1. Gets text from clipboard
178
+ 2. Asks ChatGPT to improve it
179
+ 3. Copies the result back to clipboard
180
+ ```
181
+
182
+ Claude will:
183
+ 1. Write the ScPL code
184
+ 2. Validate the syntax
185
+ 3. Create the .shortcut file
186
+ 4. Provide installation instructions
187
+
188
+ ## Usage with Claude Skill
189
+
190
+ The included `/create-shortcut` skill provides a guided experience:
191
+
192
+ ```
193
+ /create-shortcut
194
+ ```
195
+
196
+ Then describe what you want your shortcut to do.
197
+
198
+ ## ScPL Syntax Quick Reference
199
+
200
+ ```scpl
201
+ # Comments
202
+ # Single-line comments start with #
203
+
204
+ # Text and Output
205
+ Text "Hello World"
206
+ ShowResult "My Result"
207
+ ShowAlert title="Title" message="Message"
208
+
209
+ # Variables
210
+ SetVariable v:myVar
211
+ GetVariable v:myVar
212
+
213
+ # Clipboard
214
+ GetClipboard
215
+ SetClipboard
216
+
217
+ # Apple Intelligence (Apple Silicon only)
218
+ AskLLM model="Apple Intelligence" prompt="Your prompt here"
219
+
220
+ # ChatGPT (requires app installed)
221
+ Text "Your question"
222
+ AskChatGPT
223
+
224
+ # Shell Scripts (Intel & Apple Silicon)
225
+ RunShellScript shell="/bin/zsh" script="echo 'Hello'"
226
+
227
+ # Files (Intel & Apple Silicon)
228
+ GetFile path="~/Desktop"
229
+ SaveFile path="~/Documents/file.txt"
230
+
231
+ # Conditionals
232
+ If condition="Equals" value="test"
233
+ ShowResult "Match!"
234
+ Otherwise
235
+ ShowResult "No match"
236
+ End If
237
+
238
+ # Menus
239
+ ChooseFromMenu items=["Option 1", "Option 2"]
240
+ Case "Option 1"
241
+ Text "You chose 1"
242
+ Case "Option 2"
243
+ Text "You chose 2"
244
+ End Menu
245
+
246
+ # Loops
247
+ RepeatWithEachItem
248
+ ShowResult
249
+ End Repeat
250
+ ```
251
+
252
+ ## Examples
253
+
254
+ ### Simple Notification
255
+
256
+ ```scpl
257
+ Text "Hello from ScPL!"
258
+ ShowResult
259
+ ```
260
+
261
+ ### AI Text Improver
262
+
263
+ ```scpl
264
+ GetClipboard
265
+ SetVariable v:originalText
266
+
267
+ AskLLM model="Apple Intelligence" prompt="Improve this text for clarity: \\(v:originalText)"
268
+ SetClipboard
269
+ ShowAlert title="Done" message="Improved text copied to clipboard"
270
+ ```
271
+
272
+ ### Shell Script Runner
273
+
274
+ ```scpl
275
+ RunShellScript shell="/bin/zsh" script="sw_vers"
276
+ ShowResult "macOS Version"
277
+ ```
278
+
279
+ ### File Counter
280
+
281
+ ```scpl
282
+ GetFile path="~/Desktop"
283
+ Count
284
+ ShowResult "Files on Desktop"
285
+ ```
286
+
287
+ ## Troubleshooting
288
+
289
+ ### "Command not found: scpl-updated-mcp-server"
290
+
291
+ Make sure you installed globally:
292
+ ```bash
293
+ npm install -g scpl-updated-mcp-server
294
+ ```
295
+
296
+ ### "Error: Cannot find module 'scpl-macos-updated'"
297
+
298
+ The MCP server depends on scpl-macos-updated. Ensure it's installed:
299
+ ```bash
300
+ npm list -g scpl-macos-updated
301
+ ```
302
+
303
+ ### "Permission denied"
304
+
305
+ Make the script executable:
306
+ ```bash
307
+ chmod +x index.js
308
+ ```
309
+
310
+ ### ScPL Validation Errors
311
+
312
+ Check the error message for line numbers and syntax issues. Common mistakes:
313
+ - Forgetting to close `If` with `End If`
314
+ - Forgetting to close `Menu` with `End Menu`
315
+ - Using wrong parameter names (use `list_actions` to check)
316
+ - Missing quotes around text values
317
+
318
+ ## Contributing
319
+
320
+ Found a bug or want to add features? See [CONTRIBUTING.md](../CONTRIBUTING.md)
321
+
322
+ ## License
323
+
324
+ MIT - Same as scpl-macos-updated
package/index.js ADDED
@@ -0,0 +1,342 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ ListResourcesRequestSchema,
9
+ ReadResourceRequestSchema,
10
+ } from "@modelcontextprotocol/sdk/types.js";
11
+ import { convert } from "scpl-macos-updated";
12
+ import { writeFileSync, readFileSync } from "fs";
13
+ import { join } from "path";
14
+ import { homedir } from "os";
15
+
16
+ const server = new Server(
17
+ {
18
+ name: "scpl-updated-mcp-server",
19
+ version: "1.0.0",
20
+ },
21
+ {
22
+ capabilities: {
23
+ tools: {},
24
+ resources: {},
25
+ },
26
+ }
27
+ );
28
+
29
+ // Tool handlers
30
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
31
+ return {
32
+ tools: [
33
+ {
34
+ name: "create_shortcut",
35
+ description: "Create a macOS Shortcut from ScPL code. Returns the path to the generated .shortcut file.",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: {
39
+ scpl_code: {
40
+ type: "string",
41
+ description: "The ScPL code to convert to a shortcut",
42
+ },
43
+ output_name: {
44
+ type: "string",
45
+ description: "Name for the output .shortcut file (without extension)",
46
+ },
47
+ output_dir: {
48
+ type: "string",
49
+ description: "Optional output directory (defaults to ~/Downloads)",
50
+ },
51
+ },
52
+ required: ["scpl_code", "output_name"],
53
+ },
54
+ },
55
+ {
56
+ name: "validate_scpl",
57
+ description: "Validate ScPL code syntax without creating a file",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ scpl_code: {
62
+ type: "string",
63
+ description: "The ScPL code to validate",
64
+ },
65
+ },
66
+ required: ["scpl_code"],
67
+ },
68
+ },
69
+ {
70
+ name: "list_actions",
71
+ description: "List available ScPL actions with descriptions. Filter by category or search term.",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ category: {
76
+ type: "string",
77
+ description: "Optional category filter (e.g., 'Scripting', 'Files', 'AI')",
78
+ },
79
+ search: {
80
+ type: "string",
81
+ description: "Optional search term to filter actions",
82
+ },
83
+ },
84
+ },
85
+ },
86
+ ],
87
+ };
88
+ });
89
+
90
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
91
+ const { name, arguments: args } = request.params;
92
+
93
+ try {
94
+ if (name === "create_shortcut") {
95
+ const { scpl_code, output_name, output_dir } = args;
96
+
97
+ // Convert ScPL to shortcut
98
+ // Note: parse() returns a Buffer directly when makeShortcut: true
99
+ const shortcutBuffer = convert(scpl_code, {
100
+ makePlist: true,
101
+ makeShortcut: true,
102
+ });
103
+
104
+ // Determine output path (default to ~/Documents)
105
+ const dir = output_dir || join(homedir(), "Documents");
106
+ const outputPath = join(dir, `${output_name}.shortcut`);
107
+
108
+ // Write the file
109
+ writeFileSync(outputPath, shortcutBuffer);
110
+
111
+ return {
112
+ content: [
113
+ {
114
+ type: "text",
115
+ text: `✅ Shortcut created successfully!\n\nPath: ${outputPath}\n\n📝 To install and sign it:\n\n1. Install Shortcut Source Helper from RoutineHub (if you haven't already)\n - Also install: Shortcut Source Tool, Tinycut Builder\n2. Add Shortcut Source Helper to your Dock\n3. Drag and drop ${output_name}.shortcut onto it\n4. Follow the prompts to sign and import\n\nThe shortcut will be added to your Shortcuts app and ready to use!`,
116
+ },
117
+ ],
118
+ };
119
+ }
120
+
121
+ if (name === "validate_scpl") {
122
+ const { scpl_code } = args;
123
+
124
+ try {
125
+ // Just parse to validate, don't generate output
126
+ convert(scpl_code, {
127
+ makePlist: false,
128
+ makeShortcut: false,
129
+ });
130
+
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: "✅ ScPL code is valid!",
136
+ },
137
+ ],
138
+ };
139
+ } catch (error) {
140
+ return {
141
+ content: [
142
+ {
143
+ type: "text",
144
+ text: `❌ ScPL validation failed:\n\n${error.message}`,
145
+ },
146
+ ],
147
+ isError: true,
148
+ };
149
+ }
150
+ }
151
+
152
+ if (name === "list_actions") {
153
+ const { category, search } = args || {};
154
+
155
+ // Read the actions data
156
+ const actionsPath = join(
157
+ process.cwd(),
158
+ "..",
159
+ "src",
160
+ "Data",
161
+ "OutActions.json"
162
+ );
163
+ const actions = JSON.parse(readFileSync(actionsPath, "utf-8"));
164
+
165
+ let filtered = Object.entries(actions);
166
+
167
+ // Filter by category
168
+ if (category) {
169
+ filtered = filtered.filter(
170
+ ([_, action]) =>
171
+ action.Category?.toLowerCase() === category.toLowerCase()
172
+ );
173
+ }
174
+
175
+ // Filter by search term
176
+ if (search) {
177
+ const searchLower = search.toLowerCase();
178
+ filtered = filtered.filter(
179
+ ([id, action]) =>
180
+ id.toLowerCase().includes(searchLower) ||
181
+ action.Name?.toLowerCase().includes(searchLower) ||
182
+ action.Description?.DescriptionSummary?.toLowerCase().includes(
183
+ searchLower
184
+ )
185
+ );
186
+ }
187
+
188
+ // Format the results
189
+ const results = filtered
190
+ .slice(0, 50) // Limit to 50 results
191
+ .map(([id, action]) => {
192
+ return `• **${action.Name || id}**\n ID: \`${id}\`\n ${
193
+ action.Description?.DescriptionSummary || "No description"
194
+ }\n Category: ${action.Category || "Unknown"}`;
195
+ })
196
+ .join("\n\n");
197
+
198
+ const total = filtered.length;
199
+ const showing = Math.min(50, total);
200
+
201
+ return {
202
+ content: [
203
+ {
204
+ type: "text",
205
+ text: `Found ${total} action${
206
+ total !== 1 ? "s" : ""
207
+ } (showing ${showing}):\n\n${results}`,
208
+ },
209
+ ],
210
+ };
211
+ }
212
+
213
+ throw new Error(`Unknown tool: ${name}`);
214
+ } catch (error) {
215
+ return {
216
+ content: [
217
+ {
218
+ type: "text",
219
+ text: `Error: ${error.message}`,
220
+ },
221
+ ],
222
+ isError: true,
223
+ };
224
+ }
225
+ });
226
+
227
+ // Resource handlers (for documentation)
228
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
229
+ return {
230
+ resources: [
231
+ {
232
+ uri: "scpl://actions/all",
233
+ name: "All Available Actions",
234
+ description: "Complete list of all 294 ScPL actions",
235
+ mimeType: "text/markdown",
236
+ },
237
+ {
238
+ uri: "scpl://actions/tahoe",
239
+ name: "macOS Tahoe New Actions",
240
+ description: "22 new actions added for macOS Tahoe",
241
+ mimeType: "text/markdown",
242
+ },
243
+ {
244
+ uri: "scpl://examples",
245
+ name: "ScPL Examples",
246
+ description: "Example shortcuts written in ScPL",
247
+ mimeType: "text/markdown",
248
+ },
249
+ ],
250
+ };
251
+ });
252
+
253
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
254
+ const { uri } = request.params;
255
+
256
+ if (uri === "scpl://actions/tahoe") {
257
+ const content = readFileSync(
258
+ join(process.cwd(), "..", "MACOS_TAHOE_UPDATES.md"),
259
+ "utf-8"
260
+ );
261
+ return {
262
+ contents: [
263
+ {
264
+ uri,
265
+ mimeType: "text/markdown",
266
+ text: content,
267
+ },
268
+ ],
269
+ };
270
+ }
271
+
272
+ if (uri === "scpl://examples") {
273
+ const examples = `# ScPL Examples
274
+
275
+ ## Apple Intelligence Example
276
+ \`\`\`scpl
277
+ # Ask Apple Intelligence to summarize text
278
+ Text "The quick brown fox jumps over the lazy dog. This is a sample text."
279
+ AskLLM model="Apple Intelligence" prompt="Summarize this in 5 words"
280
+ ShowResult
281
+ \`\`\`
282
+
283
+ ## Shell Script Example
284
+ \`\`\`scpl
285
+ # Run a shell script and show the result
286
+ RunShellScript shell="/bin/zsh" script="sw_vers"
287
+ ShowResult "macOS Version"
288
+ \`\`\`
289
+
290
+ ## File Operations Example
291
+ \`\`\`scpl
292
+ # Get files from Desktop and show count
293
+ GetFile path="~/Desktop" errorIfNotFound=false
294
+ Count
295
+ ShowResult "Files on Desktop"
296
+ \`\`\`
297
+
298
+ ## ChatGPT Integration Example
299
+ \`\`\`scpl
300
+ # Ask ChatGPT a question
301
+ Text "What is the meaning of life?"
302
+ AskChatGPT
303
+ ShowResult
304
+ \`\`\`
305
+
306
+ ## Combined Workflow Example
307
+ \`\`\`scpl
308
+ # Get clipboard, ask AI to improve it, copy back
309
+ GetClipboard
310
+ SetVariable v:originalText
311
+
312
+ AskLLM model="Apple Intelligence" prompt="Improve this text for clarity and grammar: \\(v:originalText)"
313
+ SetClipboard
314
+ ShowAlert title="Text Improved" message="The improved text has been copied to your clipboard"
315
+ \`\`\`
316
+ `;
317
+
318
+ return {
319
+ contents: [
320
+ {
321
+ uri,
322
+ mimeType: "text/markdown",
323
+ text: examples,
324
+ },
325
+ ],
326
+ };
327
+ }
328
+
329
+ throw new Error(`Unknown resource: ${uri}`);
330
+ });
331
+
332
+ // Start the server
333
+ async function main() {
334
+ const transport = new StdioServerTransport();
335
+ await server.connect(transport);
336
+ console.error("ScPL Updated MCP server running on stdio");
337
+ }
338
+
339
+ main().catch((error) => {
340
+ console.error("Server error:", error);
341
+ process.exit(1);
342
+ });
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "scpl-updated-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for creating macOS Shortcuts using ScPL (macOS Tahoe updated fork)",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "scpl-updated-mcp-server": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "shortcuts",
16
+ "scpl",
17
+ "macos",
18
+ "automation"
19
+ ],
20
+ "author": "Cavin Graves",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^0.5.0",
24
+ "scpl-macos-updated": "^2.0.0"
25
+ }
26
+ }