What is MCP? How AI Agents Plug Into the World (MCP Series, Part 1)

Introduction

Not so long ago, every phone brand shipped with its own charger. Nokia had its pins, Samsung had a different port, and Apple had yet another. Leave yours at home and you were stuck, even in a room full of chargers.

AI applications ran into the same problem. Every app that wanted to read a file, query a database, or call an API needed its own custom connector, built for that one pairing of app and service. The Model Context Protocol (MCP) fixes that: one standard "charging port" for connecting AI applications to tools and data.

This is the first article in a series on MCP. Over the next few parts, we will cover:

  1. What is MCP? (this article)
  2. The difference between MCP and an API
  3. What changed in the new MCP version: sampling, logging (and the OpenTelemetry workaround), roots being deprecated, and others
  4. The new MCP version deep dive: handling state in a stateless infrastructure (HTTP+SSE vs Streamable HTTP)
  5. MCP on AWS: event functions or web functions, and why
  6. Handling MCP auth in web functions
  7. AWS infrastructure MCP

In this article, we focus on the foundation: how an agent connects to resources through MCP, the roles involved, what a server can offer, and how one MCP server works with several clients at once.

Prerequisite: You should have a basic idea of what an LLM is and have called an HTTP API before. No MCP experience needed.

Note: Everything here is based on the current MCP specification, revision 2026-07-28. If you read MCP tutorials from 2025, a few things (like the initialize handshake and sessions) have changed. I will point them out as we go.

How Agents Reached Tools Before MCP

An LLM on its own only knows what it learned during training. It cannot check today's exchange rate, read your Jira board, or query your Postgres database. To do anything useful in the real world, an agent needs a way to reach out to resources.

Before MCP, the usual approach was function calling (also called tool use). You describe a function to the model in your request, the model replies with "call this function with these arguments", your code executes it, and you send the result back. That works, but all the wiring (tool definitions, execution, auth, retries) lives inside that one application.

Now multiply that. Say your company has 4 AI applications (a chat assistant, an IDE plugin, an internal agent, and a support bot) and 5 services they need (GitHub, Slack, a database, Google Drive, and your billing API). Without a shared standard, you are looking at up to 4 × 5 = 20 separate integrations, each built and maintained on its own.

This is the classic N × M integration problem. MCP turns it into N + M: each AI application implements the protocol once, each service implements it once, and they can all talk to each other. In our example, that is 4 + 5 = 9 implementations instead of 20.

Before we dive deep, let's define MCP properly.

So, What Is MCP?

The Model Context Protocol (MCP) is an open standard that defines how AI applications discover and use external tools, data, and prompt templates through one common interface.

Notice the word protocol. MCP is not a library, a framework, or a product. It is a set of rules, the same way HTTP is a set of rules. It defines:

  • Who talks to whom: a host, its clients, and servers (more on these shortly).
  • What a server can offer: tools, resources, and prompts.
  • How messages are encoded: every message is JSON-RPC 2.0.
  • How messages travel: stdio for local servers, Streamable HTTP for remote ones.
  • How remote servers are secured: an OAuth-based authorization framework.

The official MCP docs compare it to a USB-C port for AI applications, which is the grown-up version of my charger story. Build one MCP server for your service, and any MCP-compatible application (Claude, ChatGPT, Cursor, VS Code, or your own agent) can use it.

The Three Roles: Host, Client, and Server

MCP has three roles. Once you get these, everything else falls into place.

  • Host: The AI application the user actually interacts with: Claude Desktop, Cursor, VS Code, or a custom agent you built yourself. The host owns the conversation, the model, and the user's trust.
  • Client: A connector that lives inside the host. The host creates one client for each server it connects to, and each client keeps a one-to-one relationship with its server.
  • Server: A program that exposes capabilities. It might wrap a database, a file system, a SaaS product like GitHub, or your own HTTP API.

Going back to the charger analogy: the host is your phone, each client is a port on the phone, and each server is whatever you plug into that port.

Here is the key point people often miss: the model never talks to the server directly. When it wants to use a tool, it tells the host, and the host's client makes the call. The host stays in control of what gets called and what the user sees. That separation is deliberate; it is where user consent and security checks happen.

How MCP Clients and server connect

Host A runs two clients, one per server it uses. The billing server is shared: Host A's Client 2 and Host B's Client 1 both talk to it.

What an MCP Server Can Offer

An MCP server exposes its features through three primitives. The difference that matters most is who decides when each one gets used.

Primitive Controlled by What it is Example
Tools The model Functions the model can call, each with a name, description, and JSON Schema input calculate, create_invoice, search_issues
Resources The application Read-only context identified by a URI file:///project/README.md, a customer record
Prompts The user Reusable prompt templates, often shown as slash commands "Summarize this incident", "Draft a release note"

Tools are by far the most used. When people say "we built an MCP server for our API", they almost always mean a set of tools that call API endpoints.

There is also one feature that flows the other way, from client to server: elicitation. It lets a server ask the user for missing input in the middle of a request, for example "which account should I debit?" before a transfer goes through.

Note: Earlier spec revisions also had roots, sampling, and logging as client-side features. The 2026-07-28 revision deprecated all three. They keep working for at least twelve months under the new deprecation policy, but new implementations should not adopt them. We will dig into this, and the workarounds, in Part 3 of this series.

How a Request Flows, End to End

Let's say we built a Calculator MCP server. It exposes a single tool, calculate. Here is how the server describes that tool when a client asks with tools/list:

