Nitin Kumar SinghSolutions Architect

Type to search. to move, Enter to open.

    move open esc close
    Deep DiveAI & LLM

    MCP: What It Is and Why It Changes How You Build AI Tools

    MCP solves the N×M integration problem between AI models and tools. What it is, how it works, and why it matters before your next AI feature.

    Before MCP existed, adding tools to an AI application meant writing the same glue code over and over. You had OpenAI’s function calling syntax. Anthropic had tool use with a slightly different schema. LangChain abstracted over both, but now you depended on LangChain’s versioning decisions. Every new model provider meant rewriting your tool definitions. Every new tool meant re-registering it across every AI integration you maintained.

    This is the problem MCP solves. Define a tool once as an MCP server, and every MCP-capable client can call it: no per-client re-registration, and no rewrite when you switch model providers.

    The N×M Integration Problem

    Imagine you have 5 models (GPT-4o, Claude, Gemini, Mistral, Llama) and 10 tools (database queries, file access, GitHub, Slack, email, calendar, browser, code execution, vector search, monitoring). Without a standard, you need up to 50 separate integrations, each with its own schema, auth handling, error model, and discovery mechanism.

    M models × N tools = M×N custom integrations

    This isn’t a theoretical concern. Anyone who has maintained a multi-model AI system with more than a handful of tools has felt this. The diagram below shows the explosion without a standard versus the hub-and-spoke model MCP enables:

    ModelsToolsWithout MCP — N×M integrationsGPT-4oClaudeGeminiGitHubPostgresFilesystem
    Three models, three tools, nine integrations — and a fourth model or a fourth tool adds three more. Every line is code someone writes, tests and keeps working.
    ModelsOne protocolServersWith MCP — hub and spokeGPT-4oClaudeGeminiMCP clientGitHub MCP serverPostgres MCP serverFilesystem MCP server
    The same three models and the same three tools, on the same canvas as the diagram above: six lines instead of nine. The saving is not the three lines — it is that the next model costs one line rather than three, and the next tool costs one server rather than three integrations.

    Each model connects to one MCP client. Each tool exposes one MCP server. The protocol handles the rest.

    What MCP Actually Is

    MCP is an open protocol, originally designed by Anthropic and announced in November 2024. In December 2025 it was donated to the Agentic AI Foundation under the Linux Foundation, so it is now a vendor-neutral standard, not an Anthropic product. OpenAI officially adopted it in March 2025.

    At its core, MCP is a JSON-RPC 2.0 based protocol for communication between AI applications (clients) and capability providers (servers). The spec defines:

    • What messages look like (JSON-RPC envelopes)
    • How capability discovery works (the client asks the server what it can do)
    • The three primitive types a server can expose
    • How transport is handled

    The roles are distinct:

    • Host: the application the user interacts with (Claude Desktop, Cursor, VS Code with Copilot, your own app)
    • Client: Lives inside the host; manages one connection to one MCP server
    • Server: A process (local or remote) that exposes tools, resources, or prompts over the protocol

    A single host can run multiple clients simultaneously, each connected to a different server.

    The Three Primitives

    MCP servers expose capabilities via three primitive types. Understanding the distinction matters because they have different control models.

    Tools

    Tools are functions the model can call. This is the closest analog to OpenAI function calling. You define a name, a JSON Schema input definition, and the server handles execution and returns a result.

    Example: a GitHub MCP server might expose create_pull_request, list_issues, get_file_contents. The model decides when to call them based on the conversation.

    Tools are model-controlled: the AI decides when to invoke them.

    Resources

    Resources are data the model can read. Think of them as addressable content: files, database rows, API responses, log streams. A resource has a URI and a MIME type. The host application controls when and which resources are surfaced to the model.

    Resources are application-controlled: the host decides what to expose, not the model.

    Prompts

    Prompts are reusable prompt templates exposed by the server. A user can invoke a prompt by name (e.g., “summarise this PR”) and the server returns a structured message array ready to send to the model. Think of them as server-managed prompt libraries that clients can discover and surface in their UI.

    Prompts are user-controlled: surfaced through UI affordances for the user to invoke explicitly.

    How It Works Technically

    Transport Layer

    MCP supports two primary transports in the current spec (2025-03-26):

    stdio: The client spawns the server as a local subprocess. Messages go over stdin/stdout as newline-delimited JSON-RPC. This is the standard for local tools: filesystem, local database connections, CLI wrappers. Simple, no networking required.

    Streamable HTTP: The server runs as an independent process. The client sends JSON-RPC over HTTP POST requests. The server can optionally respond using Server-Sent Events (SSE) for streaming multiple messages back. This replaces the older SSE-only transport from the original 2024-11-05 spec, which is now deprecated.

    For local developer tooling, stdio is the default. For remote servers, shared infrastructure, or multi-tenant deployments, Streamable HTTP is the right choice.

    Capability Discovery

    When a client connects to a server, it calls initialize with the client’s protocol version and capabilities. The server responds with its own version and capabilities. The client then calls tools/list, resources/list, and prompts/list to discover what the server exposes. This discovery is dynamic: a server can change its tool list at runtime and notify connected clients.

    A Tool Call, End to End

    Here is what happens when an AI model calls a tool over MCP:

    sequenceDiagram
    participant User
    participant Host as Host App<br/>(Claude Desktop)
    participant Client as MCP Client
    participant Server as MCP Server<br/>(GitHub)
    participant Tool as GitHub API
    User->>Host: "List open PRs in repo X"
    Host->>Client: Forward to model with tool list
    Client->>Host: Model requests tools/list
    Client->>Server: tools/list
    Server-->>Client: [{name: "list_pull_requests", ...}]
    Host->>Host: Model generates tool call
    Client->>Server: tools/call {name: "list_pull_requests", arguments: {repo: "X"}}
    Server->>Tool: GET /repos/X/pulls
    Tool-->>Server: PR list JSON
    Server-->>Client: {content: [{type: "text", text: "..."}]}
    Client->>Host: Tool result
    Host->>Host: Model generates final response
    Host-->>User: "There are 3 open PRs..."

    The JSON-RPC messages are straightforward. A tool call looks like this:

    {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
    "name": "list_pull_requests",
    "arguments": {
    "repo": "nitin27may/my-app",
    "state": "open"
    }
    }
    }

    And the response:

    {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
    "content": [
    {
    "type": "text",
    "text": "Found 3 open pull requests: ..."
    }
    ],
    "isError": false
    }
    }

    The messages are plain JSON-RPC, and the same envelope works over any transport.

    The Ecosystem in Practice

    As of early 2026, the MCP ecosystem has grown substantially. Anthropic maintains official reference servers, and there are 5,000+ community servers available.

    Official servers (Anthropic-maintained):

    • @modelcontextprotocol/server-filesystem: local file operations with configurable path restrictions
    • @modelcontextprotocol/server-github: issues, PRs, repo management
    • @modelcontextprotocol/server-postgres: natural language SQL against Postgres databases
    • @modelcontextprotocol/server-slack: post messages, read channels, manage workspaces
    • @modelcontextprotocol/server-google-drive: read/search Google Drive documents

    Well-adopted community servers:

    • Browser automation (Playwright-based)
    • Jira, Linear, Notion
    • AWS, Azure, GCP management
    • Redis, MongoDB, SQLite
    • Docker and Kubernetes operations
    • Memory/knowledge graph servers

    The reference implementations are at github.com/modelcontextprotocol/servers.

    Client Support

    MCP is only useful if the clients your team uses actually support it.

    ClientWhere MCP tools workConfig
    Claude DesktopEverywhere in the chat UI (Anthropic’s initial target)claude_desktop_config.json
    Claude CodeAll chat modes; acts as both client and serverIn-app / CLI
    CursorAll chat modes; one-click setup for common serversIn-app setup
    VS Code + GitHub CopilotAgent mode only, not standard chat (GA in 1.102, July 2025)mcp.json
    JetBrains IDEsVia the AI Assistant pluginPlugin settings
    WindsurfNative MCP clientIn-app setup

    VS Code with Copilot is the most enterprise-ready option: it ships OAuth authentication and Settings Sync. The practical implication: on VS Code with Copilot, MCP tools work in agent mode; on Claude Desktop or Cursor, they’re available everywhere in the chat UI.

    MCP vs Plain Function Calling

    This is where people overthink it. Function calling and MCP are not competing approaches. They operate at different layers.

    Function calling is a model-level capability. The model receives a JSON Schema list of functions, decides which to call, generates a structured call object, and your application handles execution. It is tightly coupled to your application code. The tool list is defined and managed inside your app.

    MCP adds a network-addressable layer on top. The tool definitions live in a separate server process. Any compatible client can discover and call them without changes to the server. When you switch models, your tools keep working.

    When function calling alone is the right choice:

    • Small prototype with 2-3 tools that only one application uses
    • Tight latency requirements where spawning an MCP subprocess or making an extra HTTP round-trip matters
    • You’re using a model API directly and have no MCP client layer
    • Simple, stateless operations where reusability across clients isn’t relevant

    When MCP pays for itself:

    • Multiple AI applications or tools that need the same capabilities (your database tools shouldn’t be rewritten per client)
    • Tools that need to be tested, versioned, and deployed independently
    • You’re building tools for others to consume (internal platform teams, open source)
    • You need to support multiple model providers without changing tool definitions
    • The tool server requires its own auth, dependencies, or environment

    The break-even point is lower than you might expect. If you’re writing tool code that more than one application will use, MCP gives you the right abstraction.

    Building Your First MCP Server

    MCP has official SDKs for TypeScript and Python, with community SDKs for .NET, Rust, Go, and others. A minimal Python server with one tool looks like this:

    from mcp.server import Server
    from mcp.server.stdio import stdio_server
    from mcp import types
    app = Server("my-server")
    @app.list_tools()
    async def list_tools() -> list[types.Tool]:
    return [
    types.Tool(
    name="get_weather",
    description="Get current weather for a city",
    inputSchema={
    "type": "object",
    "properties": {
    "city": {"type": "string", "description": "City name"}
    },
    "required": ["city"]
    }
    )
    ]
    @app.call_tool()
    async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == "get_weather":
    city = arguments["city"]
    # your actual implementation here
    return [types.TextContent(type="text", text=f"Weather for {city}: 22°C, partly cloudy")]
    raise ValueError(f"Unknown tool: {name}")
    async def main():
    async with stdio_server() as (read_stream, write_stream):
    await app.run(read_stream, write_stream, app.create_initialization_options())
    if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

    The Full Interaction: Putting It Together

    Here is how all the components fit together in a production setup, from the user’s query through to the result:

    graph TD
    User([User]) -->|query| Host["Host Application<br/>(Claude Desktop / VS Code)"]
    Host -->|system prompt + tool list| Model["LLM<br/>(Claude / GPT-4o)"]
    Model -->|tool call request| Host
    Host -->|tools/call JSON-RPC| Client["MCP Client"]
    Client -->|stdio / HTTP| S1["MCP Server A<br/>GitHub"]
    Client -->|stdio / HTTP| S2["MCP Server B<br/>Postgres"]
    Client -->|stdio / HTTP| S3["MCP Server C<br/>Filesystem"]
    S1 -->|GitHub API| GH[(GitHub)]
    S2 -->|SQL| DB[(PostgreSQL)]
    S3 -->|read/write| FS[(Local Files)]
    S1 -->|tool result| Client
    S2 -->|tool result| Client
    S3 -->|tool result| Client
    Client -->|tool result| Host
    Host -->|result + context| Model
    Model -->|final response| Host
    Host -->|answer| User

    Each MCP server is deployed and versioned on its own, and any host that speaks the protocol can reuse it.

    Where This Is Going

    MCP was donated to the Linux Foundation in December 2025, which signals Anthropic’s intent: this should be infrastructure, not a product. OpenAI adopted it in March 2025. JetBrains, Microsoft (via VS Code), and the major AI cloud providers are all shipping native support.

    The ecosystem is moving fast. MCP servers for everything from databases to browser automation appear weekly. The time to understand the protocol is before your next AI feature, not after. If you’re building anything that involves an LLM calling external services, the question isn’t whether to learn MCP. It’s whether you build the right abstraction from the start or refactor to it later.

    The spec lives at modelcontextprotocol.io. The reference servers are a good place to read real implementation patterns before writing your own.

    Comments

    Comments are GitHub discussions. Sign in with GitHub to post; reactions need no account.