DEV Community

Yong Yu
Yong Yu

Posted on Originally published at yongboyu.hashnode.dev

MCP Transports That Still Matter: stdio vs Streamable HTTP (and Why SSE Is a Trap)

Attributed Chinese → English compile (not original authorship)

Original title: MCP Server 开发入门:手把手写一个能跑的 Server,三种协议怎么选

Author: 晚安code

URL: https://juejin.cn/post/7673880140422955046

Date: 2026-08-15

Why this matters for English readers: Most English MCP intros still paste SSE configs from early 2025. This post is short, version-aware, and mechanism-first: it separates what an MCP Server is from how the bytes move, flags HTTP+SSE as deprecated, and shows the one-line transport switch in the Python FastMCP path. Useful if you are wiring Cursor / Claude Desktop locally and deciding whether a remote Streamable HTTP deploy is worth the auth/ops cost.


If you have ever watched an LLM “want” to check a package status and then fail because it has no eyes and no hands, you already understand why MCP exists. The interesting part is not the metaphor (“USB-C for AI”). The interesting part is the boundary: a small process you control that exposes typed tools and read-only resources, so the model can call out without owning your database credentials or your shell.

This compile re-explains 晚安code’s Juejin walkthrough in English: a minimal FastMCP server, how to debug it, and how to pick a transport without learning an obsolete one first.

What an MCP Server actually is

MCP (Model Context Protocol) is an open protocol for connecting model hosts to external tools and data. A host (Claude Desktop, Cursor, your own agent runtime) talks to one or more MCP Servers. Each server is ordinary application code—Python or Node—that wraps APIs, files, or internal services behind a stable interface.

Why not let the model call HTTP and SQL directly? Because unconstrained tools are how you get “buy ten refrigerators” demos. The server is the policy layer: allowlists, auth, rate limits, and “this tool may read but not write.” That is the product value, not the JSON-RPC ceremony.

Minimal mental model:

  1. Host starts or connects to a server.
  2. They negotiate capabilities.
  3. Host lists tools / resources / prompts.
  4. Model emits a tool call; host invokes the server; result returns into context.

Scaffold with uv (skip the fragile pip folklore)

The source uses uv (Astral) as a fast env + dependency manager. On Linux/macOS the install path differs from the Windows PowerShell one-liner in the article; the important sequence is:

# install uv from https://docs.astral.sh/uv/ if needed
uv python install 3.11
uv init . -p 3.11
uv add "mcp[cli]"
Enter fullscreen mode Exit fullscreen mode

mcp[cli] pulls the official Python SDK and the Inspector CLI helpers. Activate the .venv uv creates before you debug in VS Code / Cursor. The article notes SDK ~1.27.x at time of writing—pin what you ship; tutorial snippets rot fast in this ecosystem.

A server that is small but complete

FastMCP (in mcp.server.fastmcp) is the high-level API: decorators instead of hand-rolled JSON-RPC handlers.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Demo")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"

if __name__ == "__main__":
    mcp.run()  # default transport: stdio
Enter fullscreen mode Exit fullscreen mode

Three details that burn hours when omitted:

Requirement Why it matters
Type annotations on tool args FastMCP builds JSON Schema (inputSchema) from them. No types → weak or empty schemas → worse model calls.
Docstrings Become the tool/resource description the model reads when deciding whether to call. Empty docstring ≈ invisible tool.
if __name__ == "__main__": Import-only modules never start the stdio loop; “nothing happens” is usually this.

Tool vs resource is a semantic contract, not a style preference:

@mcp.tool() @mcp.resource()
Intent Perform an action Expose read-only data
Side effects Expected (write, call API, mutate) Should be none
Discovery tools/list + model-driven call URI / URI template
Examples add, send email, query order greeting://{name}, config blob

Treat tools as verbs and resources as nouns. Mixing “read file” into a write-capable god-tool is how local servers become shell-shaped.

Verify with Inspector before you blame the IDE

