How do I connect to an MCP server?
The Model Context Protocol (MCP) is an open protocol that standardizes how applications interact with Large Language Models (LLMs) and their context. Connecting to an MCP server allows you to extend AI capabilities with custom tools, data sources, and integrations. This guide covers the technical aspects of establishing connections to MCP servers using different approaches and programming languages.
Understanding MCP Server Architecture
Before connecting to an MCP server, it's important to understand the basic architecture. MCP uses a client-server model where:
- MCP Server: Exposes tools, resources, and prompts that AI applications can use
- MCP Client: Connects to one or more servers and makes their capabilities available to the application
- Transport Layer: Handles communication between client and server (stdio, HTTP/SSE, or WebSocket)
The connection process involves establishing a transport channel, performing protocol negotiation, and initializing the session with capability exchange.
Connection Methods
MCP supports three primary transport mechanisms for client-server communication:
1. Standard Input/Output (stdio)
The stdio transport is the most common method for local MCP servers. It uses process stdin/stdout for communication, making it ideal for command-line tools and local development.
2. HTTP with Server-Sent Events (SSE)
HTTP/SSE transport enables remote server connections and is suitable for web-based applications and distributed systems.
3. WebSocket
WebSocket transport provides bidirectional, real-time communication and is optimal for interactive applications requiring low latency.
Connecting Using Python
Python developers can connect to MCP servers using the official mcp
package. Here's a comprehensive example:
Installation
pip install mcp
Basic Connection Example
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def connect_to_mcp_server():
# Define server parameters
server_params = StdioServerParameters(
command="python",
args=["-m", "your_mcp_server"],
env=None
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {tools}")
# List available resources
resources = await session.list_resources()
print(f"Available resources: {resources}")
# Call a tool
result = await session.call_tool("tool_name", arguments={
"param1": "value1",
"param2": "value2"
})
print(f"Tool result: {result}")
# Run the connection
asyncio.run(connect_to_mcp_server())
Advanced Python Example with Error Handling
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from typing import Optional
class MCPConnection:
def __init__(self, command: str, args: list):
self.server_params = StdioServerParameters(
command=command,
args=args
)
self.session: Optional[ClientSession] = None
async def connect(self):
"""Establish connection to MCP server"""
try:
self.read, self.write = await stdio_client(self.server_params).__aenter__()
self.session = await ClientSession(self.read, self.write).__aenter__()
await self.session.initialize()
print("Successfully connected to MCP server")
return True
except Exception as e:
print(f"Connection failed: {e}")
return False
async def execute_tool(self, tool_name: str, **kwargs):
"""Execute a tool on the MCP server"""
if not self.session:
raise RuntimeError("Not connected to server")
try:
result = await self.session.call_tool(tool_name, arguments=kwargs)
return result
except Exception as e:
print(f"Tool execution failed: {e}")
raise
async def disconnect(self):
"""Close the connection"""
if self.session:
await self.session.__aexit__(None, None, None)
# Usage
async def main():
mcp = MCPConnection("node", ["path/to/server.js"])
if await mcp.connect():
# Use the connection
result = await mcp.execute_tool("web_scrape", url="https://example.com")
print(result)
await mcp.disconnect()
asyncio.run(main())
Connecting Using JavaScript/TypeScript
For Node.js applications, the @modelcontextprotocol/sdk
package provides MCP client functionality:
Installation
npm install @modelcontextprotocol/sdk
Basic TypeScript Connection
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function connectToMCPServer() {
// Create transport
const transport = new StdioClientTransport({
command: "node",
args: ["path/to/mcp-server.js"],
});
// Create client
const client = new Client(
{
name: "my-mcp-client",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Connect to server
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log("Available tools:", tools);
// Call a tool
const result = await client.callTool({
name: "scrape_website",
arguments: {
url: "https://example.com",
selector: ".main-content",
},
});
console.log("Result:", result);
// Close connection
await client.close();
}
connectToMCPServer().catch(console.error);
JavaScript Example with Event Handling
const { Client } = require("@modelcontextprotocol/sdk/client/index.js");
const { StdioClientTransport } = require("@modelcontextprotocol/sdk/client/stdio.js");
class MCPClient {
constructor(serverCommand, serverArgs) {
this.transport = new StdioClientTransport({
command: serverCommand,
args: serverArgs,
});
this.client = new Client(
{
name: "scraping-client",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
}
async connect() {
try {
await this.client.connect(this.transport);
console.log("Connected to MCP server");
// Setup error handling
this.transport.onerror = (error) => {
console.error("Transport error:", error);
};
this.transport.onclose = () => {
console.log("Connection closed");
};
return true;
} catch (error) {
console.error("Connection failed:", error);
return false;
}
}
async scrapeWebsite(url, options = {}) {
const result = await this.client.callTool({
name: "web_scrape",
arguments: {
url: url,
...options,
},
});
return result;
}
async getResource(uri) {
const resource = await this.client.readResource({ uri });
return resource;
}
async disconnect() {
await this.client.close();
}
}
// Usage example
async function main() {
const mcpClient = new MCPClient("python", ["-m", "mcp_server"]);
if (await mcpClient.connect()) {
try {
// Scrape a website
const data = await mcpClient.scrapeWebsite("https://example.com", {
waitFor: ".content",
selector: "article",
});
console.log("Scraped data:", data);
} finally {
await mcpClient.disconnect();
}
}
}
main().catch(console.error);
Connecting via HTTP/SSE Transport
For remote MCP servers, you can use HTTP with Server-Sent Events:
Python HTTP/SSE Client
from mcp import ClientSession
from mcp.client.sse import sse_client
async def connect_remote_mcp():
async with sse_client("https://mcp-server.example.com/sse") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Use the session
tools = await session.list_tools()
print(f"Remote tools: {tools}")
asyncio.run(connect_remote_mcp())
JavaScript HTTP/SSE Client
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
async function connectRemoteMCP() {
const transport = new SSEClientTransport(
new URL("https://mcp-server.example.com/sse")
);
const client = new Client(
{ name: "remote-client", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
await client.connect(transport);
const tools = await client.listTools();
console.log("Remote tools:", tools);
await client.close();
}
Configuration and Environment Setup
When connecting to an MCP server, you often need to configure environment variables and server parameters:
Environment Configuration Example
import os
from mcp import StdioServerParameters
# Set environment variables
env_vars = {
"API_KEY": os.getenv("WEBSCRAPING_API_KEY"),
"PROXY_URL": os.getenv("PROXY_URL"),
"TIMEOUT": "30000"
}
server_params = StdioServerParameters(
command="node",
args=["server.js"],
env=env_vars
)
Configuration File Approach
// config.json
{
"mcpServers": {
"webscraping": {
"command": "python",
"args": ["-m", "webscraping_mcp"],
"env": {
"API_KEY": "${WEBSCRAPING_API_KEY}"
}
}
}
}
// Load configuration
const config = require('./config.json');
const serverConfig = config.mcpServers.webscraping;
// Expand environment variables
serverConfig.env = Object.fromEntries(
Object.entries(serverConfig.env).map(([key, value]) => [
key,
value.replace(/\${(\w+)}/g, (_, envVar) => process.env[envVar] || '')
])
);
Error Handling and Reconnection
Robust MCP connections should handle errors and implement reconnection logic:
import asyncio
from typing import Optional
class ResilientMCPConnection:
def __init__(self, server_params, max_retries=3):
self.server_params = server_params
self.max_retries = max_retries
self.session: Optional[ClientSession] = None
async def connect_with_retry(self):
for attempt in range(self.max_retries):
try:
async with stdio_client(self.server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
self.session = session
print(f"Connected on attempt {attempt + 1}")
return True
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < self.max_retries - 1:
await asyncio.sleep(2 ** attempt) # Exponential backoff
return False
async def safe_call_tool(self, tool_name: str, **kwargs):
try:
return await self.session.call_tool(tool_name, arguments=kwargs)
except Exception as e:
print(f"Tool call failed, attempting reconnection: {e}")
if await self.connect_with_retry():
return await self.session.call_tool(tool_name, arguments=kwargs)
raise
Integration with Web Scraping Workflows
MCP servers are particularly useful for web scraping automation. When handling browser sessions in Puppeteer, you can integrate MCP tools to enhance your scraping capabilities:
async def scrape_with_mcp(urls: list):
mcp = MCPConnection("node", ["webscraping-mcp-server.js"])
await mcp.connect()
results = []
for url in urls:
# Use MCP tool for scraping
result = await mcp.execute_tool(
"scrape_page",
url=url,
wait_for_selector=".content",
extract_fields=["title", "description", "price"]
)
results.append(result)
await mcp.disconnect()
return results
You can also combine MCP with AJAX request handling for dynamic content extraction:
async function scrapeWithMCP(url) {
const mcpClient = new MCPClient("python", ["-m", "scraper_mcp"]);
await mcpClient.connect();
// Use MCP tool to handle dynamic content
const data = await mcpClient.scrapeWebsite(url, {
waitForAjax: true,
timeout: 30000,
extractors: {
title: "h1.title",
content: ".article-body",
metadata: "meta[property^='og:']",
},
});
await mcpClient.disconnect();
return data;
}
Best Practices
- Connection Lifecycle Management: Always properly close connections to prevent resource leaks
- Error Handling: Implement comprehensive error handling for network issues and server errors
- Timeouts: Set appropriate timeouts for long-running operations
- Authentication: Securely manage API keys and credentials using environment variables
- Logging: Implement detailed logging for debugging connection issues
- Resource Limits: Monitor and limit concurrent connections to prevent server overload
Troubleshooting Common Issues
Connection Timeout
If connections timeout, increase the timeout value:
server_params = StdioServerParameters(
command="python",
args=["-m", "server"],
env={"MCP_TIMEOUT": "60000"} # 60 seconds
)
Server Process Not Starting
Check that the server command is correct and the executable is in your PATH:
# Test server manually
python -m your_mcp_server
# Or for Node.js
node path/to/server.js
Protocol Version Mismatch
Ensure both client and server use compatible MCP protocol versions. Update your SDK:
# Python
pip install --upgrade mcp
# Node.js
npm update @modelcontextprotocol/sdk
Conclusion
Connecting to an MCP server enables powerful integrations for AI-enhanced applications, particularly in web scraping and data extraction workflows. By following the examples and best practices in this guide, you can establish robust, production-ready MCP connections in your applications. Whether you're using Python, JavaScript, or other languages, the Model Context Protocol provides a standardized way to extend AI capabilities with custom tools and data sources.