DataAIHub
DataAIHubNews · Research · Tools · Learning
LLM Concepts

Model Context Protocol (MCP) Guide

Learn MCP - the open standard for connecting LLMs to external tools, data sources, and services through a unified client-server protocol.

13 min readIntermediateUpdated Jul 5, 2026

TL;DR

  • MCP is an open protocol that standardizes how LLM applications connect to external tools and data sources - one interface instead of custom integrations per tool.

  • MCP has three primitives: Tools (actions), Resources (read-only data), and Prompts (reusable templates) - servers expose these; clients (LLM apps) consume them.

  • It uses a client-server architecture - MCP servers wrap external systems; MCP clients (like Cursor or Claude Desktop) connect to servers and expose capabilities to the model.

  • MCP solves the N×M integration problem - without it, every LLM app needs custom code for every tool. With MCP, build one server, connect any client.

  • MCP is production-ready but evolving - Anthropic open-sourced it in late 2024; adoption is growing across IDEs, agents, and enterprise platforms.

Why This Matters

Before MCP, connecting an LLM to external tools meant writing custom integration code for every combination of application and tool. Cursor needed custom code for GitHub, Slack, and databases. Claude Desktop needed separate integrations for the same tools. Every agent framework reinvented the tool connection layer.

MCP replaces this fragmentation with a standard protocol. Build an MCP server for your database once - any MCP-compatible client (Cursor, Claude Desktop, custom agents) can connect to it without custom code. This is the USB-C of AI tool integration: one port, many devices.

For AI engineers, MCP changes how you think about tool architecture. Instead of embedding tool logic in your agent code, you expose capabilities as MCP servers that any LLM application can discover and use. This separation of concerns makes tools reusable, testable, and independently deployable.

The Problem MCP Solves

The tool integration landscape before MCP:

Before MCP, every LLM application needed bespoke integrations for each external tool. MCP standardizes those connections through a host–client–server model defined by Anthropic's open protocol.

An MCP host application manages multiple MCP clients, each maintaining a dedicated one-to-one connection to an MCP server that wraps an external system like GitHub, a database, or the filesystem.

MCP host-client-server stack

Source: Model Context Protocol Docs Repository

N applications × M tools = N×M custom integrations. Each integration is built, maintained, and debugged independently. Tool definitions are inconsistent. Authentication is duplicated. Updates to a tool require changes in every client.

MCP solves this:

Each MCP client maintains a dedicated connection to one MCP server, letting the host aggregate tools, resources, and prompts from multiple backends through a single protocol.

MCP sessions begin with JSON-RPC initialization, capability exchange, and then bidirectional tool calls where the host forwards LLM-initiated requests to servers and returns results.

MCP client architecture and request flow

Source: Model Context Protocol Docs Repository

N clients + M servers, connected through one protocol. Build the server once; any client connects.

What Is MCP?

The Model Context Protocol (MCP) is an open standard introduced by Anthropic in November 2024 for connecting LLM applications to external data sources and tools. It defines a client-server protocol based on JSON-RPC 2.0 over stdio or HTTP/SSE transports.

MCP provides three capability primitives:

Primitive Purpose Example
Tools Actions the LLM can invoke create_issue, run_query, send_message
Resources Read-only data the LLM can access File contents, database schemas, API docs
Prompts Reusable prompt templates Code review template, bug report formatter

An MCP server exposes tools, resources, and prompts for a specific system (GitHub, PostgreSQL, Slack). An MCP client connects to servers and makes their capabilities available to the LLM.

MCP Server (GitHub)          MCP Client (Cursor)         LLM
├── tools/                   ├── connects to servers     ├── sees available tools
│   ├── create_issue         ├── lists tools/resources   ├── selects tool
│   ├── search_repos         └── forwards tool calls     └── generates response
│   └── list_prs
├── resources/
│   ├── repo://README
│   └── repo://file/path
└── prompts/
    └── code_review

How MCP Works

Protocol Architecture

MCP separates the data layer (tools, resources, prompts over JSON-RPC) from the transport layer (stdio for local servers, HTTP/SSE for remote services).

MCP server architecture and protocol layers

Source: Model Context Protocol Docs Repository

