Skip to content

[Bug] Running multiple parallel async browsers in --isolated mode leaves orphan browsers. This has started happening after Release v0.0.69. #1607

Description

@ShishirPrashanth

Bug Description

I created multiple concurrent HTTP sessions through a simple Python script using asyncio. Multiple browsers opened and worked as expected, and the returned results were correct.

However, after execution completed, only one browser terminated successfully. The remaining N-1 browser instances were left orphaned.

This happens after the completion of the last (slowest) task.

NOTE: This issue started happening from v0.0.69 onwards. It was not happening till v0.0.68.


Reproduction Steps

MCP Server Setup

npx @playwright/mcp@latest --port 8931 --isolated

Client Code

import asyncio

import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
from mcp.shared._httpx_utils import create_mcp_http_client

TARGET_URLS = [
    "https://www.wikipedia.org",
    "https://www.google.com",
    "https://www.amazon.in",
]

MCP_CODE = """
async (page) => {
    await page.waitForLoadState('networkidle');
    await page.waitForTimeout(2000);
    return await page.content();
}
"""


async def get_page_html(url: str) -> str:
    mcp_url = "http://localhost:8931/mcp"

    long_timeout = httpx.Timeout(300.0, read=300.0)

    async with create_mcp_http_client(timeout=long_timeout) as http_client:
        async with streamable_http_client(
            mcp_url,
            http_client=http_client,
        ) as (read, write, _get_session_id):

            async with ClientSession(read, write) as session:
                await session.initialize()

                await session.call_tool(
                    "browser_navigate",
                    {"url": url},
                )

                tool_result = await session.call_tool(
                    "browser_run_code_unsafe",
                    {"code": MCP_CODE},
                )

                return tool_result


async def main():
    tasks = [get_page_html(url) for url in TARGET_URLS]

    results = await asyncio.gather(*tasks)

    for url, result in zip(TARGET_URLS, results):
        print(f"URL: {url}")
        print(result)
        print("-" * 100)


if __name__ == "__main__":
    asyncio.run(main())

Observed Behavior

  • 3 browser instances open successfully.
  • All requests complete successfully.
  • Correct results are returned.
  • Only one browser instance closes at the end.
  • The remaining 2 browser instances remain orphaned.

Expected Behavior

All browser instances created for concurrent sessions should terminate cleanly after task completion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions