Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(puppeteer): enable async code execution in puppeteer_evaluate tool #149

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

matipojo
Copy link

@matipojo matipojo commented Nov 30, 2024

Description

The fix enables the puppeteer_evaluate tool in the Puppeteer server to properly handle and execute asynchronous code. Previously, async functions would return empty results, but now they correctly wait for and return the resolved values.

Example before fix:

// Returns empty results {}
(async function exampleForWatingforFetchResults(query) {
    const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
    await sleep(2_000);
    console.log('searching for:', query);
    return { searchResults: ['result #1'] };
})('foo');

Before fix output:

{
  "content": [
    {
      "type": "text",
      "text": "Execution result:\n{}\n\nConsole output:\n"
    }
  ],
  "isError": false
}

After fix output:

{
  "content": [
    {
      "type": "text",
      "text": "Execution result:\n{\n  \"searchResults\": [\n    \"result #1\"\n  ]\n}\n\nConsole output:\n[log] searching for: foo"
    }
  ],
  "isError": false
}

Server Details

  • Server: puppeteer
  • Changes to: tools (puppeteer_evaluate tool)

Motivation and Context

This fix is crucial for properly executing asynchronous JavaScript code in browser automation tasks. Common use cases that were previously broken include:

  • Web scraping with delay handling
  • Waiting for network requests to complete
  • Complex browser automation sequences requiring async/await
  • Custom scripts that interact with browser APIs asynchronously

How Has This Been Tested?

By running both versions in Claude Desktop and MCP Inspector.

Breaking Changes

No breaking changes. This fix enhances existing functionality without modifying the tool's interface.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Protocol Documentation
  • My server follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

The implementation approach involves three key steps:

  1. Console Preparation:

    • Before code execution, the browser's console functions are manipulated to capture all logs
    • This ensures proper collection of console output during async operations
  2. Code Execution:

    • Instead of using JavaScript's eval, the code is executed using Puppeteer's native evaluate function
    • This change is crucial as Puppeteer's evaluate is specifically designed to handle async code execution in the browser context
  3. Cleanup and Collection:

    • After execution, all console logs are collected
    • The manipulated console functions are reset to their original state
    • Both the execution result and console output are properly returned

@matipojo matipojo changed the title fix(fetch): fix puppeteer server to allow evaluate async functions fix(puppeteer): enable async code execution in puppeteer_evaluate tool Nov 30, 2024
Copy link
Member

@jspahrsummers jspahrsummers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the await on page.evaluate makes sense. Can you explain why you added window.mcpHelper?

@matipojo
Copy link
Author

matipojo commented Dec 3, 2024

Thanks, the await on page.evaluate makes sense. Can you explain why you added window.mcpHelper?

Since, in this solution, we can't use a local var to store the original console and the logs, so we have to store it on the global window.

Storing on the global window can make conflicts with other scripts that may run on the page, specially for a generic var name like logs, so I preferred to store them on a scoped variable on the global window.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants