pyproject.toml•14.3 kB
# ----------------------------------------------------------------
# 💡 Build system (PEP 517)
# - setuptools ≥ 77 gives SPDX licence support (PEP 639)
# - wheel is needed by most build front-ends
# ----------------------------------------------------------------
[build-system]
requires = ["setuptools>=77", "wheel"]
build-backend = "setuptools.build_meta"
# ----------------------------------------------------------------
# 📦 Core project metadata (PEP 621)
# ----------------------------------------------------------------
[project]
name = "mcp-contextforge-gateway"
version = "0.3.1"
description = "A production-grade MCP Gateway & Proxy built with FastAPI. Supports multi-server registration, virtual server composition, authentication, retry logic, observability, protocol translation, and a unified federated tool catalog."
keywords = ["MCP","API","gateway","proxy","tools",
"agents","agentic ai","model context protocol","multi-agent","fastapi",
"json-rpc","sse","websocket","federation","security","authentication"
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Framework :: FastAPI",
"Framework :: AsyncIO",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
"Topic :: Software Development :: Libraries :: Application Frameworks"
]
readme = "README.md"
requires-python = ">=3.11,<3.14"
# SPDX licence expression + explicit licence file (PEP 639)
license = "Apache-2.0"
license-files = ["LICENSE"]
# Maintainers
maintainers = [
{name = "Mihai Criveti", email = "redacted@ibm.com"}
]
# ----------------------------------------------------------------
# Runtime dependencies
# ----------------------------------------------------------------
dependencies = [
"alembic>=1.16.4",
"cryptography>=45.0.5",
"fastapi>=0.116.1",
"filelock>=3.18.0",
"gunicorn>=23.0.0",
"httpx>=0.28.1",
"jinja2>=3.1.6",
"jq>=1.10.0",
"jsonpath-ng>=1.7.0",
"jsonschema>=4.24.0",
"mcp>=1.11.0",
"parse>=1.20.2",
"psutil>=7.0.0",
"pydantic>=2.11.7",
"pydantic-settings>=2.10.1",
"pyjwt>=2.10.1",
"sqlalchemy>=2.0.41",
"sse-starlette>=2.4.1",
"starlette>=0.46.2",
"uvicorn>=0.35.0",
"zeroconf>=0.147.0",
]
# ----------------------------------------------------------------
# Optional dependency groups (extras)
# ----------------------------------------------------------------
[project.optional-dependencies]
# Optional dependency groups (runtime)
redis = [
"redis>=6.2.0",
]
postgres = [
"psycopg2-binary>=2.9.10",
]
alembic = [
"alembic>=1.16.4",
]
# Async SQLite Driver (optional)
aiosqlite = [
"aiosqlite>=0.21.0",
]
# Async PostgreSQL driver (optional)
asyncpg = [
"asyncpg>=0.30.0",
]
# Optional dependency groups (development)
dev = [
"argparse-manpage>=4.6",
"autoflake>=2.3.1",
"bandit>=1.8.6",
"black>=25.1.0",
"bump2version>=1.0.1",
"check-manifest>=0.50",
"code2flow>=2.5.1",
"cookiecutter>=2.6.0",
"coverage>=7.9.2",
"coverage-badge>=1.1.2",
"darglint>=1.8.1",
"dlint>=0.16.0",
"dodgy>=0.2.1",
"fawltydeps>=0.20.0",
"flake8>=7.3.0",
"gprof2dot>=2025.4.14",
"importchecker>=3.0",
"interrogate>=1.7.0",
"isort>=6.0.1",
"mypy>=1.17.0",
"pexpect>=4.9.0",
"pip-licenses>=5.0.0",
"pip_audit>=2.9.0",
"pre-commit>=4.2.0",
"prospector[with_everything]>=1.17.2",
"pydocstyle>=6.3.0",
"pylint>=3.3.7",
"pylint-pydantic>=0.3.5",
"pyre-check>=0.9.25",
"pyrefly>=0.24.2",
"pyright>=1.1.403",
"pyroma>=5.0",
"pyspelling>=2.10",
"pytest>=8.4.1",
"pytest-asyncio>=1.0.0",
"pytest-cov>=6.2.1",
"pytest-env>=1.1.5",
"pytest-examples>=0.0.18",
"pytest-md-report>=0.7.0",
"pytest-rerunfailures>=15.1",
"pytest-trio>=0.8.0",
"pytest-xdist>=3.8.0",
"pytype>=2024.10.11",
"pyupgrade>=3.20.0",
"radon>=6.0.1",
"redis>=6.2.0",
"ruff>=0.12.3",
"semgrep>=1.128.1",
"settings-doc>=4.3.2",
"snakeviz>=2.2.2",
"tomlcheck>=0.2.3",
"tox>=4.27.0",
"tox-uv>=1.26.1",
"twine>=6.1.0",
"ty>=0.0.1a14",
"types-tabulate>=0.9.0.20241207",
"unimport>=1.2.1",
"uv>=0.7.21",
"vulture>=2.14",
"yamllint>=1.37.1",
]
# UI Testing
playwright = [
"playwright>=1.53.0",
"pytest-html>=4.1.1",
"pytest-playwright>=0.7.0",
"pytest-timeout>=2.4.0",
]
# Convenience meta-extras
all = [
"mcp-contextforge-gateway[redis]>=0.3.1",
]
dev-all = [
"mcp-contextforge-gateway[redis,dev]>=0.3.1",
]
# --------------------------------------------------------------------
# Authors and URLs
# --------------------------------------------------------------------
[[project.authors]]
name = "Mihai Criveti"
email = "redacted@ibm.com"
[project.urls]
Homepage = "https://ibm.github.io/mcp-context-forge/"
Documentation = "https://ibm.github.io/mcp-context-forge/"
Repository = "https://github.com/IBM/mcp-context-forge"
"Bug Tracker" = "https://github.com/IBM/mcp-context-forge/issues"
Changelog = "https://github.com/IBM/mcp-context-forge/blob/main/CHANGELOG.md"
# --------------------------------------------------------------------
# 💻 Project scripts (cli entrypoint)
# --------------------------------------------------------------------
[project.scripts]
mcpgateway = "mcpgateway.cli:main"
# --------------------------------------------------------------------
# 🔧 setuptools-specific configuration
# --------------------------------------------------------------------
[tool.setuptools]
include-package-data = true # ensure wheels include the data files
# Automatic discovery: keep every package that starts with "mcpgateway"
[tool.setuptools.packages.find]
include = ["mcpgateway*"]
exclude = ["tests*"]
## Runtime data files ------------------------------------------------
# - py.typed -> advertises inline type hints (PEP 561)
# - static/* -> CSS/JS for the admin UI
# - templates -> Jinja2 templates shipped at runtime
[tool.setuptools.package-data]
mcpgateway = [
"py.typed",
"static/*.css",
"static/*.js",
"templates/*.html",
"alembic.ini",
"alembic/*.py",
"alembic/*.mako",
"alembic/*.md",
"alembic/versions/*.py",
]
# --------------------------------------------------------------------
# 🛠 Tool configurations (black, mypy, etc.)
# --------------------------------------------------------------------
[tool.pytype]
# Directory-specific options:
inputs = ["mcpgateway"]
python_version = "3.11" # match default runtime
[tool.check-manifest]
ignore = [
"docs/**",
"tests/**",
".github/**",
"Makefile",
]
[tool.black]
line-length = 200
target-version = ["py310", "py311", "py312"]
include = "\\.pyi?$"
# isort configuration
[tool.isort]
###############################################################################
# Core behaviour
###############################################################################
profile = "black" # inherit Black's own import-sorting profile
line_length = 200 # match Black's custom line length
multi_line_output = 3 # vertical-hanging-indent style
include_trailing_comma = true # keep trailing commas for Black
from_first = true # place all "from ... import ..." before plain "import ..."
###############################################################################
# Section ordering & headings
###############################################################################
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
import_heading_future = "Future" # header above FUTURE imports (if headings enabled)
import_heading_stdlib = "Standard" # header for built-in Stdlib imports
import_heading_thirdparty = "Third-Party" # header for pip-installed packages
import_heading_firstparty = "First-Party" # header for internal 'mcpgateway' code
import_heading_localfolder = "Local" # header for ad-hoc scripts / tests
###############################################################################
# What belongs where
###############################################################################
known_first_party = ["mcpgateway"] # treat "mcpgateway.*" as FIRSTPARTY
known_local_folder = ["tests", "scripts"] # treat these folders as LOCALFOLDER
# src_paths = ["src/mcpgateway"] # uncomment only if package moves under src/
###############################################################################
# Style niceties
###############################################################################
force_sort_within_sections = true # always alphabetise names inside each block
order_by_type = false # don't group imports by "type vs. straight name"
balanced_wrapping = true # spread wrapped imports evenly between lines
lines_between_sections = 1 # exactly one blank line between the five groups
lines_between_types = 1 # one blank line between 'import X' and 'from X import ...'
no_lines_before = ["LOCALFOLDER"] # suppress blank line *before* the LOCALFOLDER block
ensure_newline_before_comments = true # newline before any inline # comment after an import
###############################################################################
# Ignore junk we never want to touch
###############################################################################
extend_skip = [
".md", ".json", ".yaml", ".yml",
"dist", "build", ".venv", ".tox",
"*.tmp", "*.bak",
]
skip_glob = ["**/__init__.py"] # leave namespace init files alone
# ---- Optional CI toggles ----------------------------------------------------
# check_only = true # dry-run mode: non-zero exit if files would change
# verbose = true # print every file name processed
# case_sensitive = true # treat upper/lowercase differences as significant
[tool.mypy]
# Target Python version
python_version = "3.11"
# Full strictness and individual checks
strict = true # Enable all strict checks
check_untyped_defs = true # Type-check the bodies of untyped functions
no_implicit_optional = true # Require explicit Optional for None default
disallow_untyped_defs = true # Require type annotations for all functions
disallow_untyped_calls = true # Disallow calling functions without type info
disallow_any_unimported = true # Disallow Any from missing imports
warn_return_any = true # Warn if a function returns Any
warn_unreachable = true # Warn about unreachable code
warn_unused_ignores = true # Warn if a "# type: ignore" is unnecessary
warn_unused_configs = true # Warn about unused config options
warn_redundant_casts = true # Warn if a cast does nothing
strict_equality = true # Disallow ==/!= between incompatible types
# Output formatting
show_error_codes = true # Show error codes in output
pretty = true # Format output nicely
# Exclude these paths from analysis
exclude = [
'^build/',
'^\\.venv/',
'^\\.mypy_cache/',
]
[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-ra -q --cov=mcpgateway --ignore=tests/playwright"
testpaths = [ "tests",]
asyncio_mode = "auto"
filterwarnings = [
"ignore:Passing 'msg' argument to .*\\.cancel\\(\\) is deprecated:DeprecationWarning", # From 3rd party libraries
]
# Set environment variables for all tests
env = [
"MCPGATEWAY_ADMIN_API_ENABLED=true",
"MCPGATEWAY_UI_ENABLED=true"
]
# ===== PLAYWRIGHT-SPECIFIC CONFIGURATIONS =====
# Playwright test markers
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"ui: marks tests as UI tests",
"api: marks tests as API tests",
"smoke: marks tests as smoke tests for quick validation",
"e2e: marks tests as end-to-end tests",
]
# Playwright-specific test discovery patterns
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
# Playwright browser configuration (can be overridden via CLI)
# These are custom options that your conftest.py can read
playwright_browser = "chromium" # default browser
playwright_headed = false # run headless by default
playwright_slow_mo = 0 # milliseconds delay between actions
playwright_screenshot = "only-on-failure"
playwright_video = "retain-on-failure"
playwright_trace = "retain-on-failure"
# ── fawltydeps ─────────────────────────────────────────────────────
[tool.fawltydeps]
# only parse main pyproject.toml
deps = ["pyproject.toml"]
# ignore 'dev' extras so they won't show up in fawltydeps
ignore_unused = [
"autoflake",
"argparse-manpage",
"bandit",
"black",
"bump2version",
"check-manifest",
"code2flow",
"cookiecutter",
"coverage",
"coverage-badge",
"darglint",
"flake8",
"fawltydeps",
"gprof2dot",
"gunicorn",
"importchecker",
"isort",
"ty",
"tomlcheck",
"mypy",
"pexpect",
"pip-licenses",
"pip_audit",
"pre-commit",
"pydocstyle",
"pylint",
"pylint-pydantic",
"pyre-check",
"pyright",
"pyroma",
"pyspelling",
"pytest",
"pytest-asyncio",
"pytest-cov",
"pytest-examples",
"pytest-md-report",
"pytest-rerunfailures",
"pytest-xdist",
"pytype",
"radon",
"ruff",
"settings-doc",
"snakeviz",
"types-tabulate",
"twine",
"uvicorn"
]
# --------------------------------------------------------------------
# 🛠 https://github.com/facebook/pyrefly (replaces pyre)
# --------------------------------------------------------------------
[tool.pyrefly]
project-excludes = [
"**/build/",
'**/\.venv/',
'**/\.mypy_cache/',
]
python-version = "3.11.0"