Table of contents

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

  1. Connection Lifecycle Management: Always properly close connections to prevent resource leaks
  2. Error Handling: Implement comprehensive error handling for network issues and server errors
  3. Timeouts: Set appropriate timeouts for long-running operations
  4. Authentication: Securely manage API keys and credentials using environment variables
  5. Logging: Implement detailed logging for debugging connection issues
  6. 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.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon