Skip to main content
Technology #MCP #Agent #LLM #Tool Calling #AI

MCP Fundamentals: How AI Apps Standardize External Capabilities

A structured overview of the Model Context Protocol—Host / Client / Server, Tools / Resources / Prompts, transport and lifecycle—and how it differs from Function Calling.

By Author
15 min read
MCP Fundamentals: How AI Apps Standardize External Capabilities ---

MCP Fundamentals: How AI Apps Standardize External Capabilities

Large language models are getting better at doing things: reading files, querying databases, calling APIs, running workflows. But every new capability often means another one-off adapter for each Host—IDE, desktop assistant, or custom agent. As tools multiply, integration cost and security boundaries spiral out of control.

MCP (Model Context Protocol) exists for exactly that: let AI applications connect to external tools, data, and workflows in a uniform way, instead of writing a plugin protocol for every Host.

This article starts from the definition, walks through participants, the two-layer architecture, the three primitives, lifecycle, and a typical call flow, clarifies how MCP relates to Function Calling, and closes with security principles and a practical learning path.

What Is MCP?

One-line definition

MCP is an open protocol that lets AI applications discover and call external capabilities (tools, resources, prompt templates) through a standardized Client ↔ Server conversation, instead of inventing a separate plugin protocol per Host.

It is often described as: the “USB standard” for plugging external capabilities into AI apps.

What it covers—and what it doesn’t

MCP coversMCP does not cover
How Client ↔ Server exchange context and capabilities (JSON-RPC messages, primitives, transport)How the Host picks a model, writes the agent loop, or builds UI
Semantics of Tools / Resources / PromptsBusiness logic itself (querying DBs, reading files—that’s the Server author’s job)
Cross-cutting features: capability negotiation, notifications, progressReplacing Function Calling on the model side (“I want to call a tool”)

A useful mnemonic:

Function Calling = how the model expresses “call this tool”; MCP = how tools/data are wired into the application in a standard way.

Why it’s worth learning

  • Reusable: one Server can be consumed by Claude Desktop, Cursor, VS Code, and your own Host.
  • Clear boundaries: Host / Client / Server roles separate concerns and make security edges easier to draw.
  • De facto ecosystem: many official and community Servers; multiple vendor Hosts already integrate it.
  • Fits agent engineering: if you already have tool calls, workflows, or multi-agent setups, MCP is the standard answer for the tool-integration layer.

Participants: Host / Client / Server

MCP uses a Host ↔ (many) Clients ↔ (many) Servers structure.

┌──────────────────────── MCP Host (AI app) ─────────────────────────┐
│  e.g. Cursor / Claude Desktop / VS Code / your own agent           │
│                                                                    │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐                         │
│   │ Client 1 │  │ Client 2 │  │ Client 3 │   ← one Client per Server │
│   └────┬─────┘  └────┬─────┘  └────┬─────┘                         │
└────────┼─────────────┼─────────────┼───────────────────────────────┘
         │             │             │
         ▼             ▼             ▼
   ┌──────────┐  ┌──────────┐  ┌──────────────┐
   │ Server A │  │ Server B │  │ Server C     │
   │ local FS │  │ local DB │  │ remote SaaS  │
   │ (stdio)  │  │ (stdio)  │  │ (HTTP)       │
   └──────────┘  └──────────┘  └──────────────┘
RoleMetaphorResponsibility
HostCommand centerThe AI app users face; creates Clients, drives the LLM, decides when tool results re-enter the conversation
ClientTranslator / dedicated lineEmbedded in the Host; maintains a connection to one Server, handles handshake and message routing
ServerCapability providerExposes Tools / Resources / Prompts; may be a local subprocess or a remote service

Three facts worth memorizing:

  1. One-to-one connection: one Client instance maps to one Server connection; N Servers means N Clients.
  2. “Server” does not mean “must be remote”: a local stdio subprocess is still an MCP Server.
  3. Local vs remote is mainly decided by the Transport layer.

Two layers: Data Layer + Transport Layer

┌─────────────────────────────────────────┐
│           Transport Layer (outer)       │
│   stdio  |  Streamable HTTP (+ optional SSE) │
│   connection, framing, auth             │
├─────────────────────────────────────────┤
│            Data Layer (inner)           │
│   JSON-RPC 2.0: lifecycle, primitives,  │
│   notifications, tool calls             │
└─────────────────────────────────────────┘
LayerQuestion it answersKey points
Data Layer“What do we say?”JSON-RPC 2.0; initialize, tools/list, tools/call, notifications…
Transport Layer“How do we ship it?”stdio pipes, or HTTP POST (optionally streaming); same JSON-RPC payload

