Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,41 @@ swift package update

## Architecture Overview

This project implements an MCP server that provides GUI automation capabilities for macOS through 4 tools:
This project implements an MCP server that provides GUI automation capabilities for macOS through these tools:
- `moveMouse`: Move cursor to x,y coordinates
- `mouseClick`: Perform mouse clicks (left/right)
- `scroll`: Scroll in any direction
- `sendKeys`: Send keyboard shortcuts
- `getScreenSize`: Get the display dimensions
- `getPixelColor`: Get color of a pixel at x,y
- `captureScreen`: Capture full screen as base64 PNG
- `captureRegion`: Capture a region as base64 PNG
- `saveScreenshot`: Save screenshot to file

### Key Components

- **main.swift**: MCP server initialization and tool registration. All tool implementations are in this file.
- **Server+Extension.swift**: Extends MCP Server with `waitForDisconnection()` to keep the server running.
- **main.swift**: MCP server initialization and startup
- **Server+Extension.swift**: Extends MCP Server with `waitForDisconnection()` to keep the server running
- **ToolRegistry.swift**: Manages tool registration and execution
- **Tools/**:
- **Mouse/**: Mouse control tools (moveMouse, mouseClick)
- **Screen/**: Screen capture and scroll tools
- **Keyboard/**: Keyboard input tools (sendKeys)

### Dependencies

- **mcp-swift-sdk**: MCP protocol implementation
- **SwiftAutoGUI** (v0.3.2): macOS automation library
- Repository: https://github.com/modelcontextprotocol/swift-sdk
- **SwiftAutoGUI** (v0.10.0+): macOS automation library
- Repository: https://github.com/NakaokaRei/SwiftAutoGUI
- Documentation: https://nakaokarei.github.io/SwiftAutoGUI/documentation/swiftautogui/

## Important Notes

- **Platform Requirements**: macOS 15.0+, Swift 6.0+
- **Security**: Requires full accessibility permissions in System Preferences
- **Communication**: Uses stdio transport (stdin/stdout)
- **No test suite**: Currently no tests are implemented
- **Test suite**: Unit tests for tools are in Tests/swift-mcp-guiTests/

## Development Workflow

Expand Down
18 changes: 9 additions & 9 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.9.0"),
.package(url: "https://github.com/NakaokaRei/SwiftAutoGUI.git", from: "0.5.0")
.package(url: "https://github.com/NakaokaRei/SwiftAutoGUI.git", from: "0.10.0")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ The server provides the following tools for controlling macOS:
- File format is determined by the filename extension (.jpg, .jpeg, .png)
- Quality parameter only affects JPEG files

### 10. Execute AppleScript
- Tool name: `executeAppleScript`
- Input:
- `script`: string (AppleScript code to execute)
- Executes AppleScript code directly and returns the result
- Returns "AppleScript Result: <result>" if the script returns a value
- Returns "AppleScript executed successfully (no result returned)" if the script completes without returning a value

### 11. Execute AppleScript File
- Tool name: `executeAppleScriptFile`
- Input:
- `path`: string (path to the AppleScript file)
- Executes an AppleScript from a file and returns the result
- Returns "AppleScript Result: <result>" if the script returns a value
- Returns "AppleScript file executed successfully (no result returned): <path>" if the script completes without returning a value

## Security Considerations

This server requires full accessibility permissions in System Preferences to control your mouse and keyboard. Be careful when running it and only connect trusted MCP clients.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import MCP
import SwiftAutoGUI

struct ExecuteAppleScriptFileTool {
static func register(in registry: ToolRegistry) {
let tool = Tool(
name: "executeAppleScriptFile",
description: "Execute AppleScript from a file",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
"path": .object(["type": .string("string"), "description": .string("Path to the AppleScript file")])
]),
"required": .array([.string("path")])
])
)

registry.registerTool(definition: tool) { arguments in
let parser = ParameterParser(arguments: arguments)

do {
let path = try parser.parseString("path")

let result = try SwiftAutoGUI.executeAppleScriptFile(path)

if let resultString = result {
return .init(content: [.text("AppleScript Result: \(resultString)")], isError: false)
} else {
return .init(content: [.text("AppleScript file executed successfully (no result returned): \(path)")], isError: false)
}
} catch {
return .init(content: [.text("Failed to execute AppleScript file: \(error.localizedDescription)")], isError: true)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import MCP
import SwiftAutoGUI

struct ExecuteAppleScriptTool {
static func register(in registry: ToolRegistry) {
let tool = Tool(
name: "executeAppleScript",
description: "Execute AppleScript code directly",
inputSchema: .object([
"type": .string("object"),
"properties": .object([
"script": .object(["type": .string("string"), "description": .string("AppleScript code to execute")])
]),
"required": .array([.string("script")])
])
)

registry.registerTool(definition: tool) { arguments in
let parser = ParameterParser(arguments: arguments)

do {
let script = try parser.parseString("script")

let result = try SwiftAutoGUI.executeAppleScript(script)

if let resultString = result {
return .init(content: [.text("AppleScript Result: \(resultString)")], isError: false)
} else {
return .init(content: [.text("AppleScript executed successfully (no result returned)")], isError: false)
}
} catch {
return .init(content: [.text("Failed to execute AppleScript: \(error.localizedDescription)")], isError: true)
}
}
}
}
2 changes: 2 additions & 0 deletions Sources/swift-mcp-gui/Tools/ToolRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ class ToolRegistry {
CaptureScreenTool.register(in: self)
CaptureRegionTool.register(in: self)
SaveScreenshotTool.register(in: self)
ExecuteAppleScriptTool.register(in: self)
ExecuteAppleScriptFileTool.register(in: self)
}
}
Loading