mcp-use 1.3.2__tar.gz → 1.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcp-use might be problematic. Click here for more details.

Files changed (150) hide show
  1. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/publish.yml +4 -5
  2. {mcp_use-1.3.2 → mcp_use-1.3.3}/PKG-INFO +3 -2
  3. {mcp_use-1.3.2 → mcp_use-1.3.3}/pyproject.toml +3 -2
  4. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/sse/test_connection_state_tracking.py +23 -127
  5. mcp_use-1.3.2/tests/integration/servers_for_testing/long_timeout_test_server.py +0 -171
  6. {mcp_use-1.3.2 → mcp_use-1.3.3}/.env.example +0 -0
  7. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  8. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/pull_request_template.md +0 -0
  9. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/release-drafter.yml +0 -0
  10. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/changelog.yml +0 -0
  11. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/claude.yml +0 -0
  12. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/release-drafter.yml +0 -0
  13. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/transportstests.yml +0 -0
  14. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/unittests.yml +0 -0
  15. {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/update-readme.yml +0 -0
  16. {mcp_use-1.3.2 → mcp_use-1.3.3}/.gitignore +0 -0
  17. {mcp_use-1.3.2 → mcp_use-1.3.3}/.pre-commit-config.yaml +0 -0
  18. {mcp_use-1.3.2 → mcp_use-1.3.3}/CHANGELOG.md +0 -0
  19. {mcp_use-1.3.2 → mcp_use-1.3.3}/CLAUDE.md +0 -0
  20. {mcp_use-1.3.2 → mcp_use-1.3.3}/CODE_OF_CONDUCT.md +0 -0
  21. {mcp_use-1.3.2 → mcp_use-1.3.3}/CONTRIBUTING.md +0 -0
  22. {mcp_use-1.3.2 → mcp_use-1.3.3}/LICENSE +0 -0
  23. {mcp_use-1.3.2 → mcp_use-1.3.3}/README.md +0 -0
  24. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/README.md +0 -0
  25. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/adapters.mdx +0 -0
  26. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/introduction.mdx +0 -0
  27. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/mcpagent.mdx +0 -0
  28. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/mcpclient.mdx +0 -0
  29. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/changelog.mdx +0 -0
  30. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/community/showcase.mdx +0 -0
  31. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development/observability.mdx +0 -0
  32. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development/telemetry.mdx +0 -0
  33. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development.mdx +0 -0
  34. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/docs.json +0 -0
  35. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/agent-configuration.mdx +0 -0
  36. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/client-configuration.mdx +0 -0
  37. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/configuration.mdx +0 -0
  38. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/connection-types.mdx +0 -0
  39. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/llm-integration.mdx +0 -0
  40. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/server-manager.mdx +0 -0
  41. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/favicon.svg +0 -0
  42. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/fonts.css +0 -0
  43. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/building-custom-agents.mdx +0 -0
  44. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/logging.mdx +0 -0
  45. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/multi-server-setup.mdx +0 -0
  46. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/security.mdx +0 -0
  47. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/streaming.mdx +0 -0
  48. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/01.png +0 -0
  49. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/02.png +0 -0
  50. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/configuration-dark.png +0 -0
  51. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/configuration-light.png +0 -0
  52. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/examples-dark.png +0 -0
  53. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/examples-light.png +0 -0
  54. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/hero-dark.png +0 -0
  55. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/hero-light.png +0 -0
  56. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/installation-dark.png +0 -0
  57. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/installation-light.png +0 -0
  58. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/quickstart-dark.png +0 -0
  59. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/quickstart-light.png +0 -0
  60. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/index.mdx +0 -0
  61. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/installation.mdx +0 -0
  62. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/dark.svg +0 -0
  63. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/light.svg +0 -0
  64. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/react.svg +0 -0
  65. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/quickstart.mdx +0 -0
  66. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/snippets/snippet-intro.mdx +0 -0
  67. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/snippets/youtube-embed.mdx +0 -0
  68. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/common-issues.mdx +0 -0
  69. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/connection-errors.mdx +0 -0
  70. {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/performance.mdx +0 -0
  71. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/airbnb_mcp.json +0 -0
  72. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/airbnb_use.py +0 -0
  73. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/blender_use.py +0 -0
  74. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/browser_mcp.json +0 -0
  75. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/browser_use.py +0 -0
  76. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/chat_example.py +0 -0
  77. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/filesystem_use.py +0 -0
  78. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/http_example.py +0 -0
  79. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/mcp_everything.py +0 -0
  80. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/multi_server_example.py +0 -0
  81. {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/sandbox_everything.py +0 -0
  82. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/__init__.py +0 -0
  83. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/__init__.py +0 -0
  84. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/base.py +0 -0
  85. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/langchain_adapter.py +0 -0
  86. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/__init__.py +0 -0
  87. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/base.py +0 -0
  88. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/mcpagent.py +0 -0
  89. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/prompts/system_prompt_builder.py +0 -0
  90. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/prompts/templates.py +0 -0
  91. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/client.py +0 -0
  92. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/config.py +0 -0
  93. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/__init__.py +0 -0
  94. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/base.py +0 -0
  95. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/http.py +0 -0
  96. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/sandbox.py +0 -0
  97. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/stdio.py +0 -0
  98. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/utils.py +0 -0
  99. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/websocket.py +0 -0
  100. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/logging.py +0 -0
  101. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/__init__.py +0 -0
  102. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/server_manager.py +0 -0
  103. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/__init__.py +0 -0
  104. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/base_tool.py +0 -0
  105. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/connect_server.py +0 -0
  106. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/disconnect_server.py +0 -0
  107. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/get_active_server.py +0 -0
  108. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/list_servers_tool.py +0 -0
  109. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/search_tools.py +0 -0
  110. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/use_tool.py +0 -0
  111. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/__init__.py +0 -0
  112. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/laminar.py +0 -0
  113. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/langfuse.py +0 -0
  114. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/session.py +0 -0
  115. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/__init__.py +0 -0
  116. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/base.py +0 -0
  117. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/sse.py +0 -0
  118. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/stdio.py +0 -0
  119. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/streamable_http.py +0 -0
  120. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/websocket.py +0 -0
  121. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/__init__.py +0 -0
  122. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/events.py +0 -0
  123. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/telemetry.py +0 -0
  124. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/utils.py +0 -0
  125. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/types/sandbox.py +0 -0
  126. {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/utils.py +0 -0
  127. {mcp_use-1.3.2 → mcp_use-1.3.3}/pytest.ini +0 -0
  128. {mcp_use-1.3.2 → mcp_use-1.3.3}/ruff.toml +0 -0
  129. {mcp_use-1.3.2 → mcp_use-1.3.3}/static/logo_black.svg +0 -0
  130. {mcp_use-1.3.2 → mcp_use-1.3.3}/static/logo_white.svg +0 -0
  131. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/conftest.py +0 -0
  132. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/__init__.py +0 -0
  133. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/__init__.py +0 -0
  134. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/custom_streaming_server.py +0 -0
  135. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/simple_server.py +0 -0
  136. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/timeout_test_server.py +0 -0
  137. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/customStreaming/__init__.py +0 -0
  138. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/customStreaming/test_custom_streaming_integration.py +0 -0
  139. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/sse/test_sse_integration.py +0 -0
  140. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/stdio/test_stdio_integration.py +0 -0
  141. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/streamableHttp/test_streamable_http_integration.py +0 -0
  142. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_client.py +0 -0
  143. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_config.py +0 -0
  144. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_http_connector.py +0 -0
  145. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_logging.py +0 -0
  146. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_sandbox_connector.py +0 -0
  147. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_search_tools_issue_138.py +0 -0
  148. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_session.py +0 -0
  149. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_stdio_connector.py +0 -0
  150. {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_websocket_connection_manager.py +0 -0
@@ -2,9 +2,8 @@ name: Release
2
2
 
3
3
  on:
4
4
  workflow_run:
5
- workflows: ["Python Tests"]
6
- branches:
7
- - main
5
+ workflows: ["Python Tests", "Transports"]
6
+ branches: [main]
8
7
  types:
9
8
  - completed
10
9
 
@@ -15,9 +14,8 @@ permissions:
15
14
 
16
15
  jobs:
17
16
  check-version-and-publish:
18
- # Only proceed if the referenced workflow completed successfully
19
- if: ${{ github.event.workflow_run.conclusion == 'success' }}
20
17
  runs-on: ubuntu-latest
18
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
21
19
  steps:
22
20
  - uses: actions/checkout@v3
23
21
  with:
@@ -73,6 +71,7 @@ jobs:
73
71
  draft: false
74
72
  prerelease: false
75
73
  generateReleaseNotes: false
74
+ omitBodyDuringUpdate: true
76
75
 
77
76
  - name: Publish to PyPI
78
77
  if: steps.check-version.outputs.is_new_version == 'true'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-use
3
- Version: 1.3.2
3
+ Version: 1.3.3
4
4
  Summary: MCP Library for LLMs
5
5
  Author-email: Pietro Zullo <pietro.zullo@gmail.com>
6
6
  License: MIT
@@ -34,7 +34,8 @@ Provides-Extra: anthropic
34
34
  Requires-Dist: langchain-anthropic; extra == 'anthropic'
35
35
  Provides-Extra: dev
36
36
  Requires-Dist: black>=23.9.0; extra == 'dev'
37
- Requires-Dist: fastmcp; extra == 'dev'
37
+ Requires-Dist: fastapi; extra == 'dev'
38
+ Requires-Dist: fastmcp==2.8.0; extra == 'dev'
38
39
  Requires-Dist: isort>=5.12.0; extra == 'dev'
39
40
  Requires-Dist: mypy>=1.5.0; extra == 'dev'
40
41
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mcp-use"
3
- version = "1.3.2"
3
+ version = "1.3.3"
4
4
  description = "MCP Library for LLMs"
5
5
  authors = [
6
6
  {name = "Pietro Zullo", email = "pietro.zullo@gmail.com"}
@@ -46,7 +46,8 @@ dev = [
46
46
  "isort>=5.12.0",
47
47
  "mypy>=1.5.0",
48
48
  "ruff>=0.1.0",
49
- "fastmcp",
49
+ "fastmcp==2.8.0",
50
+ "fastapi",
50
51
  ]
51
52
  anthropic = [
52
53
  "langchain_anthropic",
@@ -53,48 +53,13 @@ async def timeout_server_process():
53
53
  print("Timeout test server cleanup complete")
54
54
 
55
55
 
56
- @pytest.fixture
57
- async def long_timeout_server_process():
58
- """Start a server that closes connections after 30+ seconds to match issue reproduction steps"""
59
- server_path = Path(__file__).parent.parent.parent / "servers_for_testing" / "long_timeout_test_server.py"
60
-
61
- print(f"Starting long timeout test server: python {server_path}")
62
-
63
- # Start the server process
64
- process = subprocess.Popen(
65
- ["python", str(server_path)],
66
- cwd=str(server_path.parent),
67
- stdout=subprocess.PIPE,
68
- stderr=subprocess.STDOUT,
69
- text=True,
70
- )
71
-
72
- # Give the server time to start
73
- await asyncio.sleep(2)
74
- server_url = "http://127.0.0.1:8082"
75
- yield server_url
76
-
77
- # Cleanup
78
- print("Cleaning up long timeout test server process")
79
- if process.poll() is None:
80
- process.terminate()
81
- try:
82
- process.wait(timeout=10)
83
- except subprocess.TimeoutExpired:
84
- print("Process didn't terminate gracefully, killing it")
85
- process.kill()
86
- process.wait()
87
-
88
- print("Long timeout test server cleanup complete")
89
-
90
-
91
56
  @pytest.mark.asyncio
92
- async def test_github_issue_120_fixed_behavior(long_timeout_server_process):
57
+ async def test_github_issue_120_fixed_behavior(timeout_server_process):
93
58
  """Test that GitHub issue #120 is fixed: connection state properly tracked and auto-reconnection works"""
94
- server_url = long_timeout_server_process
59
+ server_url = timeout_server_process
95
60
 
96
- # Step 1: Create an HttpConnector with SSE endpoint configuration with auto_connect enabled
97
- config = {"mcpServers": {"fixTest": {"url": f"{server_url}/sse", "auto_connect": True}}}
61
+ # Step 1: Create an HttpConnector with SSE endpoint configuration
62
+ config = {"mcpServers": {"fixTest": {"url": f"{server_url}/sse"}}}
98
63
 
99
64
  client = MCPClient(config=config)
100
65
  try:
@@ -121,11 +86,11 @@ async def test_github_issue_120_fixed_behavior(long_timeout_server_process):
121
86
  print("✓ Tool call succeeded while connected")
122
87
 
123
88
  # Step 3: Wait for 30+ seconds for the server to close the SSE connection due to inactivity
124
- print("Waiting for server timeout (35 seconds)...")
125
- await asyncio.sleep(35)
89
+ print("Waiting for server timeout (10 seconds)...")
90
+ await asyncio.sleep(10)
126
91
 
127
92
  # Step 4: Check connection state - should now properly detect disconnection
128
- print(f"Connection state after 35 second timeout: {session.is_connected}")
93
+ print(f"Connection state after 10 second timeout: {session.is_connected}")
129
94
 
130
95
  # With the fix, is_connected should properly detect the disconnection
131
96
  # But since auto_connect is enabled, it might auto-reconnect on the next call
@@ -164,12 +129,12 @@ async def test_github_issue_120_fixed_behavior(long_timeout_server_process):
164
129
 
165
130
 
166
131
  @pytest.mark.asyncio
167
- async def test_github_issue_120_auto_connect_disabled(long_timeout_server_process):
168
- """Test GitHub issue #120 fix with auto_connect disabled - should provide clear error messages"""
169
- server_url = long_timeout_server_process
132
+ async def test_github_issue_120_manual_connection(timeout_server_process):
133
+ """Test GitHub issue #120 fix with manual connection - should provide clear error messages"""
134
+ server_url = timeout_server_process
170
135
 
171
- # Create connector with auto_connect disabled
172
- config = {"mcpServers": {"noAutoTest": {"url": f"{server_url}/sse", "auto_connect": False}}}
136
+ # Create connector and test manual connection behavior
137
+ config = {"mcpServers": {"noAutoTest": {"url": f"{server_url}/sse"}}}
173
138
 
174
139
  client = MCPClient(config=config)
175
140
  try:
@@ -188,7 +153,7 @@ async def test_github_issue_120_auto_connect_disabled(long_timeout_server_proces
188
153
  assert len(tools) > 0, "Should have at least one tool"
189
154
  test_tool = tools[0]
190
155
 
191
- print(f"Initial connection established (auto_connect=False), testing tool: {test_tool.name}")
156
+ print(f"Initial connection established (manual connection), testing tool: {test_tool.name}")
192
157
  print(f"is_connected: {session.is_connected}")
193
158
 
194
159
  # Verify tool works initially
@@ -197,14 +162,14 @@ async def test_github_issue_120_auto_connect_disabled(long_timeout_server_proces
197
162
  print("✓ Tool call succeeded while connected")
198
163
 
199
164
  # Wait for server timeout
200
- print("Waiting for server timeout (35 seconds) with auto_connect=False...")
201
- await asyncio.sleep(35)
165
+ print("Waiting for server timeout (10 seconds)...")
166
+ await asyncio.sleep(10)
202
167
 
203
168
  # Check connection state after timeout
204
- print(f"Connection state after 35 second timeout (auto_connect=False): {session.is_connected}")
169
+ print(f"Connection state after 10 second timeout: {session.is_connected}")
205
170
 
206
- # Attempt to call a tool - should fail with clear error message since auto_connect is disabled
207
- print("Attempting tool call after timeout (auto_connect=False)...")
171
+ # Attempt to call a tool - should either auto-reconnect or fail with clear error message
172
+ print("Attempting tool call after timeout...")
208
173
  try:
209
174
  result2 = await session.connector.call_tool(test_tool.name, {})
210
175
  # If this succeeds, the connection may still be active or there's an issue
@@ -219,77 +184,15 @@ async def test_github_issue_120_auto_connect_disabled(long_timeout_server_proces
219
184
 
220
185
  # With the fix, we should get a clear error message about connection loss
221
186
  assert error_msg != "", "Error message should not be empty (GitHub Issue #120 fixed)"
222
- assert "connection" in error_msg.lower() and (
223
- "lost" in error_msg.lower() or "manual" in error_msg.lower()
224
- ), "Error message should clearly indicate connection loss and need for manual reconnection"
225
- print("✓ Clear error message provided for connection loss with auto_connect disabled")
187
+ assert "connection" in error_msg.lower(), "Error message should mention connection issues"
188
+ print(" Clear error message provided for connection loss")
226
189
  except Exception as e:
227
190
  error_msg = str(e)
228
191
  print(f"Tool call failed with exception: {type(e).__name__}: '{error_msg}'")
229
192
  # Any error should have a clear message
230
193
  assert error_msg != "", "Error message should not be empty"
231
194
 
232
- print("✓ GitHub Issue #120 fix verified with auto_connect=False - clear error messages")
233
-
234
- finally:
235
- await client.close_all_sessions()
236
-
237
-
238
- @pytest.mark.asyncio
239
- async def test_connection_state_after_server_timeout(timeout_server_process):
240
- """Test that connection state is properly tracked when server closes connection due to timeout"""
241
- server_url = timeout_server_process
242
- config = {"mcpServers": {"timeoutTest": {"url": f"{server_url}/sse", "auto_connect": True}}}
243
-
244
- client = MCPClient(config=config)
245
- try:
246
- # Establish initial connection
247
- await client.create_all_sessions()
248
- session = client.get_session("timeoutTest")
249
-
250
- assert session is not None, "Session should be created"
251
- await session.initialize()
252
- assert session.is_connected, "Session should be connected after initialize"
253
-
254
- # Get a tool to call later
255
- tools = session.connector.tools
256
- assert len(tools) > 0, "Should have at least one tool"
257
- test_tool = tools[0]
258
-
259
- print(f"Initial connection established, testing tool: {test_tool.name}")
260
-
261
- # Call tool successfully while connected
262
- result1 = await session.connector.call_tool(test_tool.name, {})
263
- assert result1 is not None, "Tool call should succeed while connected"
264
- print("✓ Tool call succeeded while connected")
265
-
266
- # Wait for server timeout (server should close connection after 5 seconds)
267
- print("Waiting for server timeout...")
268
- await asyncio.sleep(8)
269
-
270
- # After the fix, check connection state behavior
271
- print(f"Connection state after timeout: {session.is_connected}")
272
-
273
- # Try to call tool after timeout
274
- try:
275
- result2 = await session.connector.call_tool(test_tool.name, {})
276
- if result2 is not None:
277
- print("✓ Tool call succeeded - auto-reconnection worked")
278
- else:
279
- print("⚠ Tool call returned None")
280
- except RuntimeError as e:
281
- error_msg = str(e)
282
- print(f"Tool call failed with clear error: {error_msg}")
283
-
284
- # Check that we get a clear error message (not empty)
285
- assert error_msg != "", "Error message should not be empty (GitHub Issue #120 fixed)"
286
- print("✓ Clear error message provided instead of empty error")
287
- except Exception as e:
288
- error_msg = str(e)
289
- print(f"Tool call failed with exception: {type(e).__name__}: {error_msg}")
290
- assert error_msg != "", "Error message should not be empty"
291
-
292
- print("✓ Connection state properly tracked after server timeout")
195
+ print("✓ GitHub Issue #120 fix verified - clear error messages")
293
196
 
294
197
  finally:
295
198
  await client.close_all_sessions()
@@ -299,14 +202,7 @@ async def test_connection_state_after_server_timeout(timeout_server_process):
299
202
  async def test_connection_manager_task_detection(timeout_server_process):
300
203
  """Test that connection manager task completion is properly detected"""
301
204
  server_url = timeout_server_process
302
- config = {
303
- "mcpServers": {
304
- "timeoutTest": {
305
- "url": f"{server_url}/sse",
306
- "auto_connect": False, # Disable auto_connect to test state detection
307
- }
308
- }
309
- }
205
+ config = {"mcpServers": {"timeoutTest": {"url": f"{server_url}/sse"}}}
310
206
 
311
207
  client = MCPClient(config=config)
312
208
  try:
@@ -351,7 +247,7 @@ async def test_connection_manager_task_detection(timeout_server_process):
351
247
  async def test_multiple_reconnection_attempts(timeout_server_process):
352
248
  """Test that auto-reconnection works multiple times"""
353
249
  server_url = timeout_server_process
354
- config = {"mcpServers": {"timeoutTest": {"url": f"{server_url}/sse", "auto_connect": True}}}
250
+ config = {"mcpServers": {"timeoutTest": {"url": f"{server_url}/sse"}}}
355
251
 
356
252
  client = MCPClient(config=config)
357
253
  try:
@@ -1,171 +0,0 @@
1
- """
2
- Long Timeout Test Server for GitHub Issue #120
3
-
4
- This server specifically tests the connection state tracking issue by:
5
- 1. Accepting SSE connections
6
- 2. Closing them after 30+ seconds to simulate real server-side timeouts
7
- 3. Providing basic MCP tools to test functionality
8
- 4. Matching the exact reproduction steps from the GitHub issue
9
- """
10
-
11
- import asyncio
12
- import json
13
- import time
14
- from datetime import datetime
15
- from typing import Any
16
-
17
- from fastmcp import FastMCP
18
-
19
- # Create FastMCP server instance
20
- mcp = FastMCP(name="LongTimeoutTestServer")
21
-
22
- # Track connection times for timeout logic
23
- connection_times: dict[str, float] = {}
24
-
25
-
26
- @mcp.tool()
27
- def ping() -> dict[str, Any]:
28
- """Simple ping tool for testing connectivity"""
29
- return {"message": "pong", "timestamp": datetime.now().isoformat(), "server": "LongTimeoutTestServer"}
30
-
31
-
32
- @mcp.tool()
33
- def get_server_info() -> dict[str, Any]:
34
- """Get server information"""
35
- return {
36
- "name": "LongTimeoutTestServer",
37
- "purpose": "Testing connection timeouts for issue #120 with 30+ seconds",
38
- "timeout_seconds": 30,
39
- "timestamp": datetime.now().isoformat(),
40
- }
41
-
42
-
43
- @mcp.tool()
44
- def echo(message: str) -> dict[str, Any]:
45
- """Echo a message back"""
46
- return {"original_message": message, "echo": f"Server received: {message}", "timestamp": datetime.now().isoformat()}
47
-
48
-
49
- @mcp.resource("test://server/status")
50
- def server_status_resource() -> str:
51
- """Server status as a resource"""
52
- status = {"status": "running", "active_connections": len(connection_times), "timestamp": datetime.now().isoformat()}
53
- return json.dumps(status, indent=2)
54
-
55
-
56
- @mcp.prompt()
57
- def test_prompt() -> str:
58
- """A simple test prompt"""
59
- return f"""This is a test prompt from LongTimeoutTestServer.
60
-
61
- Current time: {datetime.now().isoformat()}
62
- Server purpose: Testing connection timeouts for GitHub issue #120 with 30+ second timeout
63
-
64
- Please use this server to test:
65
- 1. Connection establishment
66
- 2. Tool calls while connected
67
- 3. Connection state after 30+ second server timeout
68
- 4. Auto-reconnection behavior after long timeouts
69
- """
70
-
71
-
72
- # Custom SSE endpoint with 30+ second timeout logic
73
- @mcp.custom_route("/sse", methods=["GET"])
74
- async def custom_sse_endpoint(request):
75
- """Custom SSE endpoint that closes connections after 30+ seconds to match issue #120"""
76
- import uuid
77
-
78
- from fastapi.responses import StreamingResponse
79
-
80
- # Generate unique connection ID
81
- connection_id = str(uuid.uuid4())
82
- connection_times[connection_id] = time.time()
83
-
84
- print(f"New SSE connection: {connection_id}")
85
-
86
- async def event_generator():
87
- try:
88
- # Send initial connection event
89
- yield f"data: {json.dumps({'type': 'connection', 'id': connection_id, 'status': 'connected'})}\n\n"
90
-
91
- start_time = time.time()
92
- timeout_seconds = 30 # Close connection after 30 seconds to match issue reproduction
93
-
94
- heartbeat_count = 0
95
- while True:
96
- current_time = time.time()
97
-
98
- # Check if we should timeout
99
- if current_time - start_time > timeout_seconds:
100
- print(f"Timing out connection {connection_id} after {timeout_seconds} seconds")
101
- # Send timeout event before closing
102
- timeout_event = {
103
- "type": "timeout",
104
- "id": connection_id,
105
- "message": "Connection timed out after 30 seconds",
106
- }
107
- yield f"data: {json.dumps(timeout_event)}\n\n"
108
- break
109
-
110
- # Send periodic heartbeat every 5 seconds
111
- if heartbeat_count % 5 == 0:
112
- heartbeat_event = {
113
- "type": "heartbeat",
114
- "timestamp": datetime.now().isoformat(),
115
- "elapsed": int(current_time - start_time),
116
- }
117
- yield f"data: {json.dumps(heartbeat_event)}\n\n"
118
-
119
- await asyncio.sleep(1)
120
- heartbeat_count += 1
121
-
122
- except Exception as e:
123
- print(f"Error in SSE connection {connection_id}: {e}")
124
- # This should simulate the "peer closed connection without sending complete message body" error
125
- finally:
126
- # Clean up connection tracking
127
- if connection_id in connection_times:
128
- del connection_times[connection_id]
129
- print(
130
- f"Connection {connection_id} closed - "
131
- "this should trigger the disconnection logs mentioned in issue #120"
132
- )
133
-
134
- return StreamingResponse(
135
- event_generator(),
136
- media_type="text/event-stream",
137
- headers={"Cache-Control": "no-cache", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*"},
138
- )
139
-
140
-
141
- @mcp.custom_route("/health", methods=["GET"])
142
- async def health_check(request) -> dict:
143
- """Health check endpoint"""
144
- return {
145
- "status": "healthy",
146
- "timestamp": datetime.now().isoformat(),
147
- "active_connections": len(connection_times),
148
- "timeout_seconds": 30,
149
- }
150
-
151
-
152
- if __name__ == "__main__":
153
- print("🚀 Starting Long Timeout Test Server for GitHub Issue #120...")
154
- print("⏰ Connection timeout: 30 seconds (matches issue reproduction steps)")
155
- print("📡 Server features:")
156
- print(" - Automatic connection timeout after 30 seconds")
157
- print(" - Basic MCP tools for testing")
158
- print(" - Connection state tracking")
159
- print(" - Simulates 'peer closed connection' errors")
160
- print("\n💡 Available endpoints:")
161
- print(" - SSE endpoint: http://localhost:8082/sse")
162
- print(" - Health check: http://localhost:8082/health")
163
- print("\n💡 This server is designed to test:")
164
- print(" - Connection state tracking after 30+ second timeout")
165
- print(" - Auto-reconnection behavior after long timeouts")
166
- print(" - Error handling for disconnected sessions with empty error messages")
167
- print(" - Exact reproduction of GitHub Issue #120 steps")
168
- print("⚡ Starting server on port 8082...")
169
-
170
- # Run the FastMCP server with SSE transport
171
- mcp.run(transport="sse", host="0.0.0.0", port=8082, log_level="info")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes