Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .bandit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# Bandit configuration file

# Skip specific test IDs
skips: [B104, B404, B603]

# Plugin configs
any_other_function_with_shell_equals_true:
no_shell: [subprocess.Popen]
6 changes: 6 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[flake8]
max-line-length = 88
extend-ignore = E501
per-file-ignores =
server/server.py:E501
src/browser_use_mcp_server/cli.py:E501
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ jobs:
- name: "Python lint"
run: uvx ruff check .

- name: "Validate project metadata"
run: uvx --from 'validate-pyproject[all,store]' validate-pyproject pyproject.toml

build-and-publish:
runs-on: ubuntu-latest

Expand Down
15 changes: 6 additions & 9 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-depth: 0

- name: Set up uv and Python
uses: astral-sh/setup-uv@v5
Expand All @@ -30,18 +30,14 @@ jobs:
python-version: "3.13"
cache-dependency-glob: "pyproject.toml"

- name: Install python packages
run: |
uv sync
- name: Build a binary wheel and a source tarball
run: |
uv build --sdist --wheel --out-dir dist
- name: Build
run: uv build

- name: Publish build artifacts
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: pypi-dists
path: "./dist"
path: dist/

pypi-publish:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -73,6 +69,7 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/

github-release:
name: >-
Sign the Python 🐍 distribution 📦 with Sigstore and upload them to GitHub
Expand Down
59 changes: 59 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[MASTER]
# Python version
py-version = 3.11

# Disable specific messages
disable=
C0301, # Line too long
R0402, # Use 'from mcp import types' instead
W1203, # Use lazy % formatting in logging functions
R0913, # Too many arguments
R0917, # Too many positional arguments
R0914, # Too many local variables
W0718, # Catching too general exception Exception
R0915, # Too many statements
W0613, # Unused argument
R1705, # Unnecessary "elif" after "return"
R0912, # Too many branches
W0621, # Redefining name from outer scope
W0404, # Reimport
C0415, # Import outside toplevel
W0212, # Access to a protected member
W0107, # Unnecessary pass statement
R0801, # Similar lines in files
import-error,
no-value-for-parameter,
logging-fstring-interpolation,
protected-access,
redefined-outer-name,
reimported

# Add files or directories to the blacklist
ignore=.git,__pycache__,.venv,dist,build

# Use multiple processes to speed up Pylint
jobs=4

[FORMAT]
# Maximum number of characters on a single line
max-line-length=120

# Maximum number of lines in a module
max-module-lines=300