When learning MCP, prioritize Data Layer primitives first; you can swap transports later without changing semantics.

Transports

Two mainstream options (per the official docs):

TransportShapeTypical useTraits
stdioHost spawns a subprocess; JSON-RPC over stdin/stdoutLocal files, local git, local DBNo network surface; lifecycle owned by Host; best for beginners
Streamable HTTPServer listens on HTTP; Client POSTs, optional SSE streamingShared remote capabilities, multi-clientStandard HTTP auth (Bearer / API Key / OAuth, etc.)

On SSE: early designs used “SSE-only” remote transport; newer specs center on Streamable HTTP, with SSE as part of streaming or a historical path. For learning and selection, remember:

Local → stdio; remote → Streamable HTTP.

Server primitives: Tools / Resources / Prompts

This is the part worth memorizing first. A Server may implement one, two, or all three.

PrimitiveMetaphorWhat it isUsually triggered byTypical methods
ToolsExecutable actionsFunctions with JSON Schema inputs (query DB, write file, call API)The model deciding mid-conversationtools/listtools/call
ResourcesReadable materialURI-addressed data (file content, schema, config snapshot)App/user injecting context, or the model reading via Hostresources/listresources/read
PromptsPreset workflow templatesParameterized prompts / few-shot templatesThe user picking a template in Host UIprompts/listprompts/get

How to tell them apart

QuestionMore like
Does it change the outside world or run computation?Tool
Is it only “inject this data into context”?Resource
Do you want a one-click fixed script / flow for users?Prompt

The same product often uses all three—for example a “database assistant”:

  • Tool: query_sql
  • Resource: db://schema (table structure)
  • Prompt: analyze-slow-query (analysis template with few-shots)

Tool metadata (what Client / LLM use to choose)

Each tool returned by tools/list typically includes:

FieldRole
nameStable unique call key
titleShort human-facing name
description“When to use this” for the model (poor wording means the model never calls it)
inputSchemaJSON Schema: types, required fields, enums

tools/call usually returns a content array (multiple text / image / resource segments, etc.), which the Host turns into a model-readable tool result.

Client-side capabilities: Sampling / Elicitation / Roots / Logging

Beyond what Servers “offer outward,” the protocol also lets a Server ask the Client / Host to do something (capabilities must be declared at handshake).

CapabilityDirectionUse
SamplingServer → ClientServer asks the Host-side LLM to complete (Server isn’t tied to one model SDK)
ElicitationServer → ClientServer requests extra user info or confirmation (form / dialog)
RootsClient ↔ ServerBounds the filesystem / URI space a Server may touch
LoggingServer → ClientStructured logs for Host debugging and monitoring

For beginners: master Server Tools first; leave Sampling / Elicitation for later.

Lifecycle and capability negotiation

Under the common stateful session model, a connection usually starts with a handshake:

Client                         Server
  |                               |
  |──── initialize (version,      |
  |      capabilities, clientInfo)──►|
  |◄─── result (version,          |
  |      capabilities, serverInfo)───|
  |──── notifications/initialized ─►|
  |                               |
  |──── tools/list ───────────────►|
  |◄─── tools[] ───────────────────|
  |──── tools/call ───────────────►|
  |◄─── content[] ─────────────────|

The handshake settles three things:

  1. Protocol version negotiation (mismatch → disconnect)
  2. Capabilities declaration (tools? list_changed notifications? …)
  3. Identity info (clientInfo / serverInfo for debugging)

Only then come discovery and calls. Methods not declared in capabilities must not be assumed available.

The spec continues to evolve (session models and HTTP deployment shapes may shift). Learn with “handshake + primitives + transport” as the spine; when coding, pin an SDK / protocol version and read its changelog.

A typical call (mental walkthrough)

With an LLM embedded in the Host:

  1. Host starts, creates a Client per configured Server, completes initialize.
  2. Client calls tools/list; Host merges tools from all Servers into one tool table for the model.
  3. User asks a question → model emits a tool call (Function / Tool Calling).
  4. Host maps the tool name to the right MCP Client → tools/call.
  5. Server runs business logic and returns content.
  6. Host writes the result back into the conversation; the model continues to a final answer.

Who calls the LLM? By default, the Host. Servers usually don’t embed a model; if they need one, they use Sampling (advanced).

Notifications and utilities

