Skip to content

fix: enhance project configuration with dynamic versioning and update CI workflow for artifact handling #36

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

Merged
merged 8 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions 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 Expand Up @@ -57,7 +57,8 @@ COPY --from=builder /app /app
# Set proper permissions
RUN chmod -R 755 /python /app

ENV PATH="/app/.venv/bin:$PATH" \
ENV ANONYMIZED_TELEMETRY=false \
PATH="/app/.venv/bin:$PATH" \
DISPLAY=:0 \
CHROME_BIN=/usr/bin/chromium \
CHROMIUM_FLAGS="--no-sandbox --headless --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage"
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: 0 additions & 2 deletions src/browser_use_mcp_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@
This package provides a Model-Control-Protocol (MCP) server for browser automation
using the browser_use library.
"""

__version__ = "0.1.3"
Loading