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:
- Host starts or connects to a server.
- They negotiate capabilities.
- Host lists tools / resources / prompts.
- 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]"
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
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
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+argsfrom 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
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"]
}
}
}
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
- Learning / IDE plugins / personal automation → stdio + FastMCP + Inspector.
- Team-shared or productized tools → Streamable HTTP behind auth, health checks, and metrics.
- 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
- Official MCP docs and Python SDK (primary; always prefer over secondary tutorials).
- Alternate Chinese source for a longer FastMCP build (filesystem + search tools + host config), not compiled in this pack: https://juejin.cn/post/7680761868907921442
- Portfolio / related MCP work (optional): https://yongbo-yu.vercel.app · https://github.com/YongBoYu1
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)
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