Skip to content

Commit 5e7bc5e

Browse files
committed
Add reconnect example for async tools
1 parent b33721e commit 5e7bc5e

File tree

12 files changed

+1121
-0
lines changed

12 files changed

+1121
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Async Reconnect Client Example
2+
3+
A demonstration of how to use the MCP Python SDK to call async tools and handle operation tokens for resuming long-running operations.
4+
5+
## Features
6+
7+
- Async tool invocation with operation tokens
8+
- Operation status polling and result retrieval
9+
- Support for resuming operations with existing tokens
10+
11+
## Installation
12+
13+
```bash
14+
cd examples/clients/async-reconnect-client
15+
uv sync --reinstall
16+
```
17+
18+
## Usage
19+
20+
### 1. Start an MCP server with async tools
21+
22+
```bash
23+
# Example with simple-tool-async server
24+
cd examples/servers/simple-tool-async
25+
uv run mcp-simple-tool-async --transport streamable-http --port 8000
26+
```
27+
28+
### 2. Run the client
29+
30+
```bash
31+
# Connect to default endpoint
32+
uv run mcp-async-reconnect-client
33+
34+
# Connect to custom endpoint
35+
uv run mcp-async-reconnect-client --endpoint http://localhost:3001/mcp
36+
37+
# Resume with existing operation token
38+
uv run mcp-async-reconnect-client --token your-operation-token-here
39+
```
40+
41+
## Example
42+
43+
The client will call the `fetch_website` async tool and demonstrate:
44+
45+
1. Starting an async operation and receiving an operation token
46+
2. Polling the operation status until completion
47+
3. Retrieving the final result when the operation completes
48+
49+
```bash
50+
$ uv run mcp-async-reconnect-client
51+
Calling async tool...
52+
Operation started with token: abc123...
53+
Status: submitted
54+
Status: working
55+
Status: completed
56+
Result: <html>...</html>
57+
```
58+
59+
The client can be terminated during polling and resumed with the returned token, demonstrating how reconnection is supported:
60+
61+
```bash
62+
$ uv run mcp-async-reconnect-client
63+
Calling async tool...
64+
Operation started with token: abc123...
65+
Status: working
66+
^C
67+
Aborted!
68+
$ uv run mcp-async-reconnect-client --token=abc123...
69+
Calling async tool...
70+
Status: completed
71+
Result: <html>...</html>
72+
```
73+
74+
## Configuration
75+
76+
- `--endpoint` - MCP server endpoint (default: http://127.0.0.1:8000/mcp)
77+
- `--token` - Operation token to resume with (optional)
78+
79+
This example showcases the async tool capabilities introduced in MCP protocol version "next", allowing for long-running operations that can be resumed even if the client disconnects.

examples/clients/async-reconnect-client/mcp_async_reconnect_client/__init__.py

Whitespace-only changes.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import asyncio
2+
3+
import click
4+
from mcp import ClientSession, types
5+
from mcp.client.streamable_http import streamablehttp_client
6+
7+
8+
async def call_async_tool(session: ClientSession, token: str | None):
9+
"""Demonstrate calling an async tool."""
10+
print("Calling async tool...")
11+
12+
if not token:
13+
result = await session.call_tool("fetch_website", arguments={"url": "https://modelcontextprotocol.io"})
14+
assert result.operation
15+
token = result.operation.token
16+
print(f"Operation started with token: {token}")
17+
18+
# Poll for completion
19+
while True:
20+
status = await session.get_operation_status(token)
21+
print(f"Status: {status.status}")
22+
23+
if status.status == "completed":
24+
final_result = await session.get_operation_result(token)
25+
for content in final_result.result.content:
26+
if isinstance(content, types.TextContent):
27+
print(f"Result: {content.text}")
28+
break
29+
elif status.status == "failed":
30+
print(f"Operation failed: {status.error}")
31+
break
32+
33+
await asyncio.sleep(0.5)
34+
35+
36+
async def run_session(endpoint: str, token: str | None):
37+
async with streamablehttp_client(endpoint) as (read, write, _):
38+
async with ClientSession(read, write, protocol_version="next") as session:
39+
await session.initialize()
40+
await call_async_tool(session, token)
41+
42+
43+
@click.command()
44+
@click.option("--endpoint", default="http://127.0.0.1:8000/mcp", help="Endpoint to connect to")
45+
@click.option("--token", default=None, help="Operation token to resume with")
46+
def main(endpoint: str, token: str | None):
47+
asyncio.run(run_session(endpoint, token))
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
[project]
2+
name = "mcp-async-reconnect-client"
3+
version = "0.1.0"
4+
description = "A client for the MCP simple-tool-async server that supports reconnection"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
authors = [{ name = "Anthropic" }]
8+
keywords = ["mcp", "client", "async"]
9+
license = { text = "MIT" }
10+
classifiers = [
11+
"Development Status :: 4 - Beta",
12+
"Intended Audience :: Developers",
13+
"License :: OSI Approved :: MIT License",
14+
"Programming Language :: Python :: 3",
15+
"Programming Language :: Python :: 3.10",
16+
]
17+
dependencies = ["click>=8.2.0", "mcp>=1.0.0"]
18+
19+
[project.scripts]
20+
mcp-async-reconnect-client = "mcp_async_reconnect_client.client:main"
21+
22+
[build-system]
23+
requires = ["hatchling"]
24+
build-backend = "hatchling.build"
25+
26+
[tool.hatch.build.targets.wheel]
27+
packages = ["mcp_async_reconnect_client"]
28+
29+
[tool.pyright]
30+
include = ["mcp_async_reconnect_client"]
31+
venvPath = "."
32+
venv = ".venv"
33+
34+
[tool.ruff.lint]
35+
select = ["E", "F", "I"]
36+
ignore = []
37+
38+
[tool.ruff]
39+
line-length = 120
40+
target-version = "py310"
41+
42+
[tool.uv]
43+
dev-dependencies = ["pyright>=1.1.379", "pytest>=8.3.3", "ruff>=0.6.9"]
44+
45+
[tool.uv.sources]
46+
mcp = { path = "../../../" }
47+
48+
[[tool.uv.index]]
49+
url = "https://pypi.org/simple"

0 commit comments

Comments
 (0)