Cloud Engineer Lab
Cloud Engineer Lab
Cloud Engineer Lab
Cloud Engineer Lab
© 2026
MCP Explained: The New USB-C of AI Agents

MCP Explained: The New USB-C of AI Agents

A deep architectural look at MCP: what problem it solves, how client-server and auth work, and what the July 2026 spec rewrite changed.

19 min read
Share

Every developer who has connected an LLM to more than two or three external systems has hit the same wall. Wire up a database, and you write a custom integration. Wire up a ticketing system, and you write another one, with its own auth flow, its own schema conventions, its own way of describing what it can do. Add a third client application that needs the same two systems, and you're maintaining the same integration logic twice, in two codebases, that will drift out of sync within a quarter.

That's the problem Model Context Protocol was built to remove, and it's why the "USB-C for AI" comparison, overused as it's become, is actually accurate. Before USB-C, every device had its own connector and its own cable. USB-C didn't make any single device smarter. It made every device speak the same physical and electrical language, so any cable worked with any port. MCP does the same thing for AI applications and the tools, data, and systems they need to reach.

The one sentence to remember

MCP doesn't make an AI model more capable. It standardizes how any AI application connects to any external system, so that integration work gets written once instead of once per client, per server.

This is a deep architectural explainer, not a marketing pitch: what MCP actually solves, how it differs from a REST API, the full client-server model, its three core primitives, how auth works, what changes when a server is remote instead of local, the real security risks, a working first server, how this looks in production, how it compares to plain function calling, and what the July 2026 specification rewrite (2026-07-28, the biggest revision since MCP launched) actually changed under the hood.


What MCP Actually Solves

Before a shared protocol existed, connecting M AI applications to N external tools meant writing roughly M × N custom integrations. Every client had to know, ahead of time, exactly how to talk to every tool it wanted to use: which endpoint, which auth scheme, which response shape.

Without a standard: every AI client writes custom integration code for every tool it connects to
The integration count grows as M times N, and every pairing needs its own maintenance
With MCP: each client implements the protocol once, each server implements the protocol once
Any MCP client now works with any MCP server, turning M times N into M plus N

The core idea is that a server describes its own capabilities in a standard, machine-readable way, and a client discovers and uses them dynamically instead of having that knowledge hard-coded at build time. That single design choice is what makes it fundamentally different from how most APIs work today.


MCP vs REST APIs

REST and MCP solve related but distinctly different problems, and the confusion between them usually comes from both using JSON over HTTP.

REST APIMCP
Built forA developer who reads documentation once and hard-codes calls to known endpointsAn LLM that discovers what's available at connection time and decides what to call based on intent
Self-descriptionOptional (OpenAPI/Swagger, often out of date)Required and built into the protocol itself (tools/list, resources/list, prompts/list)
Message formatVaries by API: different verbs, status codes, URL conventions per serviceUniform JSON-RPC 2.0 for every server, regardless of what it wraps
DiscoveryYou read docs, then write code against a fixed set of endpointsThe client calls a listing method and gets structured schemas back at runtime
PrimitivesWhatever resource model the API designer chose (often inconsistent across APIs)Three standardized primitives: tools, resources, prompts
Typical callerApplication code written by a human developerAn LLM-driven host deciding dynamically which capability to invoke

The distinction that actually matters

REST assumes the caller already knows what it wants to call. MCP assumes the caller needs to find out what's available first, then decide, because the "caller" is often a language model reasoning about a task it wasn't specifically programmed for.

MCP isn't a replacement for REST. A well-built MCP server frequently wraps a REST API on the inside, translating that API's fixed endpoints into MCP's self-describing tools so an LLM-driven client can use it without custom glue code.


MCP Client/Server Architecture

An MCP deployment has three roles, and it's worth being precise about them because "client" and "server" alone undersell the architecture.

Host: the application the user interacts with (an IDE, a desktop app, a custom agent)
Client: lives inside the host, maintains one dedicated connection per server
Server: a focused program exposing a specific set of tools, resources, and prompts

A single host can run several clients at once, each one connected to a different server: one client talking to a filesystem server, another to a database server, another to an internal ticketing server. The host is what aggregates all of those capabilities into a single experience for the user.

Every message on the wire is JSON-RPC 2.0: requests, responses, and notifications. What differs between deployments is the transport carrying those messages:

TransportWhere it runsTypical use
stdioServer runs as a local subprocess of the host, communicates over stdin/stdoutLocal tools: filesystem access, a local git repo, a local database
Streamable HTTPServer runs anywhere reachable over the networkRemote/hosted servers shared across many users or client applications

A meaningful shift in the July 2026 spec