[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels
confidence=HIGH,CONTROL_FLOW

[DESIGN]
# Maximum number of arguments for function / method
max-args=10

# Maximum number of locals for function / method
max-locals=30

# Maximum number of statements in function / method body
max-statements=60

# Maximum number of branch for function / method body
max-branches=15
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ENV UV_COMPILE_BYTECODE=1 \

# Install build dependencies and clean up in the same layer
RUN apt-get update -y && \
apt-get install --no-install-recommends -y clang && \
apt-get install --no-install-recommends -y clang git && \
rm -rf /var/lib/apt/lists/*

# Install Python before the project for caching
Expand Down
56 changes: 43 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "browser-use-mcp-server"
version = "0.1.3"
dynamic = ["version"]
description = "MCP browser-use server library"
readme = "README.md"
requires-python = ">=3.11,<4.0"
license = {text = "MIT"}
authors = [
{name = "Cobrowser Team"}
]
Expand All @@ -32,17 +29,19 @@ dependencies = [
]

[project.optional-dependencies]
dev = [
# Dependencies for running tests
test = [
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
]
# Dependencies for development (includes test dependencies)
dev = [
"browser-use-mcp-server[test]",
"black>=23.0.0",
"isort>=5.12.0",
"mypy>=1.0.0",
]
test = [
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"ruff>=0.5.5",
]

[project.urls]
Expand All @@ -53,6 +52,7 @@ test = [
testpaths = ["tests"]
python_files = "test_*.py"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

[tool.black]
line-length = 88
Expand All @@ -72,9 +72,39 @@ disallow_incomplete_defs = true
[project.scripts]
browser-use-mcp-server = "browser_use_mcp_server.cli:cli"

[build-system]
requires = ["hatchling", "uv-dynamic-versioning"]
build-backend = "hatchling.build"

[tool.hatch.build]
packages = ["src", "server"]
include = ["server"]
include = ["src/browser_use_mcp_server", "server"]

[tool.hatch.build.targets.wheel]
packages = ["src/browser_use_mcp_server", "server"]

[tool.hatch.version]
source = "uv-dynamic-versioning"

[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true

[tool.ruff]
line-length = 88
target-version = "py311"

[tool.ruff.lint]
# Enable common Pyflakes, pycodestyle, and isort rules
select = ["E", "F", "W", "I"]
# Ignore line length violations in comments, docstrings, and string literals
extend-ignore = ["E501"]

# Exclude string literals and comments from line length checks
[tool.ruff.lint.per-file-ignores]
"server/server.py" = ["E501"]
"src/browser_use_mcp_server/cli.py" = ["E501"]

[tool.ruff.format]
# Use black-compatible formatting
quote-style = "double"
8 changes: 8 additions & 0 deletions pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"reportMissingImports": false,
"reportMissingModuleSource": false,
"reportOptionalMemberAccess": false,
"reportAttributeAccessIssue": false,
"reportCallIssue": false,
"reportFunctionMemberAccess": false
}
30 changes: 28 additions & 2 deletions server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
from .server import main
"""
Browser-Use MCP Server core implementation.
__all__ = ["main"]
This package provides the core implementation of the MCP server for browser automation.
"""

from .server import (
CONFIG,
Server,
cleanup_old_tasks,
create_browser_context_for_task,
create_mcp_server,
init_configuration,
main,
run_browser_task_async,
task_store,
)

__all__ = [
"Server",
"main",
"create_browser_context_for_task",
"run_browser_task_async",
"cleanup_old_tasks",
"create_mcp_server",
"init_configuration",
"CONFIG",
"task_store",
]
42 changes: 21 additions & 21 deletions server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,41 @@
"""

# Standard library imports
import os
import asyncio
import json
import logging
import os
import sys

# Set up SSE transport
import threading
import time
import traceback
import uuid
from datetime import datetime
from typing import Any, Dict, Optional, Tuple, Union
import time
import sys

# Third-party imports
import click
from dotenv import load_dotenv
from pythonjsonlogger import jsonlogger
import mcp.types as types
import uvicorn

# Browser-use library imports
from browser_use import Agent
from browser_use.browser.browser import Browser, BrowserConfig
from browser_use.browser.context import BrowserContext, BrowserContextConfig

# MCP server components
from mcp.server import Server
import mcp.types as types
from dotenv import load_dotenv
from langchain_core.language_models import BaseLanguageModel

# LLM provider
from langchain_openai import ChatOpenAI
from langchain_core.language_models import BaseLanguageModel

# MCP server components
from mcp.server import Server
from mcp.server.sse import SseServerTransport
from pythonjsonlogger import jsonlogger
from starlette.applications import Starlette
from starlette.routing import Mount, Route

# Configure logging
logger = logging.getLogger()
Expand Down Expand Up @@ -805,14 +812,6 @@ def main(
locale=locale,
)

# Set up SSE transport
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Mount, Route
import uvicorn
import asyncio
import threading

sse = SseServerTransport("/messages/")

# Create the Starlette app for SSE
Expand Down Expand Up @@ -891,15 +890,15 @@ def run_uvicorn():

uvicorn.run(
starlette_app,
host="0.0.0.0",
host="0.0.0.0", # nosec
port=port,
log_config=log_config,
log_level="info",
)

# If proxy mode is enabled, run both the SSE server and mcp-proxy
if stdio:
import subprocess
import subprocess # nosec

# Start the SSE server in a separate thread
sse_thread = threading.Thread(target=run_uvicorn)
Expand All @@ -924,7 +923,8 @@ def run_uvicorn():
)

try:
with subprocess.Popen(proxy_cmd) as proxy_process:
# Using trusted command arguments from CLI parameters
with subprocess.Popen(proxy_cmd) as proxy_process: # nosec
proxy_process.wait()
except Exception as e:
logger.error(f"Error starting mcp-proxy: {str(e)}")
Expand Down
2 changes: 1 addition & 1 deletion src/browser_use_mcp_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
using the browser_use library.
"""

__version__ = "0.1.3"
__version__ = "0.0.0"
Loading