Model Context Protocol (MCP): Connect AI to Your Tools and DataPrimitives, client features and transports · Lesson 5 of 18
Transports: stdio, Streamable HTTP and running at scale
Video lecture
Transports: stdio, Streamable HTTP and running at scale
The narrated lecture is in production
Every chapter is scripted and ready. Browse the chapters and read the full transcript now — the video will appear here when it’s published.
Chapters
Transcript of the narration, chapter by chapter.
0:00 Transports
How do messages actually get between an AI app and an MCP server? There are two standard ways, and choosing the right one affects security, scaling and how you deploy. In this lesson you'll learn standard I O and Streamable HTTP, what changed in twenty twenty six, and how to protect local servers from a sneaky browser attack.
0:25 Why transports matter
Why do transports deserve a whole lesson? Because the transport decides who can reach your server, how it authenticates, and how it scales. Think of standard I O as a private phone line inside your house: only the person who picked up can talk, and there's no one else on it. Streamable HTTP is a public shop front: anyone can walk up to the counter, so you need a door policy, opening hours and a queue system. Choose the wrong one, and you either can't share your tool, or you've left the shop unlocked.
1:06 stdio
With standard I O, the client launches your server as a subprocess and they swap JSON messages, one per line, over standard input and output. Your server can log to standard error, but it must never write anything else to standard output, because that channel is the protocol. This is ideal for local tools like file access, local databases and developer utilities, and credentials come from environment variables rather than OAuth.
1:37 Streamable HTTP
Streamable HTTP runs your server as a web service with a single endpoint, usually slash M C P. The client posts each message. The server replies with a JSON body, or, if it needs to send progress updates first, a server sent events stream for that one response. It's the right choice for remote, shared and multi user servers, and it uses OAuth for authorization. The older HTTP plus SSE transport, with two endpoints, is formally deprecated, so don't build on it.
2:13 HTTP in 2026-07-28
The twenty twenty six spec made HTTP much simpler to scale. There are no sessions, so every request stands alone. Posts must carry M C P method and M C P name headers, so gateways can route and authorize on headers. The old GET stream is replaced by an opt in subscriptions listen request for change notifications. Stream resumability is gone, so if a stream breaks, the client simply re issues the request, which means your tools should be idempotent. And list results carry cache hints.
2:50 Simple example: a notes-search server
A simple example. You build a server that searches your own notes folder. For yourself, standard I O is perfect: your AI app launches it, it reads your local files, and nothing listens on the network. Now your team of five wants the same thing over a shared drive. You switch to Streamable HTTP, deploy it on an internal host with company sign in, and each teammate adds the URL. Same tools, same code, different transport, and suddenly authentication and rate limits matter.
3:26 Local server security
Now a security trap. If you run an HTTP server on localhost, any web page the user visits can try to reach it through a trick called DNS rebinding. The page's domain suddenly resolves to your own machine, and the browser treats your server as same origin. Defend it: bind to one two seven dot zero dot zero dot one, not all interfaces, validate the host and origin headers, and require auth for anything non trivial. The official TypeScript Express helper turns these checks on by default. And for standard I O servers, remember the host runs your command with the user's privileges, so only install servers you trust.
4:13 Choosing a transport
How do you choose? A personal tool on a laptop touching local files: standard I O. A team or company wide service: Streamable HTTP with OAuth. A software vendor offering an integration to customers: Streamable HTTP with OAuth, listed in registries. A desktop app bundling a helper: usually standard I O. And serverless or edge deployments: Streamable HTTP, since stateless servers fit perfectly.
4:40 Example: laptop to team service
A worked example. A data analyst in Lahore builds a standard I O server with read only SQL over marketing data. Colleagues want access. Moving to HTTP takes five steps: switch the run call to Streamable HTTP, deploy behind the company's API gateway with TLS, add OAuth through the company identity provider with an analytics read scope, rate limit per user on the tool name header, and scale horizontally, which just works because there's no session state.
5:13 Hands-on: one server, two transports
The hands on section shows the same metrics server both ways. In Python, one flag switches between standard I O and Streamable HTTP on port three thousand and one. In TypeScript version two, a handler factory creates a fresh server per request, which is why it scales statelessly, and the Express helper adds host and origin validation. Keep connection pools at module scope, not inside the factory. Avoid printing to standard output, binding to all interfaces, relying on removed session features, and building on the deprecated transport.
5:51 Serverless notes
What about serverless platforms? Streamable HTTP under the twenty twenty six spec is a great fit, because every request is independent. But watch three things. Cold starts can add latency to the first request after idle time. Execution time limits can cut off long running tools, so use the tasks extension or background jobs for slow work. And keep connection pools and SDK clients outside the request handler, so warm instances reuse them.
6:23 Deeper: from 1 to 20 users (illustrative)
Let's deepen the Lahore analyst's move to a team service, with illustrative numbers. The standard I O version served one person. The HTTP version, behind the company gateway with sign in, served twenty analysts in its first month. Two replicas handled peak Monday mornings without any session affinity. The gateway's per user rate limit on the tool name header stopped one analyst's runaway script from affecting everyone else. And because every request carried its method and tool name in headers, the security team built a dashboard of who queried what, without decrypting or parsing request bodies.
7:05 Watch me do it: one server, two transports
Watch me do it. Let's run the metrics server both ways. In Python, the file defines one tool, weekly signups, and at the bottom checks for a dash dash http flag. Without it, mcp run uses standard I O. I launch the Inspector with the stdio command and call the tool with market UAE. Now I start it with the flag: the server listens on one two seven dot zero dot zero dot one, port three thousand and one, path slash mcp. In the Inspector I switch to Streamable HTTP, paste the URL and call the same tool. Same result. Now the TypeScript version: create MCP handler takes a factory that builds a fresh server and registers the same tool with a Zod schema. Create MCP Express app gives me Express with host and origin checks for localhost. I mount the node handler on slash mcp and listen on the loopback address. If I send a request with a foreign host header, it gets a four oh three.
8:18 Try this now
Try this now. Run the lesson's server both ways. First, standard I O: open the Inspector and call the tool. Then start it with the HTTP flag and connect the Inspector to the local URL. Try adding a print statement to the standard I O version and watch what breaks. Finally, write one paragraph for your team: which transport your first production server will use, who needs to reach it, how they'll authenticate, and what happens when you need three copies of it.
8:54 Recap
To recap: standard I O for local, Streamable HTTP for remote. Keep standard output clean, protect localhost servers from DNS rebinding, and enjoy stateless scaling in the twenty twenty six spec. Your next step: run the lesson's server over both transports, connect the Inspector to each, and decide which transport your first production server should use.
Two standard transports
stdio: the client launches the server as a subprocess and exchanges newline-delimited JSON-RPC messages over stdin/stdout. The server may log to stderr; it must never write anything to stdout that is not a valid MCP message. Best for local tools: file access, local databases, CLIs, developer utilities. Credentials come from the environment, not OAuth.
Streamable HTTP: the server is an HTTP service with a single MCP endpoint (commonly /mcp). The client POSTs each JSON-RPC message; the server replies with a JSON body or, when it needs to send notifications such as progress first, an SSE stream for that response. Best for remote, shared and multi-user servers. Authorization uses OAuth (module 5).
The older HTTP+SSE transport (two endpoints) was superseded in 2025-03-26 and is formally deprecated; do not build new servers on it, though some SDKs still offer it for legacy clients.
What changed for HTTP in 2026-07-28
- No sessions: no
Mcp-Session-Id; each request is independent and self-describing. - Required headers:
Mcp-MethodandMcp-Nameon POSTs, plus the protocol version header, so infrastructure can route and authorize on headers. Tool parameters can be exposed as custom headers withx-mcp-headerwhen you need routing on an argument (never for sensitive values). - No GET stream: server-to-client change notifications move to an opt-in
subscriptions/listenrequest whose response is a long-lived stream. - No resumability: SSE event IDs and
Last-Event-IDredelivery were removed; if a stream breaks, the client re-issues the request with a new ID. Design tools to be idempotent (lesson 8). - Cacheable lists: list and read results carry
ttlMsandcacheScopehints.
Result: an MCP server can now scale like any stateless web API behind a round-robin load balancer.
Security basics for local HTTP servers
A local HTTP server bound to localhost is reachable by any web page the user visits via DNS rebinding unless you validate the Host and Origin headers. Official SDK helpers (for example createMcpExpressApp in TypeScript) enable this validation by default for localhost binds. Rules:
- Bind to
127.0.0.1, not0.0.0.0, for local servers. - Validate
HostandOrigin. - Require auth for anything non-trivial.
For stdio servers, remember the host executes your command with the user's privileges: a malicious "server" is just malware. Only install servers from trusted sources and review their launch commands.
Choosing a transport
| Situation | Transport |
|---|---|
| Personal tool on a laptop, touches local files | stdio |
| Team or company-wide service, many users | Streamable HTTP + OAuth |
| SaaS vendor offering an integration to customers | Streamable HTTP + OAuth, listed in registries |
| Desktop app bundling a helper | stdio (or a local HTTP server with Host/Origin validation) |
| Serverless / edge deployment | Streamable HTTP (stateless fits well) |
Worked example: from laptop to team service
A data analyst in Lahore builds a stdio server exposing read-only SQL over a local copy of marketing data. Colleagues want it. Moving to Streamable HTTP:
- Same server code; change the run call to Streamable HTTP.
- Deploy behind the company's API gateway with TLS.
- Add OAuth via the company identity provider; tools check scopes (
analytics:read). - Gateway rate-limits on
Mcp-Nameper user; logs include method and tool name without parsing bodies. - Horizontal scaling works because there is no session state.
Hands-on: the same server over both transports
Python (SDK v2):
from mcp.server import MCPServer
mcp = MCPServer("metrics")
@mcp.tool()
def weekly_signups(market: str) -> dict:
"""Signups for the last 7 days in a market (UAE, KSA, PK, UK, US)."""
return {"market": market, "signups": 412} # replace with a real query
if __name__ == "__main__":
import sys
if "--http" in sys.argv:
mcp.run(transport="streamable-http", port=3001) # serves http://127.0.0.1:3001/mcp by default
else:
mcp.run() # stdioTypeScript (SDK v2) with Express and DNS-rebinding protection:
import { createMcpExpressApp } from '@modelcontextprotocol/express';
import { toNodeHandler } from '@modelcontextprotocol/node';
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
const handler = createMcpHandler(() => {
const server = new McpServer({ name: 'metrics', version: '1.0.0' });
server.registerTool(
'weekly_signups',
{ description: 'Signups for the last 7 days in a market', inputSchema: z.object({ market: z.string() }) },
async ({ market }) => ({ content: [{ type: 'text', text: JSON.stringify({ market, signups: 412 }) }] })
);
return server;
});
const app = createMcpExpressApp(); // Host/Origin validation on localhost binds
const node = toNodeHandler(handler);
app.all('/mcp', (req, res) => void node(req, res, req.body));
app.listen(3001, '127.0.0.1');The TypeScript v2 handler builds a fresh server per request (a factory), which is why it scales statelessly: create connection pools at module scope, not inside the factory.
Pitfalls
- Printing debug output to stdout in a stdio server (corrupts the protocol).
- Binding local HTTP servers to all interfaces without Host/Origin checks.
- Relying on removed session or resumability features after upgrading.
- Building new servers on the deprecated HTTP+SSE transport.
Measuring success
For remote servers: p95 latency per method, error rates by Mcp-Name, instance count versus load, and zero auth bypasses in security tests.
Key takeaways
- stdio suits local subprocess servers; Streamable HTTP suits remote, shared servers.
- Never write non-protocol output to stdout in a stdio server; log to stderr.
- 2026-07-28 HTTP is stateless: no sessions, required Mcp-Method/Mcp-Name headers, no resumability.
- Protect local HTTP servers against DNS rebinding with Host and Origin validation and a loopback bind.
- HTTP+SSE is deprecated; don't build new servers on it.
Check your understanding
Quick questions to lock in the lesson. They don’t count towards your certificate.
Put it into practice
Run the lesson's server over stdio and Streamable HTTP, connect the Inspector to each, and write down which transport your first production server should use and why.
Enrol for free to save your progress
Reading is always free. Enrol to keep your place, take the final assessment and earn a verifiable certificate.