Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
eebc76c
fix(deps): correct minimum versions for supported Python releases
joshua-berri Sep 18, 2026
3519d01
test(mcp): add isolated SDK2 dependency compatibility gate
joshua-berri Sep 18, 2026
0a87dc6
ci(deps): run wheel installation gates in GitHub Actions
joshua-berri Sep 18, 2026
1dbcf31
ci(mcp): run isolated dependency gates in GitHub Actions
joshua-berri Sep 18, 2026
c19b5c5
ci(deps): document pinned action versions
joshua-berri Sep 18, 2026
b42e282
ci(mcp): document pinned workflow action versions
joshua-berri Sep 18, 2026
6aa921c
fix(ci): run dependency tests in an isolated Python environment
joshua-berri Sep 18, 2026
21beb9b
fix(ci): verify coverage uploads and normalize dependency inventories
joshua-berri Sep 18, 2026
dfd0474
fix(ci): preserve repository paths in dependency coverage reports
joshua-berri Sep 18, 2026
4bc3f1d
build(deps): migrate MCP integration to MCP SDK 2.2.0
joshua-berri Sep 18, 2026
5dc0131
refactor(mcp): port MCP client and server helpers to MCP SDK 2
joshua-berri Sep 18, 2026
545bbeb
test(mcp): update MCP suites for SDK 2 APIs
joshua-berri Sep 18, 2026
7830380
refactor(mcp): register SDK2 request handlers and drop request_ctx Co…
joshua-berri Sep 18, 2026
0d2963f
test(mcp): update MCP suites for SDK2 handler signatures and ctx var
joshua-berri Sep 18, 2026
8d8a2c3
ci(mcp): add dependency-resolution workflow for the SDK 2 floor
joshua-berri Sep 18, 2026
8d8efe7
style(mcp): satisfy lint and type budgets for the SDK 2 port
joshua-berri Sep 18, 2026
7410d00
merge(main): resolve mcp server.py import conflict and relock
joshua-berri Sep 19, 2026
4a7d8bb
fix(mcp): resolve SDK2 wire-shape regressions in guardrail, arize, an…
joshua-berri Sep 19, 2026
a873ead
test(mcp): read SDK2 snake_case fields on CallToolResult
joshua-berri Sep 19, 2026
77cf6c2
ci(mcp): keep dependency-resolution matrix to resolve and import smoke
joshua-berri Sep 19, 2026
aea13ee
fix(mcp): preserve legacy behavior on SDK2 and streamline verification
joshua-berri Sep 19, 2026
f5ab563
fix(mcp): preserve session expiry signals and scope dependency CI
joshua-berri Sep 19, 2026
c91ca90
fix(mcp): retain wire aliases in guardrail inspection payloads
joshua-berri Sep 19, 2026
fb56a14
chore(mcp): merge main with unit test timeout safeguards
joshua-berri Sep 19, 2026
8f3562e
ci(mcp): consolidate integration tests into shared workflow
joshua-berri Sep 19, 2026
78e1103
fix(ci): preserve shared runner setup time allowance
joshua-berri Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .circleci/scripts/classify_changes.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#!/usr/bin/env bash
set -uo pipefail

category="${1:?usage: classify_changes.sh <backend|client|ui|provider-harness|cost-map-only>}"
category="${1:?usage: classify_changes.sh <backend|client|ui|provider-harness|cost-map-only|mcp-dependencies>}"

