Skip to main content
Glama
safari.mdc14.2 kB
--- description: globs: alwaysApply: false --- #### 5. MCP Inspector Specifics * **URL Consistency:** The MCP Inspector URL (`http://127.0.0.1:6274`) was found to be consistent between runs, simplifying Safari targeting. * **"Connected" State vs. iTerm Logs:** A key finding was that the Safari Inspector UI can show "Connected" (and tools subsequently work) even if detailed `DEBUG`-level logs from the launched server process (`start.sh` -> `node dist/server.js`) do not appear in the iTerm console where `npx @modelcontextprotocol/inspector` is running. The Inspector seems to show its own proxying/connection logs, but the full stdout/stderr of the child might not always be visible there. This means successful connection and tool usability are the primary indicators, and absence of detailed server logs in the iTerm console is not necessarily a showstopper for basic interaction, though it would affect deeper debugging of the server itself. These notes capture the iterative process and key takeaways from the Safari automation for the MCP Inspector. The successful methods are now enshrined in `mcp-inspector.mdc`, while this document provides the background and context. This contrasts with `mcp-inspector.mdc`, which is designed to be the concise, polished, and operational ruleset for future automated runs once a specific automation flow (like connecting to the MCP Inspector) has been stabilized and proven reliable. `mcp-inspector.mdc` should contain the 'final' working scripts and minimal necessary commentary, while `safari.mdc` is the space for the extended antechamber of discovery. * **Clarification on `[WORKSPACE_PATH]` Resolution:** The placeholder `[WORKSPACE_PATH]` used in rules (e.g., for script paths like `[WORKSPACE_PATH]/start.sh`) must be dynamically replaced by the AI with the absolute path of the current project workspace. This path is typically available to the AI from its context (e.g., derived from `user_info.workspace_path` or a similar environment variable). It is crucial that the AI ensures the resolved path is correctly quoted if it's used in shell commands or script arguments, especially if the path might contain spaces or special characters. For instance, a path like `/Users/username/My Projects/project-name` should be passed as `'/Users/username/My Projects/project-name'` in a shell command. --- ### Strategies for Robust Element Selection When automating UI interactions, the reliability of your scripts heavily depends on how you identify and select HTML elements. Here's a hierarchy of preferences and tips for making your selectors more robust: 1. **`data-testid` Attributes (Gold Standard):** * **Why:** These are custom attributes specifically added for testing and automation. They are decoupled from styling and functional implementation details, making them the most resilient to UI changes. * **Example (CSS):** `[data-testid='user-login-button']` * **Example (XPath):** `//*[@data-testid='user-login-button']` 2. **Unique `id` Attributes:** * **Why:** `id` attributes are *supposed* to be unique within a page. If developers adhere to this, they are very reliable. * **Example (CSS):** `#submit-form` * **Example (XPath):** `//*[@id='submit-form']` 3. **Stable `aria-label`, `aria-labelledby`, `role`, or other Accessibility Attributes:** * **Why:** Accessibility attributes are often more stable than class names used for styling, as they relate to the element's function and purpose. * **Example (CSS):** `button[aria-label='Open settings']` * **Example (XPath):** `//button[@aria-label='Open settings']` 4. **Stable Class Names (Used for Structure/Function, Not Just Styling):** * **Why:** Some class names indicate the structure or function of an element rather than just its appearance. These can be reasonably stable. Avoid classes that are purely presentational (e.g., `color-blue`, `margin-small`). * **Example (CSS):** `.user-profile-card .username` (Contextual selection) * **Example (XPath):** `//div[contains(@class, 'user-profile-card')]//span[contains(@class, 'username')]` 5. **Structural XPaths (Based on DOM hierarchy):** * **Why:** Relying on the element's position within the DOM (e.g., "the second `div` inside a `section` with a specific header"). These are more brittle than attribute-based selectors because any structural change can break them. Use sparingly and keep them as simple as possible. * **Example (XPath):** `//section[@id='main-content']/div[2]/p` 6. **Text-Based XPaths (Using visible text):** * **Why:** Selecting elements based on their visible text content (e.g., a button with the text "Submit"). Can be useful, but prone to breakage if the text changes (e.g., for localization or wording updates). * **Example (XPath):** `//button[text()='Submit']` or `//button[contains(text(), 'Submit')]` * **Tip for Robustness:** Use XPath's `normalize-space()` function to handle variations in whitespace (leading, trailing, multiple internal spaces). * `//button[normalize-space(text())='Submit']` (Matches " Submit ", "Submit", " Submit" etc.) * `//a[contains(normalize-space(.), 'Learn More')]` (Checks within any descendant text nodes) **General Tips for Selectors:** * **Prefer CSS Selectors for Simplicity and Speed:** When applicable, CSS selectors are often more concise and can be faster than XPaths. * **Use Browser Developer Tools:** Actively use the "Inspect Element" feature in your browser to test and refine your CSS selectors and XPaths. Most dev tools allow you to directly test them. * **Avoid Generated IDs/Classes:** Be wary of IDs or class names that look auto-generated (e.g., `id="ext-gen1234"`), as these are likely to change between page loads or application versions. * **Context is Key:** Instead of overly complex global selectors, try to select a stable parent element first, then find the target element within that parent's context. This often leads to simpler and more reliable selectors. --- ### Debugging AppleScript `do JavaScript` Execution Flow Successfully executing JavaScript via AppleScript's `do JavaScript` command often involves navigating two potential layers of errors: AppleScript parsing errors and JavaScript runtime errors. Here's how to approach debugging: **1. Differentiating Error Types:** * **AppleScript Compile-Time/Parsing Errors (e.g., `-2741`):** * **Symptom:** The AppleScript editor shows an error, or the script fails immediately when run, often with error messages like "Syntax Error," "Expected end of line but found...", or specific error codes like `-2741` (which typically means the command couldn't be parsed correctly, often due to malformed strings or incorrect quoting). * **Cause:** The AppleScript interpreter itself cannot understand the structure of your `do JavaScript "..."` command, usually due to incorrect quoting or escaping of characters *within the AppleScript string that defines the JavaScript code*. * **The JavaScript code itself hasn't even been sent to Safari yet.** * **JavaScript Runtime Errors:** * **Symptom:** The AppleScript command runs without an immediate AppleScript error, but the desired action doesn't occur in Safari, or `do JavaScript` returns an error message from the JavaScript engine (e.g., "TypeError: null is not an object" or "SyntaxError: Unexpected identifier"). * **Cause:** The JavaScript code was successfully passed to Safari, but the JavaScript engine encountered an error while trying to execute it (e.g., trying to access a property of a non-existent element, incorrect JS syntax, etc.). **2. Debugging AppleScript Syntax/Parsing Errors:** * **Simplify the JavaScript String:** Start with the simplest possible JavaScript that should work, e.g.: ```applescript tell application "Safari" do JavaScript "'test';" in front document end tell ``` * **Log the Constructed JavaScript String:** Before the `do JavaScript` line, use AppleScript's `log` command to print the exact JavaScript string you are about to send. This helps you visually inspect it for quoting issues. ```applescript set jsCommand to "document.getElementById(\"myButton\").click();" log jsCommand tell application "Safari" do JavaScript jsCommand in front document end tell ``` Check the logged output carefully in Script Editor's "Messages" tab. * **Build Complex Strings Incrementally:** If your JavaScript is complex, build it in parts using AppleScript variables. This can make it easier to manage quoting for each part. * **Master Quoting:** * If AppleScript string is in double quotes (`"..."`): Escape internal JS double quotes as `\"`. JS single quotes usually don't need escaping. * Use `character id 39` for single quotes if constructing JS with many internal single quotes to avoid confusion: `set sQuote to character id 39`. `set jsCommand to "var name = " & sQuote & "Pete" & sQuote & ";"` **3. Debugging JavaScript Runtime Errors:** * **Test in Safari's Web Inspector Console:** The most effective way to debug the JavaScript itself is to open Safari, navigate to the target page, open the Web Inspector (Develop > Show Web Inspector), and paste your JavaScript snippet directly into the Console. This provides immediate feedback, error messages, and allows for interactive debugging. * **Use `try...catch` in Your JavaScript:** Wrap your JavaScript code in a `try...catch` block to capture and return error messages back to AppleScript. This can make it much easier to see what went wrong inside Safari. ```applescript set jsCommand to "try { document.getElementById('nonExistentElement').value = 'test'; return 'Success'; } catch(e) { return 'JS Error: ' + e.name + ': ' + e.message; }" tell application "Safari" set jsResult to do JavaScript jsCommand in front document log jsResult end tell ``` * **Return Values for Debugging:** Have your JavaScript return intermediate values or status indicators to AppleScript to understand its state. ```applescript set jsCommand to "var el = document.getElementById('myField'); if (el) { return 'Element found!'; } else { return 'Element NOT found.'; }" log (do JavaScript jsCommand in front document) ``` By systematically checking for AppleScript parsing issues first, then moving to debug the JavaScript logic within Safari's environment, you can effectively troubleshoot `do JavaScript` commands. --- ### Advanced Asynchronous Handling: Polling for Conditions Web pages load and update content asynchronously. Relying on fixed `delay` commands in AppleScript after an action (like a click or page navigation) can be unreliable because the actual time needed for the UI to update can vary due to network speed, server load, or client-side processing. A more robust approach is to actively poll for a specific condition to be met (e.g., an element appearing, text changing, a certain JavaScript variable becoming true) before proceeding. This makes your scripts more resilient to timing variations. **How Polling Works:** 1. Define the JavaScript code that checks for your desired condition (this should return `true` or `false`). 2. In AppleScript, create a loop that: * Executes the JavaScript check. * If the condition is met, exit the loop. * If not, wait for a short interval (e.g., 0.5 seconds). * Include a counter or timeout mechanism to prevent the loop from running indefinitely if the condition is never met. **Example: Polling for 'Connected' Status in MCP Inspector** This AppleScript snippet demonstrates polling for the text "Connected" to appear on the page after clicking the connect button: ```applescript -- JavaScript to check if the page body contains the text "Connected" set jsCheckConnected to "document.body.innerText.includes('Connected');" set isNowConnected to false set attempts to 0 set maxAttempts to 20 -- Set a reasonable limit, e.g., 20 attempts set pollInterval to 0.5 -- Wait 0.5 seconds between attempts log "Polling for 'Connected' status..." tell application "Safari" tell front document repeat while isNowConnected is false and attempts < maxAttempts try if (do JavaScript jsCheckConnected) is true then set isNowConnected to true log "Status changed to 'Connected' after " & (attempts + 1) & " attempts." else delay pollInterval end if on error errMsg number errNum log "Error during JavaScript check (attempt " & (attempts + 1) & "): " & errMsg & " (Number: " & errNum & ")" -- Decide if you want to stop on error or just log and continue delay pollInterval -- Still delay even if JS itself errored, maybe it's a temporary issue end try set attempts to attempts + 1 end repeat end tell end tell if isNowConnected then log "Successfully confirmed 'Connected' status via polling." -- Proceed with next actions that depend on being connected else log "Failed to see 'Connected' status within " & (maxAttempts * pollInterval) & " seconds." -- Handle the failure case (e.g., log error, stop script) end if ``` **Benefits of Polling:** * **Increased Reliability:** Scripts wait only as long as necessary, adapting to real-time conditions rather than fixed, potentially too short or too long, delays. * **Reduced Brittleness:** Less likely to fail due to unexpected slowdowns. * **Clearer Intent:** The script explicitly states what condition it's waiting for. **Considerations:** * **Timeout:** Always implement a maximum number of attempts or a total timeout to prevent infinite loops if the condition never occurs. * **Poll Interval:** Choose a reasonable interval. Too short can be resource-intensive; too long can make the script feel sluggish. * **Error Handling:** Include `try...on error` blocks within your loop to gracefully handle potential errors during the JavaScript execution (e.g., if the page is still transitioning and elements are not yet available). --- ### Meta-Level Collaboration & Rule Evolution Notes

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/steipete/Peekaboo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server