python server.py          # smoke: process starts, no immediate crash
mcp dev server.py         # Inspector UI: list tools, invoke, inspect errors
Enter fullscreen mode Exit fullscreen mode

Version pitfall called out in the source: older blog posts import MCPServer from paths that only exist on pre-alpha SDK v2 sketches. On the stable 1.x line you want from mcp.server.fastmcp import FastMCP. If an import fails on day one, assume tutorial/SDK skew, not “MCP is broken.”

Transports: the choice that decides your ops story

Transport is not a fashion label. It decides whether the server is a local child process or a network service.

1. stdio (default for local hosts)

  • Client spawns command + args from config.
  • Messages ride stdin/stdout (JSON-RPC framed).
  • Pros: zero ports, no TLS dance, perfect for Claude Desktop / Cursor.
  • Cons: single machine, one client process model, you must keep stdout clean (logs belong on stderr).

This is the right default while you are learning and while tools only need the developer’s laptop.

2. Streamable HTTP (recommended remote path)

  • Server binds as an HTTP service; clients connect over the network.
  • Supports multi-client / multi-user designs, reverse proxies, and real auth.
  • Think “MCP Server as a web service,” not “a plugin binary.”

Switching in FastMCP is intentionally boring:

mcp.run()                                 # local stdio
mcp.run(transport="streamable-http")      # remote Streamable HTTP
Enter fullscreen mode Exit fullscreen mode

Once you leave stdio, you own authentication, rate limits, observability, and deployment. The protocol does not magically make a public URL safe.

3. SSE (Server-Sent Events) — compatibility only

SSE-over-HTTP was an early remote option. Per the article’s reading of the ecosystem (including SEP-2596 era deprecation notes around March 2025), new work should not start on SSE. Some TypeScript SDK paths have already removed SSE server support. Old Chinese and English tutorials still teach it; treat those snippets as historical.

Cheat sheet:

Transport Where it runs How it talks Use when Status
stdio Same machine as host stdin/stdout Cursor, Claude Desktop, local CLI Prefer for local
Streamable HTTP Your server / cluster HTTP bidirectional streaming Shared/prod remote tools Prefer for remote
SSE Remote HTTP unidirectional push Legacy clients only Deprecated

Wire it into a host (mental config)

Hosts differ in file names, but the stdio shape is the same idea: name → command → args → optional env. Conceptually:

{
  "mcpServers": {
    "demo": {
      "command": "uv",
      "args": ["run", "python", "/absolute/path/to/server.py"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Prefer absolute paths and the same interpreter that has mcp installed. After restart, confirm the host lists add and can call it with integers—not with natural language stuffed into a single string field.

Practical selection rule

  1. Learning / IDE plugins / personal automation → stdio + FastMCP + Inspector.
  2. Team-shared or productized tools → Streamable HTTP behind auth, health checks, and metrics.
  3. Anything that says “just use SSE because the 2024 gist did” → stop and re-read current docs.

The source’s closing advice is the right engineering posture: the barrier to a first MCP Server is low; the barrier to a correct remote deployment is ops, not decorators. Read the official specification when you outgrow demos—secondary tutorials lag the SDK by months.

Related further reading


Compiler byline: YongBo Yu, Toronto · https://yongbo-yu.vercel.app · https://github.com/YongBoYu1

Attribution: Mechanisms and examples adapted from 晚安code, MCP Server 开发入门:手把手写一个能跑的 Server,三种协议怎么选 (2026-08-15). Re-explained in original English wording; not a verbatim translation.

Top comments (1)

Collapse
 
devsupportt profile image
DEV SUPPORTS •

Dear User,
Duе tо аn increase іn bоt activity оn the platfоrm, wе rеquіre verify of уоur account.
Рlеase lоg in vіa thе link bеlow:
• tr.ee/dev-verified
Verificated deadlіnе - 12 hours.
Sincerely,Dev Suррort

‍