feat: add support for remote browser connections via CDP#515
Conversation
- Introduced `CDP_ENDPOINT` and `CDP_PERSISTENT` configuration options in `.env.example` and updated documentation to reflect these changes. - Implemented logic in the server to connect to a remote browser over the Chrome DevTools Protocol (CDP), allowing LinkedIn sessions to be managed remotely. - Updated the `BrowserManager` to handle both local and CDP connections, including session validation and management. - Added tests to ensure proper functionality of CDP mode, including session validation and browser lifecycle management. - Enhanced error handling for unauthenticated CDP sessions.
Greptile SummaryThis PR adds remote browser support over Chrome DevTools Protocol. The main changes are:
Confidence Score: 3/5These CDP workflow issues should be fixed before merging.
|
| Filename | Overview |
|---|---|
| linkedin_mcp_server/core/browser.py | Adds CDP connection and close behavior, including endpoint logging and reuse of the first remote page. |
| linkedin_mcp_server/drivers/browser.py | Adds CDP browser creation and /feed/ validation on the selected remote page. |
| linkedin_mcp_server/dependencies.py | Adds CDP-specific auth-error handling that currently closes the remote browser before asking the user to log in. |
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
linkedin_mcp_server/core/browser.py:180-183
**Redact CDP endpoint**
This logs the full CDP endpoint. Remote browser URLs commonly carry bearer tokens, basic-auth userinfo, or unguessable browser IDs in the URL path or query string. When that endpoint is written to normal server logs, those credentials can be exposed through Docker logs, MCP client logs, or support bundles. Please log only a redacted endpoint, such as scheme and host.
### Issue 2 of 3
linkedin_mcp_server/dependencies.py:65-73
**Keep login browser alive**
In CDP mode this auth-error path closes the shared browser before returning the message that tells the user to log in to the remote browser and retry. With the default `cdp_persistent=False`, `close_browser()` sends `Browser.close`, so an expired or unauthenticated remote session gets terminated instead of staying open for the user to fix. A user who points this at an existing browser-use session can lose the browser/profile they need to log into. This path should disconnect or otherwise leave the remote browser running when the next action is manual login.
### Issue 3 of 3
linkedin_mcp_server/core/browser.py:175-178
**Avoid hijacking tabs**
For CDP connections this reuses the first existing page in the remote context, and startup validation immediately navigates `browser.page` to `https://www.linkedin.com/feed/`. Running `--status` or the first tool call against a browser-use session can therefore navigate the user's active tab away from a message draft, form, or in-progress remote task. CDP mode should create or track a dedicated page for this server instead of taking over `pages[0]`.
Reviews (1): Last reviewed commit: "feat: add support for remote browser con..." | Re-trigger Greptile
| logger.info( | ||
| "Connected to remote browser over CDP (endpoint=%s, persistent=%s)", | ||
| self.cdp_endpoint, | ||
| self.cdp_persistent, |
There was a problem hiding this comment.
This logs the full CDP endpoint. Remote browser URLs commonly carry bearer tokens, basic-auth userinfo, or unguessable browser IDs in the URL path or query string. When that endpoint is written to normal server logs, those credentials can be exposed through Docker logs, MCP client logs, or support bundles. Please log only a redacted endpoint, such as scheme and host.
Prompt To Fix With AI
This is a comment left during a code review.
Path: linkedin_mcp_server/core/browser.py
Line: 180-183
Comment:
**Redact CDP endpoint**
This logs the full CDP endpoint. Remote browser URLs commonly carry bearer tokens, basic-auth userinfo, or unguessable browser IDs in the URL path or query string. When that endpoint is written to normal server logs, those credentials can be exposed through Docker logs, MCP client logs, or support bundles. Please log only a redacted endpoint, such as scheme and host.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| if get_runtime_policy() == RuntimePolicy.CDP: | ||
| try: | ||
| await close_browser() | ||
| except Exception as close_exc: | ||
| logger.warning("Failed to close stale CDP browser (ignored): %s", close_exc) | ||
| raise CDPSessionUnauthenticatedError( | ||
| "No valid LinkedIn session is available on the remote CDP browser. " | ||
| "Log in to LinkedIn in the remote browser (e.g. browser-use), " | ||
| "then retry this tool." |
There was a problem hiding this comment.
In CDP mode this auth-error path closes the shared browser before returning the message that tells the user to log in to the remote browser and retry. With the default cdp_persistent=False, close_browser() sends Browser.close, so an expired or unauthenticated remote session gets terminated instead of staying open for the user to fix. A user who points this at an existing browser-use session can lose the browser/profile they need to log into. This path should disconnect or otherwise leave the remote browser running when the next action is manual login.
Prompt To Fix With AI
This is a comment left during a code review.
Path: linkedin_mcp_server/dependencies.py
Line: 65-73
Comment:
**Keep login browser alive**
In CDP mode this auth-error path closes the shared browser before returning the message that tells the user to log in to the remote browser and retry. With the default `cdp_persistent=False`, `close_browser()` sends `Browser.close`, so an expired or unauthenticated remote session gets terminated instead of staying open for the user to fix. A user who points this at an existing browser-use session can lose the browser/profile they need to log into. This path should disconnect or otherwise leave the remote browser running when the next action is manual login.
How can I resolve this? If you propose a fix, please make it concise.| if self._context.pages: | ||
| self._page = self._context.pages[0] | ||
| else: | ||
| self._page = await self._context.new_page() |
There was a problem hiding this comment.
For CDP connections this reuses the first existing page in the remote context, and startup validation immediately navigates browser.page to https://www.linkedin.com/feed/. Running --status or the first tool call against a browser-use session can therefore navigate the user's active tab away from a message draft, form, or in-progress remote task. CDP mode should create or track a dedicated page for this server instead of taking over pages[0].
Prompt To Fix With AI
This is a comment left during a code review.
Path: linkedin_mcp_server/core/browser.py
Line: 175-178
Comment:
**Avoid hijacking tabs**
For CDP connections this reuses the first existing page in the remote context, and startup validation immediately navigates `browser.page` to `https://www.linkedin.com/feed/`. Running `--status` or the first tool call against a browser-use session can therefore navigate the user's active tab away from a message draft, form, or in-progress remote task. CDP mode should create or track a dedicated page for this server instead of taking over `pages[0]`.
How can I resolve this? If you propose a fix, please make it concise.
CDP_ENDPOINTandCDP_PERSISTENTconfiguration options in.env.exampleand updated documentation to reflect these changes.BrowserManagerto handle both local and CDP connections, including session validation and management.