Transport Layers

MCP supports two transport mechanisms:

Transport Use case How it works
stdio Local servers Client spawns server as subprocess; JSON-RPC over stdin/stdout
HTTP/SSE Remote servers Server-Sent Events for server→client; HTTP POST for client→server

Local development typically uses stdio - the client launches the server process:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
    }
  }
}

Remote/production deployments use HTTP/SSE for server-side MCP servers accessible over the network.

MCP vs Function Calling

Aspect Function Calling MCP
Scope Single application Cross-application standard
Tool definition In application code Server-side, discoverable
Transport Provider API (OpenAI, Anthropic) JSON-RPC over stdio or HTTP
Discovery Static - defined at build time Dynamic - servers advertise capabilities
Reusability Per-application One server, many clients
State Client manages Server can maintain state

MCP does not replace function calling - it standardizes what function calling connects to. The MCP client translates MCP tools into function calling format for the LLM.

Architecture

In production, each external system is exposed as one MCP server; any compatible client discovers capabilities and invokes tools without bespoke integration code per application.

MCP tools available in an MCP-enabled client

Source: Model Context Protocol Docs Repository

Step-by-Step Flow

Building and connecting an MCP server:

  1. Identify the capability - What system do you want to expose? (database, API, file system, internal service)

  2. Create an MCP server - Use the MCP SDK to define tools, resources, and prompts.

  3. Implement tool handlers - Write the code that executes when the LLM calls each tool.

  4. Configure the client - Add the server to the MCP client's configuration (e.g., Cursor settings, Claude Desktop config).

  5. Client discovers capabilities - On connection, the client calls tools/list, resources/list, prompts/list.

  6. LLM uses tools - When the user asks a question, the LLM selects MCP tools; the client forwards calls to the server.

  7. Server executes and returns - The server runs the tool, returns results through the protocol.

  8. Monitor and iterate - Log tool usage, refine descriptions, add new tools as needed.

Real Production Example

Building a custom MCP server that exposes an internal customer API:

# server.py - MCP server for customer lookup
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import httpx
import json
import os

server = Server("customer-api")

API_BASE = os.environ.get("CUSTOMER_API_URL", "http://localhost:8080/api")
API_KEY = os.environ.get("CUSTOMER_API_KEY", "")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="lookup_customer",
            description="Look up customer details by email or customer ID.

Returns name, plan, status, and billing info.",
            inputSchema={
                "type": "object",
                "properties": {
                    "email": {"type": "string", "description": "Customer email address"},
                    "customer_id": {"type": "string", "description": "Customer ID (e.g., CUST-12345)"},
                },
            },
        ),
        Tool(
            name="list_recent_orders",
            description="List recent orders for a customer.

Returns order ID, date, total, and status.",
            inputSchema={
                "type": "object",
                "properties": {
                    "customer_id": {"type": "string", "description": "Customer ID"},
                    "limit": {"type": "integer", "description": "Max orders to return", "default": 10},
                },
                "required": ["customer_id"],
            },
        ),
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

    async with httpx.AsyncClient(base_url=API_BASE, headers=headers, timeout=10.0) as client:
        if name == "lookup_customer":
            params = {k: v for k, v in arguments.items() if v}
            response = await client.get("/customers", params=params)
            response.raise_for_status()
            return [TextContent(type="text", text=json.dumps(response.json(), indent=2))]

        elif name == "list_recent_orders":
            customer_id = arguments["customer_id"]
            limit = arguments.get("limit", 10)
            response = await client.get(
                f"/customers/{customer_id}/orders",
                params={"limit": limit},
            )
            response.raise_for_status()
            return [TextContent(type="text", text=json.dumps(response.json(), indent=2))]

        return [TextContent(type="text", text=json.dumps({"error": f"Unknown tool: {name}"}))]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream, server.create_initialization_options())

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

Client configuration (Cursor/Claude Desktop):

{
  "mcpServers": {
    "customer-api": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": {
        "CUSTOMER_API_URL": "https://api.internal.acme.com/v1",
        "CUSTOMER_API_KEY": "${CUSTOMER_API_KEY}"
      }
    }
  }
}