has_client=false
has_backend=false
has_ci=false
has_provider_harness=false
has_cost_map=false
has_mcp_dependencies=false
outside_cost_map_set=false
while IFS= read -r file || [ -n "$file" ]; do
[ -n "$file" ] || continue
case "$file" in
*.md | *.mdx) : ;;
pyproject.toml | */pyproject.toml | uv.lock | uv.toml | .python-version | rust-toolchain.toml | litellm-rust/* | litellm/__init__.py | litellm/proxy/proxy_server.py | litellm/*mcp* | tests/*mcp* | litellm/integrations/arize/* | tests/base_sdk_tests/* | scripts/check_mcp_sdk_install.py | .github/workflows/test-mcp-dependency-resolution.yml | .github/actions/detect-changes/* | .github/actions/setup-uv-with-retries/* | .github/actions/cache-cargo-build/* | .github/scripts/detect_changes.sh | .github/scripts/uv_sync_with_retries.sh | .circleci/scripts/classify_changes.sh | tests/test_litellm/test_circleci_path_filter.py | tests/test_litellm/test_detect_changes.py)
has_mcp_dependencies=true ;;
esac
case "$file" in
tests/e2e/*/*.py) : ;;
tests/e2e/*.py | tests/code_coverage_tests/test_provider_cache.py | tests/code_coverage_tests/test_provider_replay_harness.py | tests/test_litellm/test_circleci_path_filter.py | .circleci/* | pyproject.toml | uv.lock)
Expand All @@ -31,6 +37,9 @@ while IFS= read -r file || [ -n "$file" ]; do
done

case "$category" in
mcp-dependencies)
[ "$has_mcp_dependencies" = true ] && echo run || echo skip
;;
cost-map-only)
{ [ "$has_cost_map" = true ] && [ "$outside_cost_map_set" = false ]; } && echo run || echo skip
;;
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/detect-changes/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ description: >-

inputs:
category:
description: "Which classification to apply: backend, client or ui"
description: "Which classification to apply: backend, client, ui, provider-harness, cost-map-only or mcp-dependencies"
required: false
default: backend
github-token:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
uv run --frozen --no-default-groups
--with pytest==8.3.5
--with pytest-codspeed==4.3.0
--with "mcp>=1.26.0,<2.0"
--with "mcp>=2.2.0,<3.0"
--with "a2a-sdk>=1.1.0,<2.0"
pytest
-p pytest_codspeed.plugin
Expand All @@ -86,7 +86,7 @@ jobs:
uv run --frozen --no-default-groups
--with pytest==8.3.5
--with pytest-codspeed==4.3.0
--with "mcp>=1.26.0,<2.0"
--with "mcp>=2.2.0,<3.0"
--with "a2a-sdk>=1.1.0,<2.0"
pytest
-p pytest_codspeed.plugin
Expand Down
98 changes: 98 additions & 0 deletions .github/workflows/test-mcp-dependency-resolution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: LiteLLM MCP Dependency Resolution

on:
pull_request:
branches:
- main
- litellm_internal_staging
- litellm_oss_staging
- "litellm_**"

permissions:
contents: read
pull-requests: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
resolve:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false

- name: Detect relevant changes
id: changes
uses: ./.github/actions/detect-changes
with:
category: mcp-dependencies

- name: Set up Python
if: steps.changes.outputs.decision != 'skip'
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: ${{ matrix.python-version }}

- name: Set up uv
if: steps.changes.outputs.decision != 'skip'
uses: ./.github/actions/setup-uv-with-retries
with:
version: "0.10.9"

- name: Cache the Rust build
if: steps.changes.outputs.decision != 'skip'
uses: ./.github/actions/cache-cargo-build

- name: Verify lockfile
if: steps.changes.outputs.decision != 'skip'
run: |
uv lock --check

- name: Check locked runtime installations
if: steps.changes.outputs.decision != 'skip'
run: |
for extra in core mcp proxy; do
args=()
if [ "$extra" != core ]; then args=(--extra "$extra"); fi
UV_PROJECT_ENVIRONMENT=".venv-$extra" .github/scripts/uv_sync_with_retries.sh --frozen --no-dev --no-editable --python ${{ matrix.python-version }} "${args[@]}"
uv pip check --python ".venv-$extra"
if [ "$extra" = core ]; then
checker=("$GITHUB_WORKSPACE/tests/base_sdk_tests/check_base_sdk_install.py")
else
checker=("$GITHUB_WORKSPACE/scripts/check_mcp_sdk_install.py" --extra "$extra")
fi
(cd "$RUNNER_TEMP" && "$GITHUB_WORKSPACE/.venv-$extra/bin/python" "${checker[@]}")
done

- name: Build the public wheel
if: steps.changes.outputs.decision != 'skip'
run: uv build --all-packages --wheel --out-dir dist/mcp-check

- name: Check lowest direct runtime installations
if: steps.changes.outputs.decision != 'skip'
run: |
wheel=$(realpath dist/mcp-check/litellm-[0-9]*.whl)
for extra in core mcp proxy; do
args=()
if [ "$extra" != core ]; then args=(--extra "$extra"); fi
uv pip compile pyproject.toml --no-sources --find-links dist/mcp-check "${args[@]}" --python-version ${{ matrix.python-version }} --resolution lowest-direct -o "lowest-$extra.txt"
uv venv --python ${{ matrix.python-version }} ".venv-lowest-$extra"
uv pip sync --find-links dist/mcp-check --python ".venv-lowest-$extra" "lowest-$extra.txt"
uv pip install --python ".venv-lowest-$extra" --no-deps "$wheel"
uv pip check --python ".venv-lowest-$extra"
if [ "$extra" = core ]; then
checker=("$GITHUB_WORKSPACE/tests/base_sdk_tests/check_base_sdk_install.py")
else
checker=("$GITHUB_WORKSPACE/scripts/check_mcp_sdk_install.py" --extra "$extra")
fi
(cd "$RUNNER_TEMP" && "$GITHUB_WORKSPACE/.venv-lowest-$extra/bin/python" "${checker[@]}")
done
7 changes: 7 additions & 0 deletions .github/workflows/test-mcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ jobs:
uv lock --check
.github/scripts/uv_sync_with_retries.sh --frozen --group proxy-dev --extra proxy --extra semantic-router

- name: Install the unchanged SDK1 peer
if: steps.changes.outputs.decision != 'skip'
run: |
uv venv --python 3.12 .venv-mcp-peer
uv pip install --python .venv-mcp-peer 'mcp==1.28.1' 'langchain-mcp-adapters==0.2.1'
echo "MCP_TEST_PEER_PYTHON=$GITHUB_WORKSPACE/.venv-mcp-peer/bin/python" >> "$GITHUB_ENV"

- name: Run MCP tests
if: steps.changes.outputs.decision != 'skip'
run: |
Expand Down
11 changes: 10 additions & 1 deletion litellm/experimental_mcp_client/Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# LiteLLM MCP Client

LiteLLM MCP Client is a client that allows you to use MCP tools with LiteLLM.
LiteLLM MCP Client allows you to use MCP tools with LiteLLM

## MCP Python SDK compatibility

The `mcp` and `proxy` extras require MCP Python SDK 2.2 or newer within the 2.x release line. Installing core LiteLLM without these extras does not require MCP

Existing MCP SDK1 clients can continue connecting to the gateway over the supported legacy MCP protocols. The client and gateway can use different SDK versions in separate Python environments. Modern protocol advertisement remains disabled during the Phase 0 upgrade. An initialize body requesting `2026-07-28` falls back to the supported legacy version `2025-11-25`; an explicit `MCP-Protocol-Version: 2026-07-28` HTTP header is rejected with HTTP 400

Code sharing the gateway's Python environment must support SDK2. Its Python API has breaking changes, including renamed imports and snake_case model attributes such as `input_schema`, `is_error`, and `structured_content`. This also applies to callers consuming SDK objects returned by LiteLLM's experimental MCP client. MCP JSON fields retain their protocol spelling, such as `inputSchema` and `isError`

Upgrade SDK1-dependent libraries before installing them alongside `litellm[mcp]` or `litellm[proxy]`, or keep those clients in a separate environment and connect over the network. For example, `langchain-mcp-adapters==0.2.1` uses SDK1 Python APIs and is tested as a separate legacy client, not as a shared SDK2 dependency

See the official [SDK migration guide](https://py.sdk.modelcontextprotocol.io/migration/) for Python API changes
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved
Loading
Loading