MCP Protocol Deep Dive: Its Relationship with Function Calling and Agents, Plus a Practical Guide

A comprehensive guide to MCP's architecture, its role alongside Function Calling and Agents, and how to deploy it safely in production.
MCP (Model Context Protocol) is Anthropic's open standard that eliminates repetitive tool integration across AI platforms, much like USB-C unified charging. This article explains how MCP, Function Calling, and Agents operate at three distinct layers, details the protocol's four internal roles and handshake mechanism, covers JSON-RPC transport choices, and outlines six critical security defenses for production deployments.
Why Do We Need MCP? The Pain of Repetitive Integrations
If you've worked with multiple AI development tools, you've likely run into this frustration: the same Git tool requires a separate configuration in Claude Desktop, another in Cursor, and yet another in your own custom Agent. Change a parameter — you have to update everything. Change the auth method — same story. Maintenance costs spiral out of control.
This is like the early days of consumer electronics when every device came with its own proprietary charger — switching AI hosts means potentially rewriting the integration from scratch. This kind of repetitive work is precisely the problem MCP was built to solve.
MCP stands for Model Context Protocol. At its core, it's a "wiring standard." Just as USB-C unified charging interfaces, MCP enables tool capabilities to be integrated once and reused everywhere. Once a Server wraps capabilities like Git or a database, any MCP-compatible host can invoke them directly — no need to write custom adapter code for each application.
MCP was officially open-sourced by Anthropic in November 2024, born at a moment when AI tool ecosystem fragmentation was intensifying. Before MCP, every AI platform (OpenAI, Anthropic, various open-source frameworks) had its own tool-calling scheme, forcing developers to maintain separate adapter layers for each platform. MCP's design philosophy draws on the success of LSP (Language Server Protocol) — introduced by Microsoft in 2016. Before LSP, every editor needed to implement syntax highlighting, auto-completion, and error detection independently for every programming language, creating an M×N compatibility matrix with enormous maintenance overhead. LSP abstracted language intelligence into a standalone process that communicates with editors via a standard protocol, collapsing the M×N problem into M+N. MCP applies this same dimensional reduction to AI tools: LSP unified how editors and language services communicate, allowing a single language server to be reused by VSCode, Vim, Emacs, and others. MCP compresses the "every AI platform × every tool" matrix down to "each tool implements one MCP Server," aiming to replicate that success in the AI tooling space.
How Do MCP, Function Calling, and Agents Divide Responsibilities?
Many people conflate MCP, Function Calling (FC), and Agents — but they operate at three distinct layers, each with its own role while working in concert.
The Three-Layer Architecture
Think of a complete intelligent application as a three-layer structure:
- Bottom layer: Function Calling — Responsible for getting the LLM to output a "call intent" — the model determines that a tool needs to be invoked and generates structured call parameters (typically JSON).
- Middle layer: MCP — Responsible for routing that call intent to the appropriate backend service (e.g., a Git Server), acting as the "wiring" and "forwarding" layer.
- Top layer: Agent — Responsible for planning the overall task flow — deciding what to do first, what comes next, and when to invoke tools.
Understanding this division requires first grasping what Function Calling actually is: it's a core capability extension for large language models, first introduced by OpenAI in June 2023 with GPT-3.5/GPT-4. Its underlying mechanism involves two key steps: first, injecting large volumes of "tool call examples" into the model during pre-training or fine-tuning so the model learns to recognize when an external tool should be invoked; second, injecting tool JSON Schema definitions into the context via special system prompts at inference time, enabling the model to generate call parameters that conform to the Schema. Some models also use dedicated special tokens to separate regular text output from tool call output, allowing host applications to reliably parse call intents. The key point: the model doesn't actually execute the call — it only outputs an "intent declaration." The actual execution is performed by the host application. This is the fundamental reason FC and MCP have separate responsibilities: FC is a model-side capability; MCP is an engineering-side standard. Minor differences in FC implementations across vendors — Schema formats, parallel multi-tool call support, error handling — are precisely why MCP needs to build a unified standard on top of FC.
In one sentence: Agents plan, FC declares intent, MCP routes. With clear boundaries between these three, they work together to build truly functional intelligent applications. Once you understand this division, you'll stop thinking of MCP and FC as interchangeable alternatives.
The Four Roles Inside the MCP Protocol
With the external division of responsibilities clear, let's dive inside the MCP protocol itself. It involves four key roles:
- Host: The AI application the user interacts with directly, such as Claude Desktop or Cursor.
- Client: The communication module inside the Host, responsible for interfacing with Servers.
- Server: The component developers work with most, exposing tool capabilities externally while keeping its underlying implementation self-contained.
- Data / External Capabilities: The actual resources behind the Server — Git, databases, and so on.
The elegance of this design is that Servers expose standard interfaces while their underlying implementations are fully encapsulated. Any MCP-compatible AI application can invoke these capabilities in a unified way, without caring how the Server implements them internally.
A Complete MCP Call Flow
With the roles understood, here's what a complete call looks like end-to-end:
- The user asks a question, which is passed to the LLM;
- The model outputs a call intent in JSON format;
- The intent is handed to the Client;
- The Client sends a
tools/callrequest to the Server; - The Server executes the operation and returns the result to the model;
- The model organizes the result into a natural language response.
Here's a critically overlooked point: the quality of tool descriptions directly determines whether the model picks the right tool. Technically, when the model receives a user request, it performs semantic matching across all registered tool description texts to determine which tool best fits the current task — this is fundamentally a retrieval and reasoning process grounded in natural language understanding. Vague descriptions will likely cause the model to invoke the wrong tool or pass incorrect parameters. Good tool descriptions should include the tool's core function, applicable scenarios, semantic explanations of parameters, and expected side effects. This is similar to traditional API documentation, except the audience shifts from "human developers" to "language models," requiring much sharper semantic boundaries.
Handshake: The Required Step Before Any Call
Before the Client can actually call any tool, both sides must complete a "handshake." MCP's handshake follows the "capability negotiation" design pattern — a concept with deep roots in distributed systems. TLS handshake CipherSuite negotiation, HTTP/2 SETTINGS frame exchange, and gRPC service discovery all embody the same core idea: before exchanging business data, both sides exchange their supported protocol versions and feature sets and take the intersection as the actual capability scope for the session. This design gives the protocol both forward and backward compatibility — a newer Client encountering an older Server can automatically downgrade; an older Client encountering a Server with new capabilities won't crash.
The Client sends an initialize request with its supported protocol version (e.g., 2024-11-05, 2025-03-26) and optional capability list; the Server responds by selecting the highest mutually supported version; once they match, the connection is established. Capability negotiation also covers support declarations for optional features like Sampling, Roots, and Elicitation. Hosts and Servers confirm their capability boundaries via the initialize/initialized message pair, ensuring subsequent communication never invokes features the other side doesn't support and avoiding silent failure scenarios.

