diff --git a/docsgpt/llm/base.py b/docsgpt/llm/base.py index e5b4c55d..38ce6a59 100644 --- a/docsgpt/llm/base.py +++ b/docsgpt/llm/base.py @@ -22,10 +22,10 @@ logger = logging.getLogger(__name__) # retries — RateLimitError needs backoff, BadRequestError won't get any # better on retry, and the existing fallback handles both. # Both HTTP stacks are listed because the providers are split across them and -# the two libraries' exception classes are unrelated types: openai and -# anthropic run on httpx2, while google-genai, elevenlabs, qdrant-client and -# the MCP client are still on httpx. Naming only one silently stops matching -# for half the providers — the retry just never fires. +# the two libraries' exception classes are unrelated types: openai, anthropic +# and the MCP client run on httpx2, while google-genai, elevenlabs, +# qdrant-client and daytona are still on httpx. Naming only one silently stops +# matching for half the providers — the retry just never fires. _TRANSPORT_ERROR_NAMES = ( "RemoteProtocolError", "ReadError", diff --git a/docsgpt/requirements-docling.txt b/docsgpt/requirements-docling.txt index 83daa7ee..133b1b33 100644 --- a/docsgpt/requirements-docling.txt +++ b/docsgpt/requirements-docling.txt @@ -231,9 +231,9 @@ fast-ebook==0.2.0 # via docsgpt fastembed==0.8.0 # via docsgpt -fastmcp==3.4.7 +fastmcp==4.0.3 # via docsgpt -fastmcp-slim==3.4.7 +fastmcp-slim==4.0.3 # via fastmcp filelock==3.32.6 # via @@ -327,20 +327,18 @@ httpx==0.28.1 # daytona # docling-slim # elevenlabs - # fastmcp-slim # google-genai # httpx-ws # huggingface-hub - # mcp # qdrant-client -httpx-sse==0.4.3 - # via mcp httpx-ws==0.9.0 # via daytona httpx2==2.12.0 # via # anthropic # docsgpt + # fastmcp-slim + # mcp # openai httpx2-jsfetch==1.0 ; sys_platform == 'emscripten' # via httpx2 @@ -444,8 +442,12 @@ markupsafe==3.0.3 # werkzeug marshmallow==3.26.2 # via dataclasses-json -mcp==1.30.0 +mcp==2.2.0 # via fastmcp-slim +mcp-types==2.2.0 + # via + # fastmcp-slim + # mcp mdurl==0.1.2 # via markdown-it-py mmh3==5.3.0 @@ -519,6 +521,7 @@ opentelemetry-api==1.44.0 # daytona # fastmcp-slim # google-api-core + # mcp # opentelemetry-distro # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http @@ -734,6 +737,7 @@ pydantic==2.13.5 # fastmcp-slim # google-genai # mcp + # mcp-types # openai # openapi-pydantic # openapi3-parser @@ -749,7 +753,6 @@ pydantic-settings==2.15.0 # docling-slim # docsgpt # fastmcp-slim - # mcp pygments==2.21.0 # via # mpire @@ -1049,6 +1052,7 @@ typing-extensions==4.16.0 # httpx2 # huggingface-hub # mcp + # mcp-types # obstore # openai # opentelemetry-api diff --git a/docsgpt/requirements-milvus.txt b/docsgpt/requirements-milvus.txt index 92fd8465..2c23a51b 100644 --- a/docsgpt/requirements-milvus.txt +++ b/docsgpt/requirements-milvus.txt @@ -193,9 +193,9 @@ fast-ebook==0.2.0 # via docsgpt fastembed==0.8.0 # via docsgpt -fastmcp==3.4.7 +fastmcp==4.0.3 # via docsgpt -fastmcp-slim==3.4.7 +fastmcp-slim==4.0.3 # via fastmcp filelock==3.32.6 # via @@ -285,20 +285,18 @@ httpx==0.28.1 # via # daytona # elevenlabs - # fastmcp-slim # google-genai # httpx-ws # huggingface-hub - # mcp # qdrant-client -httpx-sse==0.4.3 - # via mcp httpx-ws==0.9.0 # via daytona httpx2==2.12.0 # via # anthropic # docsgpt + # fastmcp-slim + # mcp # openai httpx2-jsfetch==1.0 ; sys_platform == 'emscripten' # via httpx2 @@ -386,8 +384,12 @@ markupsafe==3.0.3 # werkzeug marshmallow==3.26.2 # via dataclasses-json -mcp==1.30.0 +mcp==2.2.0 # via fastmcp-slim +mcp-types==2.2.0 + # via + # fastmcp-slim + # mcp mdurl==0.1.2 # via markdown-it-py milvus-lite==3.2.1 ; sys_platform != 'win32' @@ -438,6 +440,7 @@ opentelemetry-api==1.44.0 # daytona # fastmcp-slim # google-api-core + # mcp # opentelemetry-distro # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http @@ -639,6 +642,7 @@ pydantic==2.13.5 # fastmcp-slim # google-genai # mcp + # mcp-types # openai # openapi-pydantic # openapi3-parser @@ -652,7 +656,6 @@ pydantic-settings==2.15.0 # via # docsgpt # fastmcp-slim - # mcp pygments==2.21.0 # via # rich @@ -855,6 +858,7 @@ typing-extensions==4.16.0 # httpx2 # huggingface-hub # mcp + # mcp-types # obstore # openai # opentelemetry-api diff --git a/docsgpt/requirements.txt b/docsgpt/requirements.txt index ef73fe60..7e215825 100644 --- a/docsgpt/requirements.txt +++ b/docsgpt/requirements.txt @@ -189,9 +189,9 @@ fast-ebook==0.2.0 # via docsgpt fastembed==0.8.0 # via docsgpt -fastmcp==3.4.7 +fastmcp==4.0.3 # via docsgpt -fastmcp-slim==3.4.7 +fastmcp-slim==4.0.3 # via fastmcp filelock==3.32.6 # via @@ -279,20 +279,18 @@ httpx==0.28.1 # via # daytona # elevenlabs - # fastmcp-slim # google-genai # httpx-ws # huggingface-hub - # mcp # qdrant-client -httpx-sse==0.4.3 - # via mcp httpx-ws==0.9.0 # via daytona httpx2==2.12.0 # via # anthropic # docsgpt + # fastmcp-slim + # mcp # openai httpx2-jsfetch==1.0 ; sys_platform == 'emscripten' # via httpx2 @@ -380,8 +378,12 @@ markupsafe==3.0.3 # werkzeug marshmallow==3.26.2 # via dataclasses-json -mcp==1.30.0 +mcp==2.2.0 # via fastmcp-slim +mcp-types==2.2.0 + # via + # fastmcp-slim + # mcp mdurl==0.1.2 # via markdown-it-py mmh3==5.3.0 @@ -429,6 +431,7 @@ opentelemetry-api==1.44.0 # daytona # fastmcp-slim # google-api-core + # mcp # opentelemetry-distro # opentelemetry-exporter-otlp-proto-grpc # opentelemetry-exporter-otlp-proto-http @@ -623,6 +626,7 @@ pydantic==2.13.5 # fastmcp-slim # google-genai # mcp + # mcp-types # openai # openapi-pydantic # openapi3-parser @@ -636,7 +640,6 @@ pydantic-settings==2.15.0 # via # docsgpt # fastmcp-slim - # mcp pygments==2.21.0 # via # rich @@ -835,6 +838,7 @@ typing-extensions==4.16.0 # httpx2 # huggingface-hub # mcp + # mcp-types # obstore # openai # opentelemetry-api diff --git a/pyproject.toml b/pyproject.toml index 67c8067a..d987d88c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ dependencies = [ # with no model downloads. The docling engine is the `docling` extra. "firecrawl-anydoc>=0.2.4,<0.3", "fastembed>=0.8.0,<0.9", - "fastmcp>=3.4.6,<4", + "fastmcp>=4.0.3,<5", "Flask>=3.1.3,<4", "flask-restx>=1.3.2,<2", "google-api-python-client>=2.198.0,<3", diff --git a/tests/llm/test_fallback.py b/tests/llm/test_fallback.py index 0aae3d4b..ceba9b65 100644 --- a/tests/llm/test_fallback.py +++ b/tests/llm/test_fallback.py @@ -372,9 +372,10 @@ class TestStreamingFallback: self, patch_model_utils, error ): """The providers are split across two HTTP stacks whose exception - classes are unrelated types: openai and anthropic raise from httpx2, - google-genai and elevenlabs still from httpx. Naming one stack makes - the retry silently stop firing for the other half. + classes are unrelated types: openai, anthropic and the MCP client + raise from httpx2, google-genai and elevenlabs still from httpx. + Naming one stack makes the retry silently stop firing for the other + half. """ backup = FakeLLM(stream_chunks=["fallback"]) patch_model_utils( diff --git a/uv.lock b/uv.lock index ddd2b3ff..fce59b12 100644 --- a/uv.lock +++ b/uv.lock @@ -1467,7 +1467,7 @@ requires-dist = [ { name = "faiss-cpu", specifier = ">=1.15.0,<2" }, { name = "fast-ebook", specifier = ">=0.2.0,<0.3" }, { name = "fastembed", specifier = ">=0.8.0,<0.9" }, - { name = "fastmcp", specifier = ">=3.4.6,<4" }, + { name = "fastmcp", specifier = ">=4.0.3,<5" }, { name = "firecrawl-anydoc", specifier = ">=0.2.4,<0.3" }, { name = "flask", specifier = ">=3.1.3,<4" }, { name = "flask-restx", specifier = ">=1.3.2,<2" }, @@ -1719,21 +1719,22 @@ wheels = [ [[package]] name = "fastmcp" -version = "3.4.7" +version = "4.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastmcp-slim", extra = ["client", "server"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/62/dd/fd444d94ae7afdaf5b6dd168799d34023f576b405872d6a27d5686a9d1f4/fastmcp-3.4.7.tar.gz", hash = "sha256:43117aca886f5ee2f6a569bba91cef02b59c339aad04ba29950ff18d251c822a", size = 28808982, upload-time = "2026-08-10T21:17:55.045Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5d/1a/bee10aff530338f3b8982a3dd1c377c3ba5d0bc724615bf358422c4e9ecf/fastmcp-4.0.3.tar.gz", hash = "sha256:0dd50baf070105ee4436c245f087ac3c047e655c32d9e783de16d0bf15783a98", size = 42311418, upload-time = "2026-09-05T00:31:36.932Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl", hash = "sha256:e4e7698cb4af5bc667b1901685261fa2f3526dc73d243a461fca42500c8dbe56", size = 8016, upload-time = "2026-08-10T21:17:51.391Z" }, + { url = "https://files.pythonhosted.org/packages/e4/cb/66600db497b3be21cf141f01296308169859d48ed9b1bc8ba7c9d83279b7/fastmcp-4.0.3-py3-none-any.whl", hash = "sha256:f743f43193e1daf606e6497a9dddba5bbaad7df7957a98fd093716ecf4458b99", size = 8076, upload-time = "2026-09-05T00:31:33.957Z" }, ] [[package]] name = "fastmcp-slim" -version = "3.4.7" +version = "4.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "mcp-types" }, { name = "platformdirs" }, { name = "pydantic", extra = ["email"] }, { name = "pydantic-settings" }, @@ -1741,16 +1742,16 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/12/ac/7924e803368d0758ee4d6b1259066550df78f58f0f9f8bfebd5a123e957d/fastmcp_slim-3.4.7.tar.gz", hash = "sha256:06b32a358320a7dc2b2ee040ba89ea55ddc20763dff2949f384f7974b13b5d8f", size = 594357, upload-time = "2026-08-10T21:17:28.723Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/a9/b7b796b0d4a5e095dadef233833c82ac1136f5c110dd9947b2e9a4988518/fastmcp_slim-4.0.3.tar.gz", hash = "sha256:3ce04a82b82cc41ccb12bb3bb366cfd65b52bc797b8fee332a75da9d480f9b74", size = 685704, upload-time = "2026-09-05T00:31:12.346Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl", hash = "sha256:6c931a0089705f3f2935428ef9b2bc74ad94140adc64aab84d116d103e694b3a", size = 769370, upload-time = "2026-08-10T21:17:27.227Z" }, + { url = "https://files.pythonhosted.org/packages/43/4b/6b31820d87f56d5773538860878c8634b618cd1e9044b3bfbd8a78380a0f/fastmcp_slim-4.0.3-py3-none-any.whl", hash = "sha256:3756ed4bd9f82f40adaf51974b7cdd1463ab6b9f479cf69b69b2692969312b87", size = 859717, upload-time = "2026-09-05T00:31:10.93Z" }, ] [package.optional-dependencies] client = [ { name = "authlib" }, { name = "exceptiongroup" }, - { name = "httpx" }, + { name = "httpx2" }, { name = "mcp" }, { name = "opentelemetry-api" }, { name = "py-key-value-aio", extra = ["filetree", "keyring", "memory"] }, @@ -1761,7 +1762,7 @@ server = [ { name = "cyclopts" }, { name = "exceptiongroup" }, { name = "griffelib" }, - { name = "httpx" }, + { name = "httpx2" }, { name = "joserfc" }, { name = "jsonref" }, { name = "jsonschema-path" }, @@ -2380,15 +2381,6 @@ http2 = [ { name = "h2" }, ] -[[package]] -name = "httpx-sse" -version = "0.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, -] - [[package]] name = "httpx-ws" version = "0.9.0" @@ -3051,15 +3043,15 @@ wheels = [ [[package]] name = "mcp" -version = "1.30.0" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "httpx" }, - { name = "httpx-sse" }, + { name = "httpx2" }, { name = "jsonschema" }, + { name = "mcp-types" }, + { name = "opentelemetry-api" }, { name = "pydantic" }, - { name = "pydantic-settings" }, { name = "pyjwt", extra = ["crypto"] }, { name = "python-multipart" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, @@ -3069,9 +3061,22 @@ dependencies = [ { name = "typing-inspection" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/93/0142dc84a666daf8ad51a34268f34c12fd6fda4f3810c4be2504eecc8212/mcp-1.30.0.tar.gz", hash = "sha256:445414625fce5c295faa505bb11bacece661ab6f4028d57c935db57820b7a3e4", size = 680511, upload-time = "2026-09-07T14:34:15.845Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/31/ac54fb0fdd5b37de704486e288bba4fbbb463f24cfcfedbede407b854513/mcp-2.2.0.tar.gz", hash = "sha256:2dc37ecb1974becdcebdbf7561e7c15a07dbbf20ba21ba16c3593b3038b3afbd", size = 4084129, upload-time = "2026-09-07T16:06:23.439Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl", hash = "sha256:666edb5009503e1047c9d60346a756f94b261f05cc2625f23d41c728ffc484d0", size = 234581, upload-time = "2026-09-07T14:34:14.266Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl", hash = "sha256:bde982589473a060ae145e3406e9a5333fe538c97229ba841f5a7f92be004f81", size = 365656, upload-time = "2026-09-07T16:06:19.711Z" }, +] + +[[package]] +name = "mcp-types" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/91/762d7755d971aff8a28d75f7961656148edf27875c8026e6385aaab08ae7/mcp_types-2.2.0.tar.gz", hash = "sha256:d3ed53703ddd10d9c6399f29d322bb66f3f67ab41348ac8556ba23e07fedefad", size = 65892, upload-time = "2026-09-07T16:06:25.187Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl", hash = "sha256:ea476b73ee86709ab5abc9452385ed36cc05907e582355622e294595c9a04f13", size = 69106, upload-time = "2026-09-07T16:06:21.461Z" }, ] [[package]]