A Model Context Protocol (MCP) server for controlling BetterTouchTool on macOS
The server provides 28 tools with consistent naming conventions (btt_* prefix with action verbs), but suffers from moderate-to-significant gaps in schema completeness, parameter descriptions, and error handling guidance. Most tools have descriptions (194 chars avg baseline), but schemas are incomplete: parameters lack type specifications in many cases, and output formats are undocumented. The 'connection' parameter is overloaded across all tools but poorly described. No enumeration constraints for multi-valued parameters (e.g., response_format, widget_type, item_type). Error handling provides no recovery guidance. Tools are well-scoped (single responsibility), but composition is hampered by missing chaining IDs and pagination support.
Add an item to a floating menu
Add a new trigger to BetterTouchTool with JSON definition
Create a new floating menu with sensible defaults
Delete a trigger from BetterTouchTool
Display a notification via BetterTouchTool
Execute all actions assigned to a trigger by UUID
Export a BetterTouchTool preset to a file
Get clipboard content in specified format
Overloaded 'connection' parameter present on ALL 28 tools with generic description ('BTT connection configuration'). This violates secret-injection and parameter clarity patterns. The connection config should be injected server-side via environment/config, not passed per-tool.
Output schemas are completely undocumented. No tool explicitly declares what fields it returns or their types. LLMs cannot plan downstream calls or extract data. Examples: btt_get_triggers returns what? Array of trigger objects? What fields? btt_create_floating_menu returns the UUID of the created menu? Status? Full menu object?
Numeric and string parameters lack type specificity. Examples: btt_create_floating_menu has 'positioning_type' (integer) and 'anchor_menu' (integer), but no enum constraints or range bounds. LLMs will pass invalid integers. Same for 'layout_direction' (0-8 undocumented), 'icon_position' (0-4 undocumented), 'item_type' (773-778 undocumented). Descriptions mention examples ('0=freeMove, 1=fixedPosition') but no JSON Schema enums.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 45 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 23 | - | v1 |
Get a single floating menu by UUID with full details
Get all floating menus or floating menus for a specific app
Get detailed information about a preset
Get a single trigger by UUID
Retrieve triggers from BetterTouchTool with optional filtering by trigger type, ID, parent UUID, app, or specific trigger UUID
Get a BetterTouchTool variable by name
Hide a floating menu
Import a BetterTouchTool preset from a file
List all named triggers in BetterTouchTool
Refresh a script widget to trigger its update
Reveal an element in the BetterTouchTool UI by UUID
Set clipboard content to specified value
Set a BetterTouchTool variable to a value
Show a floating menu
Toggle the visibility of a floating menu
Trigger a BetterTouchTool action via JSON definition
Execute a named trigger by name
Update a floating menu's configuration
Update an existing trigger with partial JSON update
Update a widget (Touch Bar, Menubar, or Stream Deck) with new content
JSON parameters (trigger_json, update_json, action_json, actions_json) accept arbitrary JSON strings with no validation. Descriptions say 'use btt_lookup_reference for field names', but btt_lookup_reference is not in the tool list. LLMs have no way to know valid field names, types, or structures. This forces agents to guess or fail.
No pagination support. btt_get_triggers and btt_get_floating_menus return lists with no documented limit, offset, or pagination parameters. Large result sets will blow context windows. No mention of result limits or how to fetch next page.
Error handling provides no recovery guidance. No tool description explains what errors can occur, whether they are retryable, or what the LLM should do next. HTTP client (client/http.py) returns raw error strings like 'Error: Could not connect to BTT webserver', no actionable next steps.
response_format parameter accepts 'markdown' or 'json' but no enum constraint. Also, accepting multiple output formats is unusual and wastes LLM reasoning deciding which to request. Prefer structured (JSON) output always.
Destructive operations (btt_delete_trigger, btt_import_preset) lack confirmation or dry-run pattern. No description warns of irreversibility. An agent could silently delete or overwrite configs without safeguard.
btt_lookup_reference is mentioned in multiple tool descriptions but does not exist in the tool list. This breaks the composition chain, agents cannot discover field names or type IDs without this tool.
wait_for_reply parameter is boolean with no description of what 'reply' means or what is returned if true. Does it block? Does it return the result of the executed action? Timeout behavior?
variable_type parameter ('string' or 'number') is not an enum constraint. Descriptions say 'Type of variable', but no JSON Schema enum. LLMs may pass invalid types like 'boolean' or 'integer'.