Once configured, any MCP client can ask "Look up customer john@example.com" and the LLM will invoke lookup_customer through the MCP protocol.

Design Decisions

Decision Option A Option B When to choose
Server scope One server per system Monolithic server One per system for modularity and independent deployment; monolithic for simple setups
Transport stdio (local) HTTP/SSE (remote) stdio for local dev tools; HTTP/SSE for shared/remote servers in production
Tool granularity Fine-grained tools High-level tools Fine-grained for flexibility; high-level for reliability (fewer tool selection errors)
Auth model Server manages credentials Client passes tokens Server-managed for simplicity; client-passed for multi-tenant scenarios
Resource exposure Expose schemas and docs Expose live data Schemas for context; live data when the LLM needs current state

⚠ Common Mistakes

  1. Exposing too many tools - An MCP server with 30 tools overwhelms the model's selection accuracy. Keep servers focused: 5–10 tools per server, one server per domain.

  2. Vague tool descriptions - MCP tool descriptions are how the LLM decides when to use them. "Query the database" is useless. "Execute a read-only SQL query against the analytics database. Use for revenue, customer, and order data." is actionable.

  3. No error handling in tool handlers - Unhandled exceptions crash the MCP server. Wrap all handlers in try/except and return structured error messages.

  4. Hardcoding credentials in server config - Use environment variables and secret managers. MCP config files often end up in version control.

  5. Ignoring resource capabilities - MCP resources let the LLM read data without tool calls (database schemas, file contents, API docs). Exposing resources reduces unnecessary tool invocations.

  6. Not versioning servers - MCP servers are APIs. Version your tool schemas, maintain backward compatibility, and communicate breaking changes to client configurations.

Where It Breaks Down

  • Protocol maturity - MCP is young (late 2024). Breaking changes, incomplete SDK support, and missing features (streaming tool results, batch operations) are expected during rapid adoption.

  • No built-in auth protocol - MCP does not standardize authentication between clients and servers. You implement auth in your server or transport layer, leading to inconsistent patterns.

  • Latency overhead - JSON-RPC serialization + process communication (stdio) adds 10–50ms per tool call compared to in-process function calling. Acceptable for most use cases; problematic for high-frequency tool loops.

  • Stateless by default - MCP servers are typically stateless. Tools requiring persistent connections (WebSocket feeds, long-running jobs) need custom state management.

  • Discovery limits - All tools are listed at connection time. No runtime tool discovery based on conversation context. Large tool sets degrade model selection accuracy.

Running in Production

Best Practice

Best Practices - Instrument every stage, version embedding models, enforce access control at retrieval time, and evaluate on a fixed golden set before shipping changes.

Dimension Consideration
Scaling MCP servers are independent processes. Scale by running multiple server instances behind a load balancer (HTTP/SSE transport). stdio servers are single-process - one instance per client connection.
Latency stdio transport: 10–30ms overhead per call. HTTP/SSE: 20–100ms depending on network. Budget MCP overhead into your agent loop latency calculations.
Cost MCP itself is free (open protocol). Cost comes from the underlying systems tools call (API fees, database queries) and the LLM tokens consumed by tool definitions and results.
Monitoring Log every tool call: server name, tool name, arguments (sanitized), result size, latency, and errors. Track tool usage frequency to identify unused or misused tools.
Evaluation Test MCP tool selection with the same golden scenarios used for function calling. Verify tool descriptions lead to correct selection across different LLM clients.
Security MCP servers execute with the credentials configured in the client. Restrict server permissions to minimum required. Audit tool calls. Never expose admin-level tools through MCP without authentication. Run servers with limited OS permissions.

Important

MCP servers execute with the credentials and permissions configured in the client. A compromised MCP config or malicious server can access everything the credentials allow. Validate server sources, restrict permissions, and audit tool calls.

Ecosystem

Official MCP Servers (Anthropic-maintained)

  • @modelcontextprotocol/server-github - GitHub repos, issues, PRs
  • @modelcontextprotocol/server-postgres - PostgreSQL queries and schema
  • @modelcontextprotocol/server-filesystem - Local file read/write
  • @modelcontextprotocol/server-slack - Slack messaging
  • @modelcontextprotocol/server-google-maps - Location and mapping

