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.
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/publish.yml +4 -5
- {mcp_use-1.3.2 → mcp_use-1.3.3}/PKG-INFO +3 -2
- {mcp_use-1.3.2 → mcp_use-1.3.3}/pyproject.toml +3 -2
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/sse/test_connection_state_tracking.py +23 -127
- mcp_use-1.3.2/tests/integration/servers_for_testing/long_timeout_test_server.py +0 -171
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.env.example +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/pull_request_template.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/release-drafter.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/changelog.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/claude.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/release-drafter.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/transportstests.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/unittests.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.github/workflows/update-readme.yml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.gitignore +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/.pre-commit-config.yaml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/CHANGELOG.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/CLAUDE.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/CODE_OF_CONDUCT.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/CONTRIBUTING.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/LICENSE +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/README.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/README.md +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/adapters.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/introduction.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/mcpagent.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/api-reference/mcpclient.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/changelog.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/community/showcase.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development/observability.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development/telemetry.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/development.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/docs.json +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/agent-configuration.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/client-configuration.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/configuration.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/connection-types.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/llm-integration.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/essentials/server-manager.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/favicon.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/fonts.css +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/building-custom-agents.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/logging.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/multi-server-setup.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/security.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/guides/streaming.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/01.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/02.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/configuration-dark.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/configuration-light.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/examples-dark.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/examples-light.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/hero-dark.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/hero-light.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/installation-dark.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/installation-light.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/quickstart-dark.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/images/quickstart-light.png +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/index.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/installation.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/dark.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/light.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/logo/react.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/quickstart.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/snippets/snippet-intro.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/snippets/youtube-embed.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/common-issues.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/connection-errors.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/docs/troubleshooting/performance.mdx +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/airbnb_mcp.json +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/airbnb_use.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/blender_use.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/browser_mcp.json +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/browser_use.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/chat_example.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/filesystem_use.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/http_example.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/mcp_everything.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/multi_server_example.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/examples/sandbox_everything.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/base.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/adapters/langchain_adapter.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/base.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/mcpagent.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/prompts/system_prompt_builder.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/agents/prompts/templates.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/client.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/config.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/base.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/http.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/sandbox.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/stdio.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/utils.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/connectors/websocket.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/logging.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/server_manager.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/base_tool.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/connect_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/disconnect_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/get_active_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/list_servers_tool.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/search_tools.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/managers/tools/use_tool.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/laminar.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/observability/langfuse.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/session.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/base.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/sse.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/stdio.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/streamable_http.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/task_managers/websocket.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/events.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/telemetry.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/telemetry/utils.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/types/sandbox.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/mcp_use/utils.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/pytest.ini +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/ruff.toml +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/static/logo_black.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/static/logo_white.svg +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/conftest.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/custom_streaming_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/simple_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/timeout_test_server.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/customStreaming/__init__.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/customStreaming/test_custom_streaming_integration.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/sse/test_sse_integration.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/stdio/test_stdio_integration.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/streamableHttp/test_streamable_http_integration.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_client.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_config.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_http_connector.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_logging.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_sandbox_connector.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_search_tools_issue_138.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_session.py +0 -0
- {mcp_use-1.3.2 → mcp_use-1.3.3}/tests/unit/test_stdio_connector.py +0 -0
- {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.
|
|
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:
|
|
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.
|
|
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",
|
{mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/sse/test_connection_state_tracking.py
RENAMED
|
@@ -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(
|
|
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 =
|
|
59
|
+
server_url = timeout_server_process
|
|
95
60
|
|
|
96
|
-
# Step 1: Create an HttpConnector with SSE endpoint configuration
|
|
97
|
-
config = {"mcpServers": {"fixTest": {"url": f"{server_url}/sse"
|
|
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 (
|
|
125
|
-
await asyncio.sleep(
|
|
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
|
|
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
|
|
168
|
-
"""Test GitHub issue #120 fix with
|
|
169
|
-
server_url =
|
|
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
|
|
172
|
-
config = {"mcpServers": {"noAutoTest": {"url": f"{server_url}/sse"
|
|
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 (
|
|
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 (
|
|
201
|
-
await asyncio.sleep(
|
|
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
|
|
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
|
|
207
|
-
print("Attempting tool call after timeout
|
|
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()
|
|
223
|
-
|
|
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
|
|
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"
|
|
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
|
|
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
|
|
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
|
|
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
|
{mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/custom_streaming_server.py
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/servers_for_testing/timeout_test_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_use-1.3.2 → mcp_use-1.3.3}/tests/integration/transports/stdio/test_stdio_integration.py
RENAMED
|
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
|