pmcp 2.4.0

High-quality Rust SDK for Model Context Protocol (MCP) with full TypeScript SDK compatibility
Documentation
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  # Override .cargo/config.toml target-cpu=native to avoid SIGILL on CI runners
  RUSTFLAGS: ""

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6

    - name: Free Disk Space
      uses: jlumbroso/free-disk-space@main
      with:
        # Remove large packages we don't need
        tool-cache: false
        android: true
        dotnet: true
        haskell: true
        large-packages: true
        docker-images: true
        swap-storage: true

    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        components: rustfmt, clippy, llvm-tools-preview
    
    - name: Cache cargo
      uses: actions/cache@v5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Install cargo-llvm-cov
      run: |
        if ! command -v cargo-llvm-cov &> /dev/null; then
          cargo install cargo-llvm-cov
        fi
    
    - name: Format check
      run: cargo fmt --all -- --check
    
    - name: Clippy
      run: |
        cargo clippy --all-targets --all-features -- \
          -D warnings \
          -A clippy::module_name_repetitions \
          -A clippy::must_use_candidate \
          -A clippy::missing_errors_doc \
          -A clippy::missing_const_for_fn \
          -A clippy::return_self_not_must_use \
          -A clippy::missing_fields_in_debug \
          -A clippy::uninlined_format_args \
          -A clippy::if_not_else \
          -A clippy::result_large_err \
          -A clippy::multiple_crate_versions \
          -A clippy::implicit_hasher \
          -A clippy::unused_async \
          -A clippy::cast_lossless \
          -A clippy::redundant_clone \
          -A clippy::redundant_closure_for_method_calls \
          -A clippy::significant_drop_tightening \
          -A clippy::missing_panics_doc \
          -A clippy::cast_possible_truncation \
          -A clippy::cast_precision_loss \
          -A clippy::option_if_let_else \
          -A clippy::derive_partial_eq_without_eq \
          -A clippy::redundant_else \
          -A clippy::match_same_arms
    
    - name: Build
      run: cargo build --all-features --verbose
    
    - name: Run tests
      run: cargo test --all-features --verbose -- --test-threads=1
    
    - name: Run doctests
      run: cargo test --doc --all-features --verbose
    
    - name: Check examples
      run: |
        # Build every registered example with its declared required-features.
        # Reading required-features from cargo metadata keeps this in sync with
        # Cargo.toml automatically, so future renames or feature changes don't
        # require workflow edits.
        cargo metadata --no-deps --format-version 1 \
          | python3 -c '
        import json, sys
        meta = json.load(sys.stdin)
        pkg = next(p for p in meta["packages"] if p["name"] == "pmcp")
        for t in pkg["targets"]:
            if "example" in t["kind"]:
                feats = ",".join(t.get("required-features") or [])
                print(f"{t[\"name\"]}|{feats}")
        ' | while IFS='|' read -r name feats; do
            if [[ -n "$feats" ]]; then
              echo "Checking example: $name (features: $feats)"
              cargo check --example "$name" --features "$feats"
            else
              echo "Checking example: $name (no required features)"
              cargo check --example "$name" --features http
            fi
          done

    - name: Clean up before coverage
      run: |
        echo "Disk usage before cleanup:"
        df -h
        echo "Cleaning cargo build artifacts..."
        cargo clean
        echo "Disk usage after cleanup:"
        df -h

    - name: Run coverage
      run: cargo llvm-cov --all-features --lcov --output-path lcov.info

  feature-flags:
    name: Feature Flag Verification
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6

    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        components: clippy

    - name: Cache cargo
      uses: actions/cache@v5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-cargo-feature-flags-${{ hashFiles('**/Cargo.lock') }}

    - name: Verify feature flag combinations
      run: make test-feature-flags

  quality-gate:
    name: Quality Gate
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6

    - name: Free Disk Space
      uses: jlumbroso/free-disk-space@main
      with:
        # Remove large packages we don't need
        tool-cache: false
        android: true
        dotnet: true
        haskell: true
        large-packages: true
        docker-images: true
        swap-storage: true

    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        components: rustfmt, clippy
    
    - name: Cache cargo
      uses: actions/cache@v5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
        key: ${{ runner.os }}-cargo-quality-${{ hashFiles('**/Cargo.lock') }}

    - name: Install quality tools
      run: |
        if ! command -v cargo-llvm-cov &> /dev/null; then
          cargo install cargo-llvm-cov
        fi
        if ! command -v cargo-nextest &> /dev/null; then
          cargo install cargo-nextest
        fi
        # Force install latest cargo-audit to support CVSS 4.0
        cargo install cargo-audit --force

    - name: Check disk space before quality gate
      run: df -h

    - name: Check rustdoc zero-warnings
      run: make doc-check

    - name: Run quality gate
      run: make quality-gate

    - name: Check disk space after quality gate
      run: df -h

  benchmarks:
    name: Benchmarks
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    
    - name: Cache cargo
      uses: actions/cache@v5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Run benchmarks
      run: cargo bench --all-features --no-run

  msrv:
    name: Minimum Supported Rust Version (1.82)
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    
    - name: Install Rust 1.82
      uses: dtolnay/rust-toolchain@1.82
    
    - name: Cache cargo
      uses: actions/cache@v5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-cargo-msrv-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Check MSRV
      run: cargo check --all-features

  # Unified gate — single required check for org ruleset.
  # Reports as "gate" to match the org ruleset's required status check.
  gate:
    runs-on: ubuntu-latest
    needs: [test, quality-gate]
    if: always()
    steps:
      - name: Evaluate required checks
        env:
          TEST_RESULT: ${{ needs.test.result }}
          QG_RESULT: ${{ needs.quality-gate.result }}
        run: |
          if [[ "$TEST_RESULT" != "success" ]] || \
             [[ "$QG_RESULT" != "success" ]]; then
            echo "Required checks failed: test=$TEST_RESULT, quality-gate=$QG_RESULT"
            exit 1
          fi
          echo "All required checks passed."