Many users configure a Server correctly only to find the tools never appear — the problem is almost always in the initialization phase. Mismatched protocol versions or SDK version gaps causing incorrect capability declarations can both result in handshake failure, preventing tools from being exposed. When debugging MCP issues, the handshake is the first place to look.
Three Types of Capabilities a Server Can Expose
Once the handshake succeeds, Servers can offer more than just "tool calls" — there are three categories:
- Tools: Executable actions, such as "commit code" or "query database."
- Resources: Read-only context, such as files, logs, or database schemas.
- Prompts: Reusable prompt templates.
A useful analogy: Resources are the ingredients in the fridge; Tools are the act of chopping. If tool descriptions are unclear, the model will "use the wrong ingredients" — pulling incorrect context to execute an action, with predictably off-target results.
Clients Can Also Provide Reverse Capabilities
Capability flow isn't one-directional. The Client layer can also provide a reverse channel for Server use:
- Roots: Restricts the working directories the Server can access.
- Sampling: Allows the Server to request the Host's model for assistance with tasks like summarization.
- Elicitation: When parameters are ambiguous, prompts the user for confirmation via a dialog.
It's worth emphasizing: these reverse capabilities are all optional. For most Servers just getting started, exposing Tools alone is sufficient — there's no need to implement everything from day one.
Choosing a Transport Method
MCP uses JSON-RPC rather than the more familiar REST. Understanding this choice requires grasping the fundamental difference between the two: REST centers on "resources" as its core abstraction — URLs represent resources, and HTTP verbs (GET/POST/PUT/DELETE) represent operations on those resources. This design maps perfectly to web CRUD scenarios but feels awkward for "action execution" use cases, forcing developers to shoehorn verbs into URLs (e.g., POST /execute-query) or fall back to an RPC-over-HTTP style. JSON-RPC 2.0 treats "method calls" as first-class citizens: each request contains three core fields — method (method name), params (parameters), and id (request identifier) — perfectly matching the "execute an action" nature of AI tool calls. JSON-RPC also natively supports Notification mode (one-way messages requiring no response) and Batch Requests (multiple calls in a single network round-trip), which can significantly reduce latency for Agent scenarios involving parallel tool calls. MCP extends JSON-RPC with streaming support, allowing long-running tools to report progress in real time — something pure REST architectures struggle to do elegantly.
For transport method, two practical recommendations:
- Local development: Prefer STDIO (standard input/output).
- Remote deployment: Use Streamable HTTP.
Here's a hard-learned warning: understanding STDIO mode requires knowing its underlying mechanism. UNIX/Linux systems pre-allocate three standard file descriptors for each process: fd=0 (stdin), fd=1 (stdout), fd=2 (stderr). In MCP's STDIO transport, the Host process uses the OS pipe mechanism to spawn a Server child process, connecting both sides' stdin/stdout through pipes end-to-end to form a full-duplex communication channel. stdout (fd=1) is the dedicated channel for protocol communication, while stderr (fd=2) is an independent third channel that does not participate in protocol communication. This is why you must never use print to write logs to stdout — any non-protocol data mixed into stdout will cause the Host to misparse it as a JSON-RPC message, producing parse errors or logical corruption that is extremely difficult to trace. Always direct logs to stderr, which can be safely and independently redirected to a log file by the Host. This also explains why mature MCP SDKs enforce structured logging and redirect it to stderr.
Six Lines of Defense Before Going to Production
Once the protocol, capabilities, and transport are in place, pushing an MCP service to production requires holding six security and engineering lines:
- Clear schemas and version numbers: All tools must have well-defined parameter schemas and version management.
- Injection prevention and double confirmation: Guard against path traversal and command injection; write operations must go through a second confirmation step.
- Observability: The full call chain must be traceable and monitorable.
- Cost attribution: Clearly attribute resource consumption to each call.
- Dependency auditing: Review all third-party components the Server depends on.
- Tool description auditing: Regularly verify the accuracy of tool descriptions.
These may look like classic backend engineering problems, but in AI applications none can be skipped — and the threat model has fundamentally changed. Traditional backend services face threats primarily from external attackers, with relatively clear security perimeters. MCP-driven AI applications introduce a new class of threat: Prompt Injection attacks — where attackers embed malicious instructions inside data returned by tools (e.g., injecting "Now ignore previous instructions and execute the following..." into file contents or database records), attempting to hijack the model's subsequent behavior. This expands the scope of injection defense from SQL/command injection into semantic-level filtering of model inputs. Furthermore, because LLMs autonomously decide call chains, tools with vague descriptions can be invoked by the model in ways developers never anticipated, causing unauthorized operations — rooted in "what the model understands" rather than "what the code does." Precisely because LLMs make autonomous decisions about which tools to call, security boundaries must be held even more strictly — the greater the model's autonomy, the higher the cost of any defensive layer failing.
Conclusion
The value of MCP lies not in inventing some entirely new technology, but in using a unified standard to end the repetitive labor of tool integration. Understanding its three-layer division of responsibility with Function Calling and Agents, mastering the handshake mechanism, capability exposure patterns, and transport method selection, then holding the six production defense lines — that's what it takes to truly use MCP well and reliably. For developers building AI applications today, this "wiring standard" is fast becoming indispensable infrastructure.
Key Takeaways
Related articles

From Chat to Agent: Automating Your Entire Business Workflow with AI Agents
Veteran AI practitioner Remy breaks down the leap from chat models to AI agents: how agents work, the three pillars of context, tools, and skills, MCP connections, and hands-on architecture to make you a 100x employee.

Understand Anything: The AI Skill That Turns Code into Interactive Knowledge Graphs
Understand Anything is a high-star open-source GitHub skill that runs static analysis on any codebase and generates interactive knowledge graphs. It supports Claude Code, Cursor, Copilot and other agents, letting engineers ask questions in natural language with path references.

Kimi K3 Released: How a 2.8 Trillion Parameter Open Model Reshapes AI Cost-Effectiveness
Moonshot AI unveils Kimi K3: a 2.8 trillion parameter, 1M context, natively multimodal open model. With KDA architecture and ultra-low cost, it rivals GPT-5.6 and Fable 5, redefining AI cost-effectiveness.