docs/api-reference/client-api/connection-management.mdx
2024-11-18 11:36:07 -05:00

355 lines
No EOL
8.1 KiB
Text

---
title: 'Connection Management'
description: 'Learn how to establish and manage MCP client connections'
---
## Overview
The MCP client API provides flexible connection management options with support for different transport types. This guide covers establishing connections, handling connection events, and managing connection lifecycles.
## Creating a client
First, create an MCP client instance with your application's information.
<CodeGroup>
```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk";
const client = new Client({
name: "my-application",
version: "1.0.0"
});
```
```python Python
from mcp import Client
client = Client(
name="my-application",
version="1.0.0"
)
```
</CodeGroup>
## Transport types
MCP supports multiple transport types for different use cases. Choose the appropriate transport based on your needs.
### WebSocket transport
Use WebSocket transport for real-time bidirectional communication.
<CodeGroup>
```typescript TypeScript
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk";
const transport = new WebSocketClientTransport(
new URL("ws://localhost:3000")
);
await client.connect(transport);
```
```python Python
from mcp.transports import WebSocketTransport
transport = WebSocketTransport(
url="ws://localhost:3000"
)
await client.connect(transport)
```
</CodeGroup>
### SSE transport
Server-Sent Events transport is suitable for scenarios where the server pushes data to the client.
<CodeGroup>
```typescript TypeScript
import { SSEClientTransport } from "@modelcontextprotocol/sdk";
const transport = new SSEClientTransport(
new URL("http://localhost:3000/events")
);
await client.connect(transport);
```
```python Python
from mcp.transports import SSETransport
transport = SSETransport(
url="http://localhost:3000/events"
)
await client.connect(transport)
```
</CodeGroup>
### Stdio transport
For local server processes, use the stdio transport to communicate via standard input/output.
<CodeGroup>
```typescript TypeScript
import { StdioClientTransport } from "@modelcontextprotocol/sdk";
const transport = new StdioClientTransport({
command: "/path/to/server",
args: ["--arg1", "--arg2"],
env: { "KEY": "value" }
});
await client.connect(transport);
```
```python Python
from mcp.transports import StdioTransport
transport = StdioTransport(
command="/path/to/server",
args=["--arg1", "--arg2"],
env={"KEY": "value"}
)
await client.connect(transport)
```
</CodeGroup>
## Connection lifecycle
### Event handling
Set up event handlers to manage the connection lifecycle.
<CodeGroup>
```typescript TypeScript
client.onclose = () => {
console.log("Connection closed");
};
client.onerror = (error) => {
console.error("Connection error:", error);
};
// Transport-specific events
transport.onclose = () => {
console.log("Transport closed");
};
transport.onerror = (error) => {
console.error("Transport error:", error);
};
```
```python Python
@client.on_close
async def handle_close():
print("Connection closed")
@client.on_error
async def handle_error(error):
print(f"Connection error: {error}")
# Transport-specific events
@transport.on_close
async def handle_transport_close():
print("Transport closed")
@transport.on_error
async def handle_transport_error(error):
print(f"Transport error: {error}")
```
</CodeGroup>
### Connection states
Monitor and manage connection states throughout your application's lifecycle.
<CodeGroup>
```typescript TypeScript
// Check if connected
if (client.transport) {
console.log("Client is connected");
}
// Get server capabilities after connection
const capabilities = client.getServerCapabilities();
const serverVersion = client.getServerVersion();
// Clean up connection
await client.close();
```
```python Python
# Check if connected
if client.transport:
print("Client is connected")
# Get server capabilities after connection
capabilities = client.get_server_capabilities()
server_version = client.get_server_version()
# Clean up connection
await client.close()
```
</CodeGroup>
## Error handling
Implement robust error handling for connection-related issues.
<CodeGroup>
```typescript TypeScript
try {
await client.connect(transport);
} catch (error) {
if (error.code === ErrorCode.ConnectionClosed) {
// Handle connection closure
} else if (error.code === ErrorCode.InvalidRequest) {
// Handle invalid request
} else {
// Handle other errors
}
}
```
```python Python
try:
await client.connect(transport)
except ConnectionClosedError:
# Handle connection closure
pass
except InvalidRequestError:
# Handle invalid request
pass
except McpError as e:
# Handle other errors
pass
```
</CodeGroup>
## Best practices
<CardGroup cols={2}>
<Card title="Connection management" icon="plug">
Always close connections when they're no longer needed to free up resources
</Card>
<Card title="Error handling" icon="shield-check">
Implement comprehensive error handling for all connection states
</Card>
<Card title="Event handling" icon="bell">
Set up appropriate event handlers before establishing connections
</Card>
<Card title="Resource cleanup" icon="broom">
Use try/finally blocks to ensure proper cleanup of resources
</Card>
</CardGroup>
## Connection examples
Here are some common connection patterns:
<AccordionGroup>
<Accordion title="Basic connection with retry">
<CodeGroup>
```typescript TypeScript
async function connectWithRetry(
client: Client,
transport: Transport,
maxAttempts = 3
) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
await client.connect(transport);
return;
} catch (error) {
if (attempt === maxAttempts) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
```
```python Python
async def connect_with_retry(
client: Client,
transport: Transport,
max_attempts: int = 3
):
for attempt in range(max_attempts):
try:
await client.connect(transport)
return
except Exception as e:
if attempt == max_attempts - 1:
raise
await asyncio.sleep(attempt + 1)
```
</CodeGroup>
</Accordion>
<Accordion title="Connection with timeout">
<CodeGroup>
```typescript TypeScript
async function connectWithTimeout(
client: Client,
transport: Transport,
timeoutMs = 5000
) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Connection timeout")), timeoutMs);
});
await Promise.race([
client.connect(transport),
timeoutPromise
]);
}
```
```python Python
async def connect_with_timeout(
client: Client,
transport: Transport,
timeout: float = 5.0
):
async with asyncio.timeout(timeout):
await client.connect(transport)
```
</CodeGroup>
</Accordion>
</AccordionGroup>
## Troubleshooting
<AccordionGroup>
<Accordion title="Connection refused">
- Verify the server is running and accessible
- Check if the port is correct and available
- Ensure firewalls aren't blocking the connection
</Accordion>
<Accordion title="Authentication failures">
- Verify credentials if required
- Check if environment variables are properly set
- Ensure transport configuration is correct
</Accordion>
<Accordion title="Connection drops">
- Implement reconnection logic
- Check network stability
- Monitor server health
</Accordion>
</AccordionGroup>
## Transport selection guide
Choose the appropriate transport based on your use case:
| Transport | Use Case | Advantages | Considerations |
|-----------|----------|------------|----------------|
| WebSocket | Real-time bidirectional | Full-duplex, low latency | Requires WebSocket server |
| SSE | Server push updates | Simple, firewall-friendly | One-way server push |
| Stdio | Local process communication | Simple, reliable | Limited to local processes |