From 12a92b0900d9bf22bd72c1b301c639086ae9c927 Mon Sep 17 00:00:00 2001 From: Tony Deng Date: Fri, 16 Oct 2026 21:40:37 +0000 Subject: [PATCH 1/5] fix: constrain Pydantic for the oldest MCP compatibility test --- .github/scripts/run_integration_tests.py | 6 +++- tests/test_integration_runner.py | 44 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/.github/scripts/run_integration_tests.py b/.github/scripts/run_integration_tests.py index 90627d1386..2e2ed9be6d 100644 --- a/.github/scripts/run_integration_tests.py +++ b/.github/scripts/run_integration_tests.py @@ -488,10 +488,14 @@ def main() -> None: if args.profile == "mcp-v1": for mcp_version in ("1.19.0", "1.29.0"): environment_kind = f"mcp-v1-{mcp_version}" + requirements = (f"mcp=={mcp_version}",) + if mcp_version == "1.19.0": + # MCP 1.19.0 imports eval_type_backport, removed in Pydantic 2.14. + requirements += ("pydantic<2.14",) python = create_environment( environment_kind, wheel, - additional_requirements=(f"mcp=={mcp_version}",), + additional_requirements=requirements, ) run_suite( python, diff --git a/tests/test_integration_runner.py b/tests/test_integration_runner.py index 9ce940aefa..bc3cf90c3e 100644 --- a/tests/test_integration_runner.py +++ b/tests/test_integration_runner.py @@ -582,6 +582,50 @@ def test_extra_collection_deselects_only_non_applicable_memory_backends( assert deselected == [non_applicable] +def test_mcp_v1_profile_isolates_legacy_pydantic_constraint( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + namespace = runpy.run_path(str(RUNNER)) + main = cast(Callable[[], None], namespace["main"]) + created: list[tuple[str, tuple[str, ...]]] = [] + suites: list[dict[str, Any]] = [] + + def fake_create_environment( + name: str, + distribution: Path, + *, + additional_requirements: tuple[str, ...] = (), + ) -> Path: + _ = distribution + created.append((name, additional_requirements)) + return tmp_path / name / "python" + + monkeypatch.setattr(sys, "argv", [str(RUNNER), "--profile", "mcp-v1"]) + monkeypatch.setitem( + main.__globals__, + "build_distributions", + lambda: (tmp_path / "candidate.whl", tmp_path / "candidate.tar.gz"), + ) + monkeypatch.setitem(main.__globals__, "create_environment", fake_create_environment) + monkeypatch.setitem( + main.__globals__, "run_suite", lambda *args, **kwargs: suites.append(kwargs) + ) + monkeypatch.setattr(main.__globals__["shutil"], "rmtree", lambda *args, **kwargs: None) + + main() + + assert created == [ + ("mcp-v1-1.19.0", ("mcp==1.19.0", "pydantic<2.14")), + ("mcp-v1-1.29.0", ("mcp==1.29.0",)), + ] + assert [suite["selection"] for suite in suites] == ["mcp_compat", "mcp_compat"] + assert [suite["additional_env"] for suite in suites] == [ + {"OPENAI_AGENTS_INTEGRATION_MCP_VERSION": "1.19.0"}, + {"OPENAI_AGENTS_INTEGRATION_MCP_VERSION": "1.29.0"}, + ] + + def test_packaging_profile_checks_dependency_present_contract_for_wheel_and_sdist( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, From ac9c46df6b902e04ceeab9250b280451d8ebbc0f Mon Sep 17 00:00:00 2001 From: td Date: Fri, 16 Oct 2026 15:03:04 -0700 Subject: [PATCH 2/5] fix: enforce MCP-compatible Pydantic in package metadata --- .github/scripts/run_integration_tests.py | 6 +-- .../packaging/test_mcp_compat.py | 14 ++++++ pyproject.toml | 3 +- tests/test_integration_runner.py | 44 ------------------- uv.lock | 2 +- 5 files changed, 18 insertions(+), 51 deletions(-) diff --git a/.github/scripts/run_integration_tests.py b/.github/scripts/run_integration_tests.py index 2e2ed9be6d..90627d1386 100644 --- a/.github/scripts/run_integration_tests.py +++ b/.github/scripts/run_integration_tests.py @@ -488,14 +488,10 @@ def main() -> None: if args.profile == "mcp-v1": for mcp_version in ("1.19.0", "1.29.0"): environment_kind = f"mcp-v1-{mcp_version}" - requirements = (f"mcp=={mcp_version}",) - if mcp_version == "1.19.0": - # MCP 1.19.0 imports eval_type_backport, removed in Pydantic 2.14. - requirements += ("pydantic<2.14",) python = create_environment( environment_kind, wheel, - additional_requirements=requirements, + additional_requirements=(f"mcp=={mcp_version}",), ) run_suite( python, diff --git a/integration_tests/packaging/test_mcp_compat.py b/integration_tests/packaging/test_mcp_compat.py index 50ca59b358..2563271141 100644 --- a/integration_tests/packaging/test_mcp_compat.py +++ b/integration_tests/packaging/test_mcp_compat.py @@ -7,6 +7,7 @@ from unittest.mock import MagicMock, patch import pytest +from packaging.requirements import Requirement from agents.mcp import MCPServerSse, MCPServerStdio, MCPServerStreamableHttp @@ -15,6 +16,19 @@ LEGACY_SERVER_PATH = Path(__file__).with_name("mcp_legacy_server.py") +def test_package_metadata_excludes_incompatible_pydantic() -> None: + requirements = [ + Requirement(value) for value in importlib.metadata.requires("openai-agents") or [] + ] + pydantic = next(requirement for requirement in requirements if requirement.name == "pydantic") + + assert "2.12.2" in pydantic.specifier + assert "2.13.5" in pydantic.specifier + assert "2.14.0" not in pydantic.specifier + assert "2.14.1" not in pydantic.specifier + assert importlib.metadata.version("pydantic") in pydantic.specifier + + @pytest.mark.asyncio async def test_packaged_client_supports_mcp_v1() -> None: expected_version = os.environ["OPENAI_AGENTS_INTEGRATION_MCP_VERSION"] diff --git a/pyproject.toml b/pyproject.toml index 2fda55bf0d..b261231caa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,8 @@ license = "MIT" authors = [{ name = "OpenAI", email = "support@openai.com" }] dependencies = [ "openai>=3.0.0,<4", - "pydantic>=2.12.2, <3", + # MCP 1.19.0 imports eval_type_backport, removed in Pydantic 2.14. + "pydantic>=2.12.2, <2.14", "griffelib>=2, <3", "typing-extensions>=4.12.2, <5", "requests>=2.0, <3", diff --git a/tests/test_integration_runner.py b/tests/test_integration_runner.py index bc3cf90c3e..9ce940aefa 100644 --- a/tests/test_integration_runner.py +++ b/tests/test_integration_runner.py @@ -582,50 +582,6 @@ def test_extra_collection_deselects_only_non_applicable_memory_backends( assert deselected == [non_applicable] -def test_mcp_v1_profile_isolates_legacy_pydantic_constraint( - monkeypatch: pytest.MonkeyPatch, - tmp_path: Path, -) -> None: - namespace = runpy.run_path(str(RUNNER)) - main = cast(Callable[[], None], namespace["main"]) - created: list[tuple[str, tuple[str, ...]]] = [] - suites: list[dict[str, Any]] = [] - - def fake_create_environment( - name: str, - distribution: Path, - *, - additional_requirements: tuple[str, ...] = (), - ) -> Path: - _ = distribution - created.append((name, additional_requirements)) - return tmp_path / name / "python" - - monkeypatch.setattr(sys, "argv", [str(RUNNER), "--profile", "mcp-v1"]) - monkeypatch.setitem( - main.__globals__, - "build_distributions", - lambda: (tmp_path / "candidate.whl", tmp_path / "candidate.tar.gz"), - ) - monkeypatch.setitem(main.__globals__, "create_environment", fake_create_environment) - monkeypatch.setitem( - main.__globals__, "run_suite", lambda *args, **kwargs: suites.append(kwargs) - ) - monkeypatch.setattr(main.__globals__["shutil"], "rmtree", lambda *args, **kwargs: None) - - main() - - assert created == [ - ("mcp-v1-1.19.0", ("mcp==1.19.0", "pydantic<2.14")), - ("mcp-v1-1.29.0", ("mcp==1.29.0",)), - ] - assert [suite["selection"] for suite in suites] == ["mcp_compat", "mcp_compat"] - assert [suite["additional_env"] for suite in suites] == [ - {"OPENAI_AGENTS_INTEGRATION_MCP_VERSION": "1.19.0"}, - {"OPENAI_AGENTS_INTEGRATION_MCP_VERSION": "1.29.0"}, - ] - - def test_packaging_profile_checks_dependency_present_contract_for_wheel_and_sdist( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, diff --git a/uv.lock b/uv.lock index 412e6374dc..e2349fa146 100644 --- a/uv.lock +++ b/uv.lock @@ -2914,7 +2914,7 @@ requires-dist = [ { name = "protobuf", marker = "extra == 'e2b'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, { name = "protobuf", marker = "extra == 'modal'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, { name = "protobuf", marker = "extra == 'temporal'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, - { name = "pydantic", specifier = ">=2.12.2,<3" }, + { name = "pydantic", specifier = ">=2.12.2,<2.14" }, { name = "pygments", marker = "python_full_version >= '3.11' and extra == 'any-llm'", specifier = ">=2.20.0" }, { name = "pygments", marker = "extra == 'e2b'", specifier = ">=2.20.0" }, { name = "pygments", marker = "extra == 'modal'", specifier = ">=2.20.0" }, From 69eef10bd4b26a49ed078b24987d44923f5fab17 Mon Sep 17 00:00:00 2001 From: td Date: Fri, 16 Oct 2026 15:52:59 -0700 Subject: [PATCH 3/5] fix: raise MCP minimum to 1.21.1 and retain current Pydantic support --- .github/scripts/run_integration_tests.py | 2 +- integration_tests/packaging/test_mcp_compat.py | 11 ++++++++--- pyproject.toml | 5 ++--- uv.lock | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/scripts/run_integration_tests.py b/.github/scripts/run_integration_tests.py index 90627d1386..406c97b271 100644 --- a/.github/scripts/run_integration_tests.py +++ b/.github/scripts/run_integration_tests.py @@ -486,7 +486,7 @@ def main() -> None: print(f"[integration] wheel={wheel.name} sdist={sdist.name} profile={args.profile}") if args.profile == "mcp-v1": - for mcp_version in ("1.19.0", "1.29.0"): + for mcp_version in ("1.21.1", "1.29.0"): environment_kind = f"mcp-v1-{mcp_version}" python = create_environment( environment_kind, diff --git a/integration_tests/packaging/test_mcp_compat.py b/integration_tests/packaging/test_mcp_compat.py index 2563271141..92ee348283 100644 --- a/integration_tests/packaging/test_mcp_compat.py +++ b/integration_tests/packaging/test_mcp_compat.py @@ -16,7 +16,7 @@ LEGACY_SERVER_PATH = Path(__file__).with_name("mcp_legacy_server.py") -def test_package_metadata_excludes_incompatible_pydantic() -> None: +def test_package_metadata_requires_fixed_mcp_and_allows_current_pydantic() -> None: requirements = [ Requirement(value) for value in importlib.metadata.requires("openai-agents") or [] ] @@ -24,8 +24,13 @@ def test_package_metadata_excludes_incompatible_pydantic() -> None: assert "2.12.2" in pydantic.specifier assert "2.13.5" in pydantic.specifier - assert "2.14.0" not in pydantic.specifier - assert "2.14.1" not in pydantic.specifier + assert "2.14.0" in pydantic.specifier + assert "2.14.1" in pydantic.specifier + mcp = next(requirement for requirement in requirements if requirement.name == "mcp") + assert "1.21.0" not in mcp.specifier + assert "1.21.1" in mcp.specifier + assert "1.29.0" in mcp.specifier + assert importlib.metadata.version("mcp") in mcp.specifier assert importlib.metadata.version("pydantic") in pydantic.specifier diff --git a/pyproject.toml b/pyproject.toml index b261231caa..74945f70cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,13 +8,12 @@ license = "MIT" authors = [{ name = "OpenAI", email = "support@openai.com" }] dependencies = [ "openai>=3.0.0,<4", - # MCP 1.19.0 imports eval_type_backport, removed in Pydantic 2.14. - "pydantic>=2.12.2, <2.14", + "pydantic>=2.12.2, <3", "griffelib>=2, <3", "typing-extensions>=4.12.2, <5", "requests>=2.0, <3", "websockets>=15.0, <17", - "mcp>=1.19.0, <3; python_version >= '3.10'", + "mcp>=1.21.1, <3; python_version >= '3.10'", # Security floors for transitive runtime dependencies. "httpx2>=2.12.0", "pyjwt>=2.15.0", diff --git a/uv.lock b/uv.lock index e2349fa146..81ceadd3ac 100644 --- a/uv.lock +++ b/uv.lock @@ -2905,7 +2905,7 @@ requires-dist = [ { name = "h2", marker = "extra == 'modal'", specifier = ">=4.4.1" }, { name = "httpx2", specifier = ">=2.12.0" }, { name = "litellm", marker = "extra == 'litellm'", specifier = ">=1.83.0" }, - { name = "mcp", marker = "python_full_version >= '3.10'", specifier = ">=1.19.0,<3" }, + { name = "mcp", marker = "python_full_version >= '3.10'", specifier = ">=1.21.1,<3" }, { name = "modal", marker = "extra == 'modal'", specifier = "==1.4.3" }, { name = "numpy", marker = "python_full_version >= '3.10' and extra == 'voice'", specifier = ">=2.2.0,<3" }, { name = "openai", specifier = ">=3.0.0,<4" }, @@ -2914,7 +2914,7 @@ requires-dist = [ { name = "protobuf", marker = "extra == 'e2b'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, { name = "protobuf", marker = "extra == 'modal'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, { name = "protobuf", marker = "extra == 'temporal'", specifier = ">=5.29.6,!=6.30.*,!=6.31.*,!=6.32.*,!=6.33.0.*,!=6.33.1.*,!=6.33.2.*,!=6.33.3.*,!=6.33.4.*" }, - { name = "pydantic", specifier = ">=2.12.2,<2.14" }, + { name = "pydantic", specifier = ">=2.12.2,<3" }, { name = "pygments", marker = "python_full_version >= '3.11' and extra == 'any-llm'", specifier = ">=2.20.0" }, { name = "pygments", marker = "extra == 'e2b'", specifier = ">=2.20.0" }, { name = "pygments", marker = "extra == 'modal'", specifier = ">=2.20.0" }, From ecbf68c34af5b060682b124f5cd172d9e515886f Mon Sep 17 00:00:00 2001 From: td Date: Mon, 19 Oct 2026 09:23:50 -0700 Subject: [PATCH 4/5] fix: raise MCP minimum to 1.21.2 for the OAuth scope hotfix --- .github/scripts/run_integration_tests.py | 2 +- integration_tests/packaging/test_mcp_compat.py | 4 ++-- pyproject.toml | 2 +- uv.lock | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/scripts/run_integration_tests.py b/.github/scripts/run_integration_tests.py index 406c97b271..9062826d66 100644 --- a/.github/scripts/run_integration_tests.py +++ b/.github/scripts/run_integration_tests.py @@ -486,7 +486,7 @@ def main() -> None: print(f"[integration] wheel={wheel.name} sdist={sdist.name} profile={args.profile}") if args.profile == "mcp-v1": - for mcp_version in ("1.21.1", "1.29.0"): + for mcp_version in ("1.21.2", "1.29.0"): environment_kind = f"mcp-v1-{mcp_version}" python = create_environment( environment_kind, diff --git a/integration_tests/packaging/test_mcp_compat.py b/integration_tests/packaging/test_mcp_compat.py index 92ee348283..2bf5a8c42d 100644 --- a/integration_tests/packaging/test_mcp_compat.py +++ b/integration_tests/packaging/test_mcp_compat.py @@ -27,8 +27,8 @@ def test_package_metadata_requires_fixed_mcp_and_allows_current_pydantic() -> No assert "2.14.0" in pydantic.specifier assert "2.14.1" in pydantic.specifier mcp = next(requirement for requirement in requirements if requirement.name == "mcp") - assert "1.21.0" not in mcp.specifier - assert "1.21.1" in mcp.specifier + assert "1.21.1" not in mcp.specifier + assert "1.21.2" in mcp.specifier assert "1.29.0" in mcp.specifier assert importlib.metadata.version("mcp") in mcp.specifier assert importlib.metadata.version("pydantic") in pydantic.specifier diff --git a/pyproject.toml b/pyproject.toml index 74945f70cd..cabbce26bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "typing-extensions>=4.12.2, <5", "requests>=2.0, <3", "websockets>=15.0, <17", - "mcp>=1.21.1, <3; python_version >= '3.10'", + "mcp>=1.21.2, <3; python_version >= '3.10'", # Security floors for transitive runtime dependencies. "httpx2>=2.12.0", "pyjwt>=2.15.0", diff --git a/uv.lock b/uv.lock index 81ceadd3ac..90d4ea4dc0 100644 --- a/uv.lock +++ b/uv.lock @@ -2905,7 +2905,7 @@ requires-dist = [ { name = "h2", marker = "extra == 'modal'", specifier = ">=4.4.1" }, { name = "httpx2", specifier = ">=2.12.0" }, { name = "litellm", marker = "extra == 'litellm'", specifier = ">=1.83.0" }, - { name = "mcp", marker = "python_full_version >= '3.10'", specifier = ">=1.21.1,<3" }, + { name = "mcp", marker = "python_full_version >= '3.10'", specifier = ">=1.21.2,<3" }, { name = "modal", marker = "extra == 'modal'", specifier = "==1.4.3" }, { name = "numpy", marker = "python_full_version >= '3.10' and extra == 'voice'", specifier = ">=2.2.0,<3" }, { name = "openai", specifier = ">=3.0.0,<4" }, From f22eb5591062b32eeb3bde09df09940a40c81c48 Mon Sep 17 00:00:00 2001 From: td Date: Mon, 19 Oct 2026 09:45:26 -0700 Subject: [PATCH 5/5] test: simplify MCP minimum coverage and document version choice --- .github/scripts/run_integration_tests.py | 1 + .../packaging/test_mcp_compat.py | 19 ------------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/scripts/run_integration_tests.py b/.github/scripts/run_integration_tests.py index 9062826d66..2e5513eb87 100644 --- a/.github/scripts/run_integration_tests.py +++ b/.github/scripts/run_integration_tests.py @@ -486,6 +486,7 @@ def main() -> None: print(f"[integration] wheel={wheel.name} sdist={sdist.name} profile={args.profile}") if args.profile == "mcp-v1": + # MCP 1.21.2 includes the Pydantic 2.14 import fix and the OAuth 401 scope hotfix. for mcp_version in ("1.21.2", "1.29.0"): environment_kind = f"mcp-v1-{mcp_version}" python = create_environment( diff --git a/integration_tests/packaging/test_mcp_compat.py b/integration_tests/packaging/test_mcp_compat.py index 2bf5a8c42d..50ca59b358 100644 --- a/integration_tests/packaging/test_mcp_compat.py +++ b/integration_tests/packaging/test_mcp_compat.py @@ -7,7 +7,6 @@ from unittest.mock import MagicMock, patch import pytest -from packaging.requirements import Requirement from agents.mcp import MCPServerSse, MCPServerStdio, MCPServerStreamableHttp @@ -16,24 +15,6 @@ LEGACY_SERVER_PATH = Path(__file__).with_name("mcp_legacy_server.py") -def test_package_metadata_requires_fixed_mcp_and_allows_current_pydantic() -> None: - requirements = [ - Requirement(value) for value in importlib.metadata.requires("openai-agents") or [] - ] - pydantic = next(requirement for requirement in requirements if requirement.name == "pydantic") - - assert "2.12.2" in pydantic.specifier - assert "2.13.5" in pydantic.specifier - assert "2.14.0" in pydantic.specifier - assert "2.14.1" in pydantic.specifier - mcp = next(requirement for requirement in requirements if requirement.name == "mcp") - assert "1.21.1" not in mcp.specifier - assert "1.21.2" in mcp.specifier - assert "1.29.0" in mcp.specifier - assert importlib.metadata.version("mcp") in mcp.specifier - assert importlib.metadata.version("pydantic") in pydantic.specifier - - @pytest.mark.asyncio async def test_packaged_client_supports_mcp_v1() -> None: expected_version = os.environ["OPENAI_AGENTS_INTEGRATION_MCP_VERSION"]