{ "name": "calculate", "title": "Calculator", "description": "Performs basic arithmetic on two numbers. Use it whenever an exact result is needed instead of estimating.", "inputSchema": { "type": "object", "properties": { "operation": { "type": "string", "enum": ["add", "subtract", "multiply", "divide"], "description": "The operation to perform" }, "a": { "type": "number", "description": "First operand" }, "b": { "type": "number", "description": "Second operand" } }, "required": ["operation", "a", "b"] }, "annotations": { "readOnlyHint": true } } 

That definition is all the model will ever know about our server. It never sees our code, so the name, description, and schema have to explain the tool on their own. A vague description means wrong calls.

Now, when you ask an agent "What is 1,250 multiplied by 12?" and it uses the calculator server to answer. Here is what happens under the hood:

  1. Connect: You add the server to your host, either as a local command (stdio) or a URL (Streamable HTTP).
  2. Discover: The client asks the server what it offers with tools/list (and, where relevant, resources/list and prompts/list). This is where it receives the calculate definition above.
  3. Present: The host passes the tool names, descriptions, and input schemas to the model alongside your message.
  4. Decide: The model decides a tool would help and produces arguments that match the tool's input schema. For our question, that is a multiply with a = 1250 and b = 12.
  5. Confirm: The host can ask you to approve the call. The spec expects hosts to keep a human in the loop and let users deny tool calls.
  6. Call: The client sends tools/call to the server.
  7. Return: The server does the work (1,250 × 12 = 15,000) and returns the result. The host adds it to the conversation, and the model writes its answer.

Here is step 6 on the wire. Over Streamable HTTP, the client sends this request:

POST /mcp HTTP/1.1 Content-Type: application/json Accept: application/json, text/event-stream MCP-Protocol-Version: 2026-07-28 Mcp-Method: tools/call Mcp-Name: calculate { "jsonrpc": "2.0", "id": 7, "method": "tools/call", "params": { "name": "calculate", "arguments": { "operation": "multiply", "a": 1250, "b": 12 }, "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} } } } 

Two things are worth noticing in that request:

  • Every request is self-contained. Look at the _meta field carrying the protocol version and client capabilities, plus the Mcp-Method and Mcp-Name headers. In older revisions, the client and server first did an initialize handshake and shared an Mcp-Session-Id. In 2026-07-28, both are gone. A client that wants to know what a server supports up front can call the new server/discover method.
  • Errors are results, not crashes. If the model asks the calculator to divide by zero, the server should return a normal result with isError: true and a readable message. The model can read it and try again with better arguments.

One Server, Many Clients

Inside a host, each client talks to exactly one server. But the reverse is not true: a single MCP server can serve many clients at the same time.

Take a remote MCP server for your company's billing API. On a normal workday:

  • Babalola has it connected in Claude Desktop.
  • Aina has it connected in Cursor.
  • An internal support agent running in the cloud calls it on every ticket.

That is three hosts, three separate clients, and one server. Each client discovers the same tools, but each one sends its own requests with its own credentials.

How the server handles this depends on the transport:

  • stdio servers are one-to-one by nature. The host launches the server as a subprocess, so every host gets its own private copy of the server process. Three users means three processes. Client and server must be running on the same machine.
  • Streamable HTTP servers are shared. One deployment exposes a single endpoint, like https://billing.example.com/mcp, and every client sends its requests there.

For remote servers, the 2026-07-28 revision made this a lot easier. Since every request now carries everything the server needs, any request can land on any server instance. You no longer need sticky routing or a shared session store just to keep the protocol working. Put three instances behind a load balancer and let any of them answer.

What if a tool genuinely needs memory between calls, like a shopping cart or a multi-step booking? State becomes explicit. The tool returns a handle (say, a cartId), and the client passes that handle back as an argument in later calls. The connection itself is no longer a session.

The new stateless design makes MCP fits serverless platforms like AWS Lambda, and it is the main subject of Parts 4 and 5.

Transports: stdio vs Streamable HTTP

The same JSON-RPC messages can travel over two standard transports. The protocol is identical on both; only the delivery changes.

stdio Streamable HTTP
Where the server runs A local subprocess launched by the host An independent web service
How messages travel Newline-delimited JSON over stdin/stdout Each message is its own HTTP POST to one endpoint
How responses come back Written to stdout A single JSON response, or an SSE stream scoped to that one request
Credentials Environment variables OAuth-based authorization framework
Best for Local files, CLIs, local databases, development Shared, hosted, multi-user servers

You may also come across tutorials that open a GET /sse stream on a separate endpoint. That is the older HTTP+SSE transport from the 2024-11-05 revision, and it is now formally deprecated. We will break down HTTP+SSE vs Streamable HTTP properly in Part 4.

Conclusion

MCP did not make AI agents smarter. It made them connectable.

With MCP, a service builds one server, and any compliant host can use it. The host stays in control, the model gets a clean menu of tools, and the server does the actual work.

Next up is Part 2: MCP vs API. If most MCP servers call an API under the hood, do the two complement each other, or is one replacing the other? We’ll break down where they differ and when you need each.

References

  1. Model Context Protocol: official documentation and specification
  2. MCP 2026-07-28 changelog
  3. MCP transports (2026-07-28)
  4. MCP tools specification (2026-07-28)
  5. Anthropic: Introducing the Model Context Protocol

——————————————

For more articles, follow my social handles: