feat(mcp): support MCP Python SDK v2 / spec 2026-07-28 #2909
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| ruff-format: | |
| name: Ruff format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python dev environment | |
| uses: ./.github/actions/setup-python-dev | |
| - name: Check formatting with ruff | |
| run: | | |
| ruff format --check . | |
| ruff-lint: | |
| name: Ruff lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python dev environment | |
| uses: ./.github/actions/setup-python-dev | |
| - name: Lint with ruff | |
| run: | | |
| ruff check . | |
| mypy: | |
| name: Mypy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python dev environment | |
| uses: ./.github/actions/setup-python-dev | |
| - name: Check types with mypy | |
| run: | | |
| mypy --no-site-packages --config-file mypy.ini . | mypy-baseline filter | |
| public-api: | |
| name: Public API snapshot | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Python dev environment | |
| uses: ./.github/actions/setup-python-dev | |
| - name: Check public API snapshot | |
| run: | | |
| python .github/scripts/test_check_public_api.py | |
| make public_api_check | |
| strict-type-smoke: | |
| name: Strict type smoke | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.11.11 | |
| - name: Check strict downstream Pyright usage | |
| run: .github/scripts/check_strict_types.sh | |
| package-build: | |
| name: Package build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.11.11 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| - name: Build and verify distributions | |
| run: | | |
| uv build | |
| uv run --with twine twine check dist/* | |
| tests: | |
| name: Python ${{ matrix.python-version }} tests | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| - name: Install test dependencies | |
| shell: bash | |
| run: | | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --extra test | |
| - name: Run posthog tests | |
| run: | | |
| pytest --verbose --timeout=30 | |
| tests-mcp: | |
| # The MCP suite as a named gate per MCP Python SDK major. The v1 leg uses | |
| # the lockfile's mcp 1.x (also exercised incidentally by the `tests` | |
| # matrix — this leg exists as an explicit, named signal); the v2 leg | |
| # (spec 2026-07-28) swaps in mcp>=2 and drops jlowin fastmcp, which pins | |
| # mcp<2. posthog/test/mcp/conftest.py splits collection by major. | |
| name: MCP SDK ${{ matrix.mcp-major }} (Python ${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.10', '3.14'] | |
| mcp-major: ['v1', 'v2'] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| - name: Install test dependencies | |
| shell: bash | |
| run: | | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --extra test | |
| - name: Swap in MCP SDK v2 | |
| if: matrix.mcp-major == 'v2' | |
| shell: bash | |
| run: | | |
| uv pip uninstall --python $pythonLocation fastmcp | |
| uv pip install --python $pythonLocation 'mcp>=2,<3' | |
| - name: Run MCP tests against SDK ${{ matrix.mcp-major }} | |
| run: | | |
| pytest posthog/test/mcp --verbose --timeout=30 | |
| mutation-tests: | |
| name: Targeted mutation tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check targeted mutation inputs changed | |
| id: changes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| base="${{ github.event.pull_request.base.sha }}" | |
| head="${{ github.event.pull_request.head.sha }}" | |
| else | |
| base="${{ github.event.before }}" | |
| head="${{ github.sha }}" | |
| fi | |
| changed_files="$(git diff --name-only "$base" "$head" -- \ | |
| posthog/utils.py \ | |
| posthog/test/test_utils.py \ | |
| posthog/test/test_size_limited_dict.py)" | |
| if [[ -n "$changed_files" ]]; then | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| echo "Targeted mutation inputs changed:" | |
| echo "$changed_files" | |
| else | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| echo "Skipping targeted mutation tests: inputs unchanged." | |
| fi | |
| - name: Set up Python 3.11 | |
| if: steps.changes.outputs.changed == 'true' | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.11.11 | |
| - name: Install uv | |
| if: steps.changes.outputs.changed == 'true' | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| - name: Check utils CRAP score | |
| if: steps.changes.outputs.changed == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with pytest-crap --with pytest-cov pytest posthog/test/test_utils.py posthog/test/test_size_limited_dict.py --timeout=30 --cov=posthog.utils --crap --crap-threshold=10 --crap-top-n=40 -q | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with pytest-crap --with pytest-cov python .github/scripts/check_crap_threshold.py posthog/utils.py --max-crap 10 | |
| - name: Restore mutmut cache | |
| id: mutmut-cache | |
| if: steps.changes.outputs.changed == 'true' | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: mutants | |
| key: mutmut-${{ runner.os }}-py311-${{ hashFiles('posthog/utils.py', 'posthog/test/test_utils.py', 'posthog/test/test_size_limited_dict.py') }} | |
| restore-keys: | | |
| mutmut-${{ runner.os }}-py311- | |
| - name: Skip mutation tests on exact cache hit | |
| if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit == 'true' | |
| run: | | |
| echo "Skipping targeted mutation tests: exact mutmut cache hit." | |
| - name: Run targeted mutation tests | |
| if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit != 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut run --max-children 1 | |
| results="$(UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut results)" | |
| if [[ -n "$results" ]]; then | |
| echo "$results" | |
| exit 1 | |
| fi | |
| import-check: | |
| name: Python ${{ matrix.python-version }} import check | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install posthog | |
| run: pip install . | |
| - name: Check import produces no warnings | |
| run: python -W error -c "import posthog" | |
| openfeature-provider: | |
| name: OpenFeature provider Python ${{ matrix.python-version }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| # openfeature-provider-posthog is a uv workspace member (declared in | |
| # the root pyproject), so commands are scoped to it with --package and | |
| # builds are pinned to its own dist/ with --out-dir. | |
| - name: Install provider dependencies | |
| shell: bash | |
| working-directory: openfeature-provider | |
| run: | | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --package openfeature-provider-posthog --extra dev | |
| - name: Run provider tests | |
| working-directory: openfeature-provider | |
| run: | | |
| uv run --package openfeature-provider-posthog pytest --verbose | |
| - name: Lint and type-check provider | |
| working-directory: openfeature-provider | |
| run: | | |
| uv run --package openfeature-provider-posthog ruff format --check . | |
| uv run --package openfeature-provider-posthog ruff check . | |
| uv run --package openfeature-provider-posthog mypy . | |
| - name: Build and verify provider distribution | |
| working-directory: openfeature-provider | |
| run: | | |
| uv build --package openfeature-provider-posthog --out-dir dist | |
| uv run --with twine twine check dist/* | |
| - name: Smoke test built wheel in a clean environment | |
| working-directory: openfeature-provider | |
| shell: bash | |
| run: | | |
| uv venv /tmp/of-smoke | |
| uv pip install --python /tmp/of-smoke/bin/python dist/*.whl | |
| /tmp/of-smoke/bin/python -c "from openfeature.contrib.provider.posthog import PostHogProvider; print(PostHogProvider)" | |
| django5-integration: | |
| name: Django 5 integration tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.12 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.32" | |
| enable-cache: true | |
| - name: Install Django 5 test project dependencies | |
| shell: bash | |
| working-directory: integration_tests/django5 | |
| run: | | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync | |
| - name: Run Django 5 middleware integration tests | |
| working-directory: integration_tests/django5 | |
| run: | | |
| uv run pytest test_middleware.py test_exception_capture.py --verbose |