[project] name = "multi-mcp" version = "0.1.1" description = "Multi-Model Code Review and Analysis MCP Server for Claude Code" readme = "README.md" requires-python = ">=3.11,<3.14" license = "MIT" authors = [ {name = "Multi-MCP Team", email = "multi.mcp.team@gmail.com"} ] keywords = [ "agents", "ai", "ai-agents", "ai-agents-cli", "ai-code-review", "anthropic", "claude", "claude-commands", "claude-mcp", "claude-skills", "code-analysis", "developer-tools", "gemini", "gpt", "llm", "llm-orchestration", "mcp", "mcp-agent", "model-context-protocol", "multi-agent", "multi-model", "openai", ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", "Typing :: Typed", ] dependencies = [ "fastapi>=0.127.0", "fastmcp>=2.13", "litellm>=1.80.8", "orjson>=3.11.5", "pydantic>=2.12.0", "pydantic-settings>=2.12.0", "python-dotenv>=1.0.0", "pyyaml>=6.0", ] [project.scripts] multi = "multi_mcp.cli:main" multi-server = "multi_mcp.server:main" multi-mcp = "multi_mcp.server:main" [project.optional-dependencies] dev = [ # Testing "pytest>=9.0.0", "pytest-asyncio>=0.23.0", "pytest-mock>=3.15.0", "pytest-cov>=4.1.0", "pytest-timeout>=2.2.0", "pytest-xdist>=3.5.0", "pytest-recording>=0.13.4", "vcrpy>=7.0.0", "httpx>=0.26.0", # Linting & formatting "ruff>=0.14.0", "pyright>=1.1.407", # Dead code detection (YAGNI) "vulture>=2.11", # Publishing "twine>=6.0.0", ] [project.urls] Homepage = "https://github.com/religa/multi_mcp" Repository = "https://github.com/religa/multi_mcp" Documentation = "https://github.com/religa/multi_mcp#readme" Issues = "https://github.com/religa/multi_mcp/issues" "Release Notes" = "https://github.com/religa/multi_mcp/releases" "PyPI" = "https://pypi.org/project/multi-mcp/" Source = "https://github.com/religa/multi_mcp" [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["."] include = ["multi_mcp*"] exclude = ["tests*", "docs*", "ref*", "tmp*"] [tool.setuptools.package-data] multi_mcp = ["config/*.yaml", "prompts/*.md"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" pythonpath = ["."] norecursedirs = ["tmp", "ref", "docs", ".git", ".venv"] addopts = [ "--strict-markers", "--strict-config", "-ra", "--tb=short", "--color=yes", "--disable-recording", # Disable VCR due to httpx/litellm compatibility issues ] markers = [ "e2e: End-to-end tests using Claude CLI (deselect with '-m \"not e2e\"')", "slow: Tests that take >5 seconds to execute", "integration: Integration tests", "unit: Unit tests", ] filterwarnings = [ "error", "ignore::DeprecationWarning", "ignore::PendingDeprecationWarning", ] [tool.ruff] line-length = 140 target-version = "py311" exclude = ["tests/data/**", ".venv/**", "build/**", "dist/**", "ref/**", "tmp/**"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes (F401=unused imports, F841=unused variables) "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "C90", # mccabe complexity (KISS) "UP", # pyupgrade "SIM", # flake8-simplify (DRY/KISS suggestions) "PIE", # flake8-pie (misc simplifications) "RUF", # Ruff-specific rules (unused noqa, etc.) ] ignore = [ "E501", # line too long (handled by formatter) "B008", # do not perform function calls in argument defaults "SIM108", # use ternary operator (not always cleaner) ] [tool.ruff.lint.mccabe] max-complexity = 15 # KISS: Flag functions over this cyclomatic complexity [tool.ruff.lint.per-file-ignores] # Pre-existing complex functions - candidates for future refactoring "multi_mcp/models/cli_executor.py" = ["C901"] # execute, _parse_output "multi_mcp/tools/codereview.py" = ["C901"] # codereview_impl (31) # Tests often use nested with statements (pytest.raises + mocks) "tests/**/*.py" = ["SIM117"] # Scripts are utility code, not production "scripts/**/*.py" = ["SIM110", "SIM117"] [tool.ruff.lint.isort] known-first-party = ["multi_mcp"] [tool.pyright] include = ["multi_mcp"] exclude = ["**/__pycache__", "ref/", "tmp/", "**/.pytest_cache", "tests/data/"] typeCheckingMode = "basic" reportMissingImports = true reportMissingTypeStubs = false pythonVersion = "3.11" pythonPlatform = "All" [tool.coverage.run] source = ["multi_mcp"] branch = true omit = ["multi_mcp/__init__.py"] [tool.coverage.report] fail_under = 80 # Minimum coverage threshold show_missing = true exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", ]