[build-system] requires = ["hatchling", "hatch-vcs"] build-backend = "hatchling.build" [project] name = "ble-mcp-server" dynamic = ["version"] description = "Bluetooth Low Energy (BLE) Model Context Protocol server for AI agents and developer tooling" readme = "README.md" requires-python = ">=3.11" license = "MIT" authors = [ {name = "Enrico Santagati"}, ] dependencies = [ "bleak>=2.1,<3", "mcp>=1.23.0,<2", "pyyaml>=6.0,<7", ] [project.optional-dependencies] http = [ "uvicorn>=0.27", "starlette>=0.36", ] test = [ "pytest>=8.0", "pytest-asyncio>=0.23", "pytest-cov>=5.0", ] dev = [ "pre-commit>=4.0", "ruff>=0.9", ] [project.urls] Homepage = "https://github.com/es617/ble-mcp-server" Repository = "https://github.com/es617/ble-mcp-server" Issues = "https://github.com/es617/ble-mcp-server/issues" Changelog = "https://github.com/es617/ble-mcp-server/blob/main/CHANGELOG.md" [project.scripts] ble_mcp = "ble_mcp_server.server:main" [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] [tool.coverage.run] source = ["ble_mcp_server"] [tool.coverage.report] show_missing = true skip_covered = false [tool.ruff] target-version = "py311" line-length = 110 [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B", "S", "SIM", "RUF"] ignore = [ "E501", # line length handled by formatter "S110", # try-except-pass is intentional for best-effort BLE cleanup "SIM105", # contextlib.suppress is less readable for async cleanup "RUF001", # en-dash in strings is intentional "RUF002", # en-dash in docstrings is intentional "RUF003", # en-dash in comments is intentional "RUF006", # fire-and-forget create_task is intentional in signal handlers "S106", # token_type="bearer" is not a hardcoded password ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["S101", "S108", "RUF059"] # asserts, /tmp paths, unused unpacked vars are fine in tests "tools/*" = ["S603", "S607"] # subprocess calls in CLI tools use controlled input "examples/*" = ["S105", "S108", "S311", "S603", "S607"] # demo devices: fake passwords, /tmp, pseudo-random, subprocess [tool.ruff.lint.isort] known-first-party = ["ble_mcp_server"] [tool.hatch.version] source = "vcs" [tool.hatch.build.hooks.vcs] version-file = "ble_mcp_server/_version.py" [tool.bandit] exclude_dirs = ["tests"] skips = ["B110", "B106"] # B110: try-except-pass for BLE cleanup; B106: token_type="bearer" is not a hardcoded password