CapabilityNotes
Notificationse.g. notifications/tools/list_changed: tool list changed; Client should tools/list again (no id, no response required)
ProgressProgress reports for long tasks
Cancellation / ErrorsCancel and standard error reporting
Tasks (evolving)Long-running task handles and deferred results; shape varies by spec version

Dynamic tool lists (permission changes, hot-loaded plugins) rely on notifications; tiny static Servers can skip them at first.

MCP vs Function Calling vs A2A

ConceptLayerProblem it solves
Function / Tool CallingModel ↔ HostHow the model structurally says “call which function with which args”
MCPHost / Client ↔ ServerHow external capabilities are discovered and invoked in a standard way (reusable across apps)
A2A and similar agent protocolsAgent ↔ AgentHow multiple agents coordinate (a different layer from “plug in tools”)

As a diagram:

User ↔ Host (with LLM)
         │  Tool Calling (model decides what to call)

      MCP Client ──JSON-RPC──► MCP Server (executes / provides data)

Without MCP you can still register local functions as tools inside the Host. With MCP, the same tools can be consumed by many Hosts, and Servers can evolve and deploy independently.

Security boundaries (read before writing a Server)

MCP can open arbitrary data access and code-execution paths. Security is first-class:

PrinciplePractice tips
Least privilegeExpose only necessary tool actions; confirm dangerous ops (Elicitation / Host policy)
Roots / sandboxFilesystem Servers must restrict accessible roots
Remote authUse OAuth / tokens for Streamable HTTP; never put secrets in the prompt
Trust boundariesServers don’t see each other; Host owns isolation and user consent
Descriptions are attack surfaceTool description and return content can steer the model—guard against prompt injection

Tooling and ecosystem entry points

NameUse
MCP SpecificationAuthoritative protocol definition
Official SDKsTypeScript / Python, etc.—hide JSON-RPC boilerplate
MCP InspectorGraphical debugging: connect to a Server, exercise list / call—highly recommended for beginners
Reference ServersOfficial / community examples (filesystem, git, browser, …)

A practical local learning path:

Use Inspector as the Client → write a minimal stdio Server yourself → then build a Host that includes an LLM.

Practice roadmap: how to really learn it

Once concepts are clear, practice by keeping the product shell fixed and swapping only the MCP core—don’t pile on model and orchestration complexity too early. A strong exercise is a local Docs assistant:

  • Fixed corpus (e.g. a set of Markdown docs)
  • Fixed capability semantics: list_docs / search_docs / read_doc
  • Progressively deepen the MCP kernel, not the business logic

A five-stage progression:

StageCore questionHow to verify
A · stdio + ToolsDoes handshake / list / call close the loop?Both MCP Inspector and a minimal Host can call through
B · Resources / PromptsAre boundaries vs Tools clear?Paths that inject a resource or apply a prompt work
C · Streamable HTTPHow does remote transport differ from stdio lifecycle?Reachable over pure HTTP, no subprocess
D · Multi-language paritySame semantics across stacks (e.g. Python / TypeScript)?Same inputs and capabilities; only the implementation language differs
E · LLM Host tool loopDoes the model pick tools reliably? When do multi-round loops stop?Tool hit rate, termination reason, call rounds

Shared constraints that help:

  • Keep the UI simple (even plain HTML); focus on an MCP timeline (initialize / tools/list / tools/call)
  • Retrieval can stay naive keyword search—this track trains protocol + Host, not RAG depth
  • Prepare a few “golden questions” per stage (expected path, whether a tool should be called) for regression

Cheat sheet

  • Command center = Host, dedicated translator = Client, capability provider = Server
  • Actions = Tools, readable data = Resources, templates = Prompts
  • Local pipe = stdio, remote HTTP = Streamable HTTP
  • What we say = Data / JSON-RPC, how we ship = Transport
  • Model “wants to call” = Tool Calling, standardized “plugged in” = MCP
  • Server borrows Host’s brain = Sampling, Server asks the user = Elicitation

Closing

MCP does not replace model-side Tool Calling, nor agent-to-agent collaboration protocols. It fills the middle layer: how external capabilities are discovered, negotiated, and invoked in a standard way.

A sensible onboarding order:

  1. Internalize Host / Client / Server and the three primitives
  2. Close the loop with stdio: initialize → tools/list → tools/call
  3. Add Resources / Prompts and HTTP transport
  4. Wire a real LLM Host tool loop—and keep security and least privilege first

When you can sketch the path “model decides what to call → Host routes to which MCP Client → Server executes and returns content,” you already hold the backbone of MCP.