MCP Clients

  • Cursor IDE - Built-in MCP client for development
  • Claude Desktop - Native MCP support
  • Continue - Open-source AI code assistant
  • Custom agents via MCP SDK (Python, TypeScript)

SDKs

  • @modelcontextprotocol/sdk - TypeScript SDK for building servers and clients
  • mcp - Python SDK for server and client implementation

Community Servers

  • Growing ecosystem of community-built servers for AWS, Notion, Jira, Docker, and more. Check the MCP servers repository for the latest.
  • Tool Calling - The general pattern MCP standardizes. MCP is to tool calling what HTTP is to network communication.

  • Function Calling - The LLM-facing mechanism that MCP clients translate MCP tools into.

  • AI Agents - Agents consume MCP tools as their primary way to interact with external systems.

  • Agent Architectures - ReAct and Plan-and-Execute patterns that orchestrate MCP tool calls.

  • AI System Architecture - MCP fits into the tool/integration layer of production AI system design.

  • Prompt Engineering - MCP prompts provide reusable templates; tool descriptions are prompt engineering artifacts.

Learning Path

Prerequisites: Tool Calling · Function Calling

Next topics: AI Agents · Agent Architectures · AI System Architecture

Estimated time: 50 min · Difficulty: Intermediate

FAQs

Is MCP only for Anthropic/Claude?

No. MCP is an open protocol. While Anthropic created it, MCP clients and servers work with any LLM. Cursor uses MCP with various models. The protocol is model-agnostic.

Do I need MCP if I already have function calling?

Not necessarily. If your tools are used by one application, function calling is simpler. MCP adds value when you want tools reusable across multiple LLM applications, or when you want standardized tool discovery and configuration.

How is MCP different from LangChain tools?

LangChain tools are Python functions bound to a specific agent framework. MCP tools are protocol-based services usable by any MCP client. LangChain can consume MCP servers via an MCP adapter, combining both approaches.

Can I build an MCP server for my internal API?

Yes - this is the primary use case. Wrap your internal APIs, databases, or services as MCP servers. Any MCP-compatible client (Cursor, Claude Desktop, custom agents) can then access them without custom integration code.

Is MCP secure for production?

MCP provides the transport and protocol, not security. You must implement authentication, authorization, input validation, and audit logging in your servers. Treat MCP servers like microservices - apply the same security practices.

What is the difference between MCP tools and resources?

Tools are actions the LLM invokes (create, update, search). Resources are read-only data the LLM can access (file contents, schemas, documentation). Resources provide context; tools perform operations.

How do I debug MCP servers?

Run the server standalone and test with the MCP Inspector (browser-based debugging tool). Log all tool calls and responses. Test tool descriptions by asking the LLM questions that should trigger each tool.

Can MCP servers call other MCP servers?

Not directly through the protocol. An MCP server can internally call another service (API, database), but MCP client-to-server is the standard connection pattern. Compose at the client level by connecting to multiple servers.

What transports does MCP support?

stdio (local subprocess communication) and HTTP with Server-Sent Events (remote/network). stdio is standard for local development; HTTP/SSE for production deployments and shared servers.

How do I migrate from function calling to MCP?

Extract tool definitions and implementations into an MCP server. Replace in-process tool execution with MCP client calls. The LLM interaction pattern (tool selection, argument generation) remains the same - only the execution layer changes.

References

Further Reading

Summary

  • MCP standardizes how LLM applications connect to external tools and data - one protocol instead of N×M custom integrations. - Three primitives: Tools (actions), Resources (read-only data), Prompts (templates). - Build MCP servers for your systems; any MCP client connects without custom code. - MCP complements function calling - it standardizes the server side, not the LLM interface.

  • Keep servers focused (5–10 tools), write clear descriptions, handle errors, and secure credentials. - MCP is young but adoption is accelerating - invest in MCP servers for tools you want reusable across applications.

Next Topics

Learning Path

Continue Learning

Related Tools

ToolCategoryPurposeWebsiteBest For
CursorAI CodingAI-native code editor for building software with LLMs.cursor.comFull-stack development
ClaudeLLMAnthropic’s conversational AI focused on reliability and safety.claude.aiLong document analysis