π§© High-Level Goal
You're not just exposing endpoints anymore β you're exposing "capabilities" that an LLM can invoke, inspect, and reason about within an ongoing session.
π§± Side-by-Side Architecture Map
Layer | REST API (Stateless) | MCP Server (Stateful) | Ξ Transformation |
---|---|---|---|
Entry Point | main.py runs HTTP server |
server.py runs message loop |
π Replace request/response with message dispatch |
Router | @app.route("/path") |
@mcp.tool() |
π Path routing β tool routing |
Transport | HTTP verbs + routes | JSON-RPC methods | β Session persists; multi-step interactions |
Schema | OpenAPI / code docs | Auto-extracted from type hints | β Machine-readable for LLMs |
Context | Each request new (no memory) | Shared context across invocations | β Stateful (cache, auth, session) |
Discovery | Humans read /docs |
LLM queries list_tools |
β Self-discoverable |
Client | Browser, mobile app | LLM / AI Agent | β‘οΈ Programmatic reasoning |
π File Structure Transformation
REST API β Classic Layout
api_server/
βββ main.py # HTTP server
βββ routes/
β βββ users.py # @app.route('/users')
β βββ orders.py
βββ models/
β βββ user_model.py
β βββ order_model.py
βββ services/
β βββ db_service.py
β βββ cache_service.py
βββ utils/
βββ auth.py
βββ error_handlers.py
MCP Server β Transformed Layout
mcp_server/
βββ server.py # Message loop (stdio/ws)
βββ tools/
β βββ users.py # @mcp.tool() get_user(id)
β βββ orders.py # @mcp.tool() create_order()
βββ resources/
β βββ user://{id} # dynamic URI resource
β βββ inventory://{sku}
βββ schema/
β βββ generated.json # JSON-Schema
βββ context/
β βββ state.py # Session context store
β βββ memory.py # Persistent across calls
βββ transports/
βββ stdio.py
βββ websocket.py
π§ Key Transformations:
-
β
/routes
becomes/tools
-
β
/models
becomes/resources
(conceptual entities) -
β
/services
remain same (but injected into context) -
+
/context
added (state/session layer)
βοΈ Internal Code Transformation
Example 1: Basic Addition Handler
@app.route("/add", methods=["POST"])
def add():
data = request.json
result = data["a"] + data["b"]
return jsonify({"result": result})
@mcp.tool()
async def add(a: int, b: int) -> int:
return a + b
Key difference: MCP uses tool name + schema routing instead of path + method. Input/output validation comes from type hints automatically.
Example 2: Stateful Context Handling
@app.route("/cart", methods=["POST"])
def add_to_cart():
user = request.headers["User"]
cart = db.get_cart(user)
cart.add(request.json["item"])
db.save_cart(cart)
return jsonify({"message": "ok"})
@mcp.tool()
def add_to_cart(ctx: Context, item: str):
cart = ctx.session.get("cart", [])
cart.append(item)
ctx.session["cart"] = cart
return {"cart_size": len(cart)}
Ξ Transformation: Session is in-memory, persists across tool invocations β useful for reasoning and chaining.
π§ REST β MCP Concept Mapping
REST Concept | MCP Equivalent | Remarks |
---|---|---|
Route | Tool | Invokable function, schema-aware |
GET /resource/:id | read_resource("uri") | Accesses a resource handler |
POST /data | invoke_tool("tool_name") | Calls a capability |
Request.headers | Context.session | Holds user/session info |
Middleware | Hook / Lifespan | Pre/post invocation wrappers |
OpenAPI | MCP Schema | Generated from annotations |
404 | Error.code=32001 | JSON-RPC error variant |
βοΈ Summary of Trade-offs
Aspect | REST (+) | MCP (+) | Comment |
---|---|---|---|
Simplicity | β Very simple | β οΈ More complex | REST easier for humans |
AI Integrability | β Hard (needs wrapper) | β Native | MCP made for LLMs |
State | β Stateless | β Stateful | Enables tool chaining |
Discoverability | π§ Manual docs | π€ Auto via list_tools | Self-describe |
Security | Mature | Evolving | Requires trust boundary design |
Performance | High (HTTP optimized) | Medium (RPC overhead) | But fine for tool calls |
Purpose | Web & API apps | AI orchestration | Complementary layers |
π§ Big Picture
MCP doesn't replace REST; it wraps or extends it β turning traditional endpoints into introspectable, schema-aware, conversational tools.
"An RPC faΓ§ade for LLMs, sitting on top of APIs that were originally built for humans."