pyproject.toml•8.72 kB
[project]
name = "mcp-foxxy-bridge"
description = "A MCP Forward Proxy Bridge designed to be a one-to-many bridge allowing you to use a single MCP server to communicate with many MCP servers transparently."
authors = [{ name = "Billy Bryant", email = "billy@billyjbryant.com" }]
license = { file = "LICENSE" }
readme = "README.md"
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
"Operating System :: MacOS",
"Operating System :: POSIX :: Linux",
"Operating System :: Unix",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities",
"Typing :: Typed",
]
dynamic = ["version"]
requires-python = ">=3.11"
dependencies = [
"mcp>=1.8.0,<2.0.0",
"uvicorn>=0.34.0",
"jsonschema>=4.0.0",
"watchdog>=3.0.0",
"rich>=13.0.0",
"aiohttp>=3.12.15",
"events>=0.5",
"cryptography>=3.4.8",
"keyring>=23.0.0",
"httpx[http2]>=0.28.0",
"psutil>=5.9.0",
"pyyaml>=6.0.0",
"click>=8.1.0",
"rich-click>=1.7.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project.urls]
Homepage = "https://github.com/billyjbryant/mcp-foxxy-bridge"
Source = "https://github.com/billyjbryant/mcp-foxxy-bridge"
Documentation = "https://github.com/billyjbryant/mcp-foxxy-bridge"
Changelog = "https://github.com/billyjbryant/mcp-foxxy-bridge/releases"
[project.scripts]
foxxy-bridge = "mcp_foxxy_bridge.cli.main:cli"
mcp-foxxy-bridge = "mcp_foxxy_bridge.cli.main:cli"
[tool.hatch.build.targets.wheel]
packages = ["src/mcp_foxxy_bridge"]
[tool.hatch.version]
path = "VERSION"
pattern = "(?P<version>\\d+\\.\\d+\\.\\d+.*)"
[tool.uv]
dev-dependencies = [
"pytest>=8.3.3",
"pytest-asyncio>=0.25.0",
"coverage>=7.6.0",
"mypy>=1.0.0",
"hatch>=1.12.0",
"ruff>=0.12.5",
"pre-commit>=3.5.0",
]
[tool.coverage.run]
branch = true
[tool.coverage.report]
skip_covered = true
show_missing = true
precision = 2
exclude_lines = [
'pragma: no cover',
'raise NotImplementedError',
'if TYPE_CHECKING:',
'if typing.TYPE_CHECKING:',
'@overload',
'@typing.overload',
'\(Protocol\):$',
'typing.assert_never',
'$\s*assert_never\(',
'if __name__ == .__main__.:',
]
[tool.mypy]
allow_redefinition = false
disallow_untyped_defs = true
follow_imports = "normal"
follow_untyped_imports = true
no_implicit_optional = true
show_error_code_links = true
show_error_codes = true
strict = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_configs = true
warn_unused_ignores = true
# Exclude virtual environment and other non-source files
exclude = [
"use/",
".venv/",
"venv/",
"env/",
".mypy_cache/",
"__pycache__/",
]
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"EM101", # Exception must not use a string literal, assign to variable first
"TRY003", # Avoid specifying long messages outside the exception class
"ERA001", # Found commented-out code
"COM812", # Trailing comma missing (conflicts with formatter)
"TD002", # Missing author in TODO (false positives with our format)
"TD003", # Missing issue link for TODO (false positives with our format)
"FIX002", # Line contains TODO (expected in development)
"C901", # Function is too complex (complex functions - future refactor)
"PLR0912", # Too many branches (complex validation - future refactor)
"PLR0915", # Too many statements (complex functions - future refactor)
# Style preferences - reasonable to ignore for this codebase
"G004", # F-strings in logging (more readable than % formatting)
"FBT001", # Boolean positional arguments (common in config APIs)
"FBT002", # Boolean default arguments (common in config APIs)
"PLR2004", # Magic value comparisons (obvious values like 20, 100)
"PLR0913", # Too many arguments (sometimes necessary for APIs)
"ANN401", # Any type annotation (sometimes necessary)
"ANN003", # Missing type annotation for **kwargs
"D107", # Missing docstring in __init__ (often obvious)
"ARG001", # Unused function argument (often required by interfaces)
"PLW0603", # Global statement (sometimes necessary)
"TRY401", # Verbose log message (exception details useful in logs)
"BLE001", # Blind except - using proper graceful degradation pattern
"TRY300", # Consider moving statement to else block (often makes code less readable)
"TRY301", # Abstract raise to inner function (often makes code less readable)
"SIM102", # Use single if statement (sometimes nested is clearer)
"EM102", # Exception must not use f-string (f-strings are fine for exceptions)
"ASYNC109", # Async function with timeout parameter (legitimate pattern)
"ANN003", # Missing type annotation for **kwargs (sometimes necessary)
"B023", # Function definition does not bind loop variable (complex closure patterns)
"PLR0911", # Too many return statements (complex OAuth/API handlers need many returns)
]
[tool.ruff.lint.per-file-ignores]
"tests/*" = [
"S101", # Use of assert detected (allowed in tests)
"INP001", # File is part of an implicit namespace package
"D102", # Missing docstring in public method (not required in tests)
"D103", # Missing docstring in public function (not required in tests)
"ANN001", # Missing type annotation for function argument
"ANN201", # Missing return type annotation for public function
"ANN202", # Missing return type annotation for private function
"ANN003", # Missing type annotation for **kwargs
"PTH123", # Use of open() instead of Path.open() (acceptable in tests)
"RUF015", # Prefer next(iter()) over single element slice (acceptable in tests)
"F841", # Local variable assigned but never used (test setup variables)
"PLC0415", # Import should be at top-level (acceptable in tests)
"PLR0913", # Too many arguments (common in test fixtures)
"S106", # Possible hardcoded password (test data)
"S105", # Possible hardcoded password (test data)
"SIM117", # Use single with statement (nested context managers are fine in tests)
"PLR2004", # Magic value used in comparison (test values can be literals)
"S108", # Probable insecure usage of temp file/directory (acceptable in tests)
"ARG001", # Unused function argument (fixtures often unused)
"FBT001", # Boolean positional argument (common in test assertions)
"FBT002", # Boolean default argument (common in test fixtures)
"FBT003", # Boolean positional value in function call (test data/mocking)
"SLF001", # Private member accessed (testing internal methods)
"S110", # try-except-pass (acceptable in tests for error tolerance)
"SIM105", # Use contextlib.suppress (sometimes clearer to use try-except in tests)
]
"src/mcp_foxxy_bridge/cli/*" = [
"S324", # MD5 hash is acceptable for non-security purposes (daemon naming)
"S603", # Subprocess execution is expected in daemon manager
"S110", # Exception suppression is acceptable for daemon cleanup
"ASYNC220", # Async subprocess restrictions are relaxed for CLI tools
"ASYNC221", # Async subprocess restrictions are relaxed for CLI tools
"SIM105", # Contextlib.suppress preference is relaxed for CLI tools
"DTZ005", # Timezone awareness is less critical for CLI daemon timestamps
]
"src/mcp_foxxy_bridge/utils/bridge_config.py" = [
"PLC0415", # Import should be at the top-level (intentional to avoid circular imports)
]
"src/mcp_foxxy_bridge/cli/commands/oauth.py" = [
"PLC0415", # Import should be at the top-level (intentional to avoid circular imports)
]
"src/mcp_foxxy_bridge/cli/commands/server.py" = [
"PLC0415", # Import should be at the top-level (intentional to avoid circular imports)
]
"src/mcp_foxxy_bridge/cli/commands/tool.py" = [
"PLC0415", # Import should be at the top-level (intentional to avoid circular imports)
]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff]
line-length = 120
[tool.pytest.ini_options]
pythonpath = "src"
addopts = ["--import-mode=importlib"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"