Earlier MCP versions opened a connection with an initialize / notifications/initialized handshake and treated that connection as a stateful session. The 2026-07-28 specification removes that handshake entirely. Every request now carries its own protocol version and client capabilities in the message's _meta fields, and a new server/discover call lets a client ask what a server supports before making any other request. The protocol core is now stateless: no session to establish, none to lose.

That change alone is worth sitting with, because it reshapes what a production MCP deployment looks like, covered in the Production Architecture section below.


Tools, Resources, and Prompts

MCP defines exactly three kinds of capability a server can expose, and the distinction between them is about who decides to invoke each one, not just what they technically do.

PrimitiveWho controls itWhat it's forExample
ToolsThe modelAn action the LLM decides to take, with structured input and a resultcreate_ticket, run_query, send_email
ResourcesThe applicationReadable data the host can attach to context, identified by a URIA file's contents, a database schema, a document
PromptsThe userA reusable template a person explicitly selects, often surfaced as a slash command/summarize-pr, /draft-release-notes

Tools are for actions the model chooses

Each tool advertises a name, a description, and a JSON Schema input shape. The model reads the description, decides a tool is relevant to the current task, and calls it with arguments that match the schema. As of the July 2026 spec, both the input and output schemas can use any JSON Schema 2020-12 keyword, not a restricted subset, giving server authors much finer control over validation.

Resources are for data the application attaches

A resource isn't something the model decides to fetch mid-conversation the way it calls a tool. It's data the host application chooses to include, browse, or let a user pick from, similar to attaching a file. Resources are addressed by URI and can be text or binary.

Prompts are for templates a person explicitly picks

A prompt is a named, parameterized template the server author has curated. A user selects it deliberately, the way they'd pick a saved snippet, rather than the model deciding to use it on its own.

Why this three-way split matters in practice

Getting this distinction right is what keeps a server's capabilities legible. A server that exposes everything as a "tool," including data that should be a resource, forces the model to guess at intent it shouldn't have to guess at, and makes the server harder for a human to audit later.


Authentication and Authorization

Local stdio servers usually don't need their own auth story. They run inside the user's own machine, under the user's own account, so the operating system's permissions are already the trust boundary. Remote, HTTP-based servers are a different matter entirely, and MCP's authorization model is built on OAuth 2.1 with PKCE.

The server acts as an OAuth Resource Server

A remote MCP server doesn't issue its own tokens. It validates tokens issued by a separate (or shared) Authorization Server, the same separation of concerns as any modern OAuth deployment.

Clients discover the authorization server through standard metadata

Rather than hard-coding auth endpoints, clients use well-known metadata discovery, so the same client code works against different deployments without per-server configuration.

Clients register with the authorization server

Historically this used OAuth Dynamic Client Registration. The July 2026 spec deprecates DCR as the primary mechanism in favor of Client ID Metadata Documents, keeping DCR available only for backward compatibility with authorization servers that don't yet support the newer approach.

The July 2026 authorization hardening, and why it exists

Six specification changes tighten MCP's OAuth flow to close a real attack class known as a mix-up attack, where a malicious authorization server tricks a client into sending a code or token intended for a different, legitimate server. The concrete fixes: authorization servers should include the iss parameter in authorization responses per RFC 9207, and clients must validate that value against the issuer they originally recorded before redeeming the code. Clients must also specify the correct application_type during registration to avoid OpenID Connect redirect URI conflicts, and must key any persisted client credentials to the specific issuer that granted them, never reusing credentials across a different authorization server.

If you're building or integrating a remote MCP server today, issuer validation isn't optional hardening to consider later. It's the specific fix for a documented attack against the exact flow MCP relies on.


Remote MCP

The distinction between local and remote MCP is really a distinction in trust model and deployment shape.

Local (stdio)Remote (Streamable HTTP)
Runs whereAs a subprocess on the user's own machineAnywhere reachable over the network
Trust boundaryImplicit: the user's own OS permissionsExplicit: OAuth 2.1 with issuer validation
Scales toOne user, one running instanceMany users and client applications sharing one hosted server
Typical ownerAn individual developer running their own toolsA company hosting one server for an entire team or product

Remote MCP is what makes MCP genuinely useful at organizational scale: one team stands up a single hosted server in front of their internal ticketing system or knowledge base, and every employee's AI client, regardless of which application they're using, connects to that same server instead of each person configuring their own local integration.

Remote MCP got dramatically simpler to operate in July 2026

Before this revision, a remote MCP server that needed to track state across a client's calls typically required sticky sessions, a shared session store, and often deep packet inspection at the load balancer to route requests from the same client consistently. With protocol-level sessions removed, a server that needs cross-call state now mints its own explicit handle and passes it back to the client as an ordinary tool argument. The server itself can sit behind a plain round-robin load balancer with no session affinity at all. The spec also now requires standard Mcp-Method and Mcp-Name headers on every Streamable HTTP request, so infrastructure can route and rate-limit by operation without inspecting the request body.

One trade-off is worth knowing: the same revision removes SSE stream resumability (the Last-Event-ID mechanism). If a response stream breaks mid-request, the client can no longer resume it. It simply re-issues the whole request as a new one. That's a deliberate simplicity-over-resilience trade, consistent with the stateless-core theme of the whole release.


MCP Security

Connecting an LLM to live tools and data widens the attack surface in ways a pure chat interface doesn't have, and MCP's own design amplifies a few specific risks worth naming directly.

Tool descriptions and resource content are an injection vector

An LLM reads a tool's description and any resource content as part of its context, the same way it reads a user's message. A malicious or compromised server can embed hidden instructions inside a tool description or inside the content of a resource, and a model that doesn't clearly separate "data" from "instructions" may follow them. Treat every third-party MCP server's descriptions and resource content the way you'd treat untrusted user input, not trusted documentation.

Tool names and descriptions can mislead about actual scope

A tool called read_file that quietly also has write or delete access is a real, documented failure pattern. Review what a tool's implementation actually does, not just what its name and description claim.

Local servers run with the user's own permissions

A stdio server is a subprocess running under the user's account. Installing a third-party MCP server carries the same supply-chain risk as installing any other dependency with broad filesystem or network access, and deserves the same scrutiny.

Authorization mix-up attacks are a named, addressed risk

Covered above in Authentication and Authorization: the July 2026 issuer-validation requirement exists specifically because this attack was demonstrated against real OAuth-based MCP deployments, not as a theoretical hardening exercise.

The practical baseline

Require explicit human confirmation before any tool call that deletes data, moves money, or sends a communication on someone's behalf. Run untrusted or third-party servers with the least privilege they need, never broader access "to be safe." Validate authorization server issuers per the current spec if you're handling remote OAuth flows yourself rather than relying entirely on your client library.


Building Your First MCP Server

Here's a minimal but complete server using the official TypeScript SDK, exposing a single tool over stdio:

typescript
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
 
const server = new McpServer({ name: 'greeting-server', version: '1.0.0' });
 
server.registerTool(
  'greet',
  {
    description: 'Greet someone by name',
    inputSchema: z.object({
      name: z.string().describe('The person to greet'),
    }),
  },
  async ({ name }) => {
    return {
      content: [{ type: 'text', text: `Hello, ${name}!` }],
    };
  }
);
 
server.connect(new StdioServerTransport());

Define the server identity

McpServer takes a name and version. This is what shows up when a client calls the discovery method to identify what it's connected to.

Register a tool with a schema, not a hand-written spec

The Zod schema passed to inputSchema does three jobs at once: it generates the JSON Schema advertised to clients, it validates incoming arguments before your handler ever runs, and it gives your handler's parameters proper types. You write the shape once.

Return structured content, not a raw string

A tool result is a content array of typed blocks, text here, though a real tool can return multiple blocks or richer types. This is what lets a single tool result carry more than plain text if the task calls for it.

Connect a transport, and the server is live

StdioServerTransport is the right choice for a local tool run as a subprocess. Swapping to a Streamable HTTP transport is what turns the same server into a remote one, with everything in the Remote MCP section above then applying.

Check the SDK version before shipping

MCP's SDKs evolve alongside the spec. Package names, exact function signatures, and available options can shift between releases. Treat the example above as the shape of a minimal server, and confirm against your installed SDK's own documentation before deploying anything real.


Production Architecture

A server that works from your laptop over stdio and a server that holds up in production for an organization are different engineering problems. A few things the July 2026 spec makes directly relevant to production deployments:

ConcernWhat changed or what to do
Horizontal scalingProtocol-level sessions are gone, so a server needing cross-call state mints its own explicit handle instead of relying on sticky routing. This means ordinary round-robin load balancing works, no session affinity required.
Routing and rate-limitingEvery Streamable HTTP request now carries Mcp-Method and Mcp-Name headers, so a gateway can route and throttle by operation without parsing the JSON-RPC body.
Cachingtools/list, prompts/list, resources/list, and resources/read responses now carry a ttlMs freshness hint and a cacheScope (public or private) flag, giving clients and intermediaries an explicit, spec-defined way to cache instead of guessing.
ObservabilityThe spec documents standard _meta keys for OpenTelemetry trace propagation (traceparent, tracestate, baggage), so a server's calls can participate in a distributed trace using conventions the protocol itself defines.
Stream resilienceSSE resumability was removed. Design your client's retry logic around re-issuing a fresh request on a broken stream, not resuming a partial one.
Deterministic tool orderingServers should return tools/list results in a stable, deterministic order. This isn't cosmetic: it directly improves client-side caching and LLM prompt cache hit rates against the tool list.

Roots, Sampling, and Logging are now deprecated

The same revision deprecates three older features. Instead of the Roots feature, pass directories or files as tool parameters, resource URIs, or server configuration. Instead of the Sampling feature, integrate directly with your LLM provider's API. Instead of the Logging feature, log to stderr on stdio or use OpenTelemetry. They remain functional during a minimum twelve-month deprecation window, but new production builds shouldn't add new dependencies on any of the three.


MCP vs Function Calling

These get confused constantly because MCP tools, at the wire level, are ultimately delivered to a model as something very close to a function-calling schema. The difference is entirely in what sits around that schema.

Plain function callingMCP
Where tool definitions liveHard-coded in your application's own codeAdvertised dynamically by a server your client connects to
Reusability across appsNone: every application redefines the same toolOne server's tools are usable by any MCP-compatible client, with zero redefinition
DiscoveryStatic, decided at build timeDynamic, via tools/list at connection time
Standardized primitives beyond toolsNone: you invent your own conventions for anything elseResources and prompts are first-class, standardized alongside tools
Cross-team or cross-vendor sharingRequires distributing and syncing your own integration codeA server is the shareable, portable unit

They're not competitors

MCP tools ultimately get presented to the model as function-calling-shaped definitions; that part isn't new. What MCP adds is everything around it: a standard way to discover those definitions at runtime, a standard transport and auth model, and two more primitive types that function calling alone never defined. Function calling is the mechanism; MCP is the protocol for delivering it portably.


Where MCP Is Going

The July 2026 specification isn't a small point release. It's described by its own authors as the largest revision since MCP launched, and it delivers on a roadmap built around four goals: a stateless core that scales on ordinary HTTP infrastructure, an authorization model that matches how OAuth and OpenID Connect are actually deployed, a formal deprecation policy so the protocol can keep evolving without breaking existing servers overnight, and a real extensions framework for functionality that doesn't belong in the protocol core.

That last point is where the near-term future is heading. Rather than growing the core specification indefinitely, new capability now ships as opt-in extensions:

ExtensionWhat it adds
TasksLong-running, asynchronous work tracked through durable handles, replacing the older blocking task-result pattern with polling
Skills over MCPA way to expose structured, packaged skills through the same protocol servers already use for tools
MCP AppsServer-rendered, inline interactive UI, rather than plain text or structured data as the only response shape

A formal deprecation policy is a bigger deal than it sounds

Before this revision, MCP had no defined process for retiring a feature. The new feature lifecycle policy establishes Active, Deprecated, and Removed states with a minimum twelve-month deprecation window. That predictability is what lets the protocol keep changing, as it clearly intends to, without every server maintainer treating each new spec date as a potential breaking migration with no warning.


The Bottom Line

MCP's real contribution was never a clever new wire format. It was deciding that AI applications and the tools they use should agree on one shared language instead of every pairing inventing its own. The July 2026 specification pushes that idea further: a stateless core that scales the way ordinary web infrastructure already knows how to scale, authorization hardened against a real attack class, and new capability landing as opt-in extensions instead of an ever-growing core.

Where to actually start

If you're building your first MCP server, start local: a stdio server with one or two well-described tools, tested against a real client. Everything in this guide about remote deployment, authorization, and production architecture becomes relevant the moment that server needs to serve more than one user, and not a moment before.

The USB-C comparison holds up because it's the right kind of boring. A good connector standard doesn't make headlines for what it does. It makes headlines for how much custom cabling nobody has to build anymore.

CChetan Yamger

Written by

Chetan Yamger

Cloud Engineer · AI Automation Architect · Modern Workplace Consultant

Cloud Engineer, AI Automation Architect, and Modern Workplace Consultant based in Amsterdam, Netherlands. Specializing in scalable, secure enterprise solutions with Microsoft Azure, Intune, PowerShell, and AI-driven automation using ChatGPT, Gemini, and modern LLM technologies.

Cloud & Modern WorkplaceMicrosoft Intune & MDMAzure & Microsoft 365AI AutomationPrompt EngineeringPowerShell & Graph APIWindows AutopilotConditional Access & Zero TrustSCCM / MECM & MSIXVDI / WVDPower BINode.js & Next.js
Newsletter

Stay in the loop.
New articles, straight to you.

Deep-dive technical articles on Intune, PowerShell, and AI — no noise, no spam.

New article notifications
No spam, ever
Free forever

Discussion

Share your thoughts — your email stays private

Leave a comment

0/2000

Your email is used to prevent spam and will never be displayed.