From 6a3b375e7d30d26d1d59fc6db4aea8ac8afc9460 Mon Sep 17 00:00:00 2001 From: Ashir Amin Date: Wed, 23 Sep 2026 08:29:16 -0500 Subject: [PATCH 1/3] Upgrade to fastmcp 4.0.5 fastmcp 4 URL-encodes OpenAPI path parameters, which removes the path-traversal vector at the source (COR2-475) rather than guarding against it. The migration is import moves only -- the OpenAPI types were relocated, not changed: MCPType and the OpenAPI component classes now live in fastmcp.server.providers.openapi, HTTPRoute in fastmcp.utilities.openapi.models. Both callback signatures are unchanged, so custom_route_mapper and customize_components keep their bodies. fastmcp 4 moves to httpx2; applications call httpx2.alias_httpx() once at startup so existing `import httpx` code shares the httpx2 classes. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LZtC15RMphgMhtsoDh4i4u --- pyproject.toml | 4 ++-- src/components/customizers.py | 4 ++-- src/routes/mappers.py | 3 ++- tests/test_components.py | 2 +- tests/test_routes.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bbf12a8..67b3582 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,8 +23,8 @@ classifiers = [ "Programming Language :: Python :: 3.13" ] dependencies = [ - "fastmcp==2.12.3", # Pin to exact version to fix PublicIdentifier schema bug - "httpx>=0.25.0", + "fastmcp==4.0.5", + "httpx2>=2.13", "pydantic>=2.0.0", ] diff --git a/src/components/customizers.py b/src/components/customizers.py index dd2ccca..33ee728 100644 --- a/src/components/customizers.py +++ b/src/components/customizers.py @@ -1,11 +1,11 @@ """Component customization for MCP server.""" -from fastmcp.server.openapi import ( - HTTPRoute, +from fastmcp.server.providers.openapi import ( OpenAPIResource, OpenAPIResourceTemplate, OpenAPITool, ) +from fastmcp.utilities.openapi.models import HTTPRoute from ..utils.logging import get_logger diff --git a/src/routes/mappers.py b/src/routes/mappers.py index c893014..e52523a 100644 --- a/src/routes/mappers.py +++ b/src/routes/mappers.py @@ -1,6 +1,7 @@ """Route mapping logic for MCP server.""" -from fastmcp.server.openapi import HTTPRoute, MCPType +from fastmcp.server.providers.openapi import MCPType +from fastmcp.utilities.openapi.models import HTTPRoute from ..utils.logging import get_logger diff --git a/tests/test_components.py b/tests/test_components.py index d34e572..fad3f0c 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -1,7 +1,7 @@ """Tests for component customization.""" from unittest.mock import Mock -from fastmcp.server.openapi import OpenAPIResource, OpenAPIResourceTemplate, OpenAPITool +from fastmcp.server.providers.openapi import OpenAPIResource, OpenAPIResourceTemplate, OpenAPITool from src.components.customizers import customize_components diff --git a/tests/test_routes.py b/tests/test_routes.py index 65938b2..97127cb 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,7 +1,7 @@ """Tests for route mapping logic.""" from unittest.mock import Mock -from fastmcp.server.openapi import MCPType +from fastmcp.server.providers.openapi import MCPType from src.routes.mappers import custom_route_mapper From e25c807c4a513545df4122ed41de605568946f36 Mon Sep 17 00:00:00 2001 From: Ashir Amin Date: Wed, 23 Sep 2026 09:44:49 -0500 Subject: [PATCH 2/3] Import httpx2 explicitly instead of relying on a caller's alias The previous commit swapped the httpx dependency for httpx2 but left `import httpx` in src/clients/cortex.py, working only because the downstream application called httpx2.alias_httpx() first. That broke cortex-mcp as a standalone package -- its own console script and Dockerfile entry point import that module directly: ModuleNotFoundError: No module named 'httpx' The tests did not catch it because none of them import src.clients.cortex. httpx2's alias_httpx() is documented for applications, not libraries, and cortex-mcp is imported as a library by cortex-remote-mcp. Import httpx2 under the httpx name in this module instead, so the package is correct on its own and no longer depends on import ordering elsewhere. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LZtC15RMphgMhtsoDh4i4u --- src/clients/cortex.py | 2 +- src/utils/logging.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clients/cortex.py b/src/clients/cortex.py index d0746d3..712225f 100644 --- a/src/clients/cortex.py +++ b/src/clients/cortex.py @@ -1,6 +1,6 @@ """Cortex API client configuration.""" -import httpx +import httpx2 as httpx from ..config import Config from ..utils.logging import get_logger diff --git a/src/utils/logging.py b/src/utils/logging.py index a2fe5c2..abd3db7 100644 --- a/src/utils/logging.py +++ b/src/utils/logging.py @@ -26,7 +26,7 @@ def setup_logging(log_level: str | None = None) -> logging.Logger: ) if not Config.DEBUG: - logging.getLogger("httpx").setLevel(logging.WARNING) + logging.getLogger("httpx2").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING) logging.getLogger("langchain").setLevel(logging.INFO) logging.getLogger("langchain_community").setLevel(logging.INFO) From a20b3d42cc5919f2a95a556f0116b341f1795229 Mon Sep 17 00:00:00 2001 From: Ashir Amin Date: Wed, 23 Sep 2026 10:05:24 -0500 Subject: [PATCH 3/3] Wrap the migrated import to satisfy ruff The import-path migration left a line ruff's isort rule wants split; CI runs `ruff check src tests` and failed on it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LZtC15RMphgMhtsoDh4i4u --- tests/test_components.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_components.py b/tests/test_components.py index fad3f0c..db5beb7 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -1,7 +1,11 @@ """Tests for component customization.""" from unittest.mock import Mock -from fastmcp.server.providers.openapi import OpenAPIResource, OpenAPIResourceTemplate, OpenAPITool +from fastmcp.server.providers.openapi import ( + OpenAPIResource, + OpenAPIResourceTemplate, + OpenAPITool, +) from src.components.customizers import customize_components