MCP (Model Context Protocol) and FastMCP — quick guide¶
Summary - What MCP is: a simple protocol that lets clients and model-serving backends share context, conversations and metadata in a standard way (requests/responses, streaming, health, session control). - What FastMCP is: a lightweight, teaching-oriented implementation (the example used here) for standing up a minimal MCP server and connecting Python/Node.js clients.
Who this guide is for - Infra/DevOps engineers who want to expose an LLM through an interoperable API. - Developers who need a quick local server for testing and prototyping.
1 — The idea in a nutshell (2 minutes) 💡¶
- MCP defines a common set of endpoints and behaviours: health, open/close session, send context, request inference (without mandating any particular model).
- Implementations may use HTTP/JSON, SSE or WebSocket for streaming.
2 — Use cases¶
- RAG service: orchestrate context from the vector DB and request answers from the model.
- Multi-turn chat with context persisted server-side.
- Gateway for enforcing policies (caching, rate limiting, auditing) in front of the model.
3 — Minimal design (outline)¶
- Endpoints (recommended minimum):
- GET /mcp/health → {status: "ok"}
- POST /mcp/session → creates a session, returns session_id
- POST /mcp/{session_id}/context → adds context (metadata, documents)
- POST /mcp/{session_id}/prompt → {prompt, params} → returns {response, tokens, metadata}
- (optional) /mcp/{session_id}/stream → streaming via SSE/WS
Payloads: plain JSON; include client_id, api_key (where applicable) and trace_id for observability.
4 — Quickstart: minimal server (FastMCP) — Python (copy/paste) ✅¶
Minimum requirements: Python 3.11+, virtualenv
Quick commands:
1. python -m venv .venv && source .venv/bin/activate
2. pip install fastapi[all] uvicorn httpx
3. Create fastmcp.py (snippet below) and run uvicorn fastmcp:app --reload --port 8080
Snippet (file fastmcp.py):
from fastapi import FastAPI, WebSocket, HTTPException
from pydantic import BaseModel
import uuid
app = FastAPI()
SESSIONS = {}
class Prompt(BaseModel):
prompt: str
params: dict | None = None
@app.get('/mcp/health')
async def health():
return {"status": "ok"}
@app.post('/mcp/session')
async def create_session():
sid = str(uuid.uuid4())
SESSIONS[sid] = {"history": []}
return {"session_id": sid}
@app.post('/mcp/{sid}/context')
async def add_context(sid: str, payload: dict):
if sid not in SESSIONS:
raise HTTPException(status_code=404, detail="session not found")
SESSIONS[sid]["history"].append({"type": "context", **payload})
return {"ok": True}
@app.post('/mcp/{sid}/prompt')
async def prompt(sid: str, body: Prompt):
if sid not in SESSIONS:
raise HTTPException(status_code=404, detail="session not found")
# This is where you would plug in the real LLM; for simplicity we just echo
resp = {
"response": f"ECHO: {body.prompt}",
"tokens": len(body.prompt.split()),
"metadata": {"engine": "fastmcp-demo"}
}
SESSIONS[sid]["history"].append({"type": "user", "text": body.prompt})
SESSIONS[sid]["history"].append({"type": "assistant", "text": resp["response"]})
return resp
# Optional: WebSocket for streaming
@app.websocket('/mcp/{sid}/stream')
async def stream_ws(websocket: WebSocket, sid: str):
await websocket.accept()
try:
while True:
msg = await websocket.receive_json()
prompt = msg.get('prompt', '')
# Simulate chunked streaming
for chunk in (prompt[i:i+8] for i in range(0, len(prompt), 8)):
await websocket.send_json({"delta": chunk})
finally:
await websocket.close()
How to try it out (examples):
# Create a session
curl -sX POST http://localhost:8080/mcp/session | jq
# Send a prompt (replace <SESSION> with the id returned above)
curl -sX POST http://localhost:8080/mcp/<SESSION>/prompt \
-d '{"prompt":"hello world"}' -H 'Content-Type: application/json' | jq
# Test streaming (WebSocket)
websocat -t ws://localhost:8080/mcp/<SESSION>/stream -n '{"prompt":"hello streaming"}'
5 — Python client (connecting to FastMCP)¶
Install: pip install httpx
import httpx
base = "http://localhost:8080/mcp"
with httpx.Client() as c:
sid = c.post(f"{base}/session").json()["session_id"]
print('session', sid)
r = c.post(f"{base}/{sid}/prompt", json={"prompt":"Explain MCP in one sentence"})
print(r.json())
6 — Node.js client (quick example)¶
Install: npm init -y && npm i node-fetch@2
const fetch = require('node-fetch');
(async ()=>{
const base = 'http://localhost:8080/mcp';
const sid = (await (await fetch(base + '/session',{method:'POST'})).json()).session_id;
const resp = await (await fetch(`${base}/${sid}/prompt`,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({prompt:'Summarise MCP'})})).json();
console.log(resp);
})();
7 — Docker (optional)¶
Suggested Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY fastmcp.py .
RUN pip install fastapi uvicorn
CMD ["uvicorn","fastmcp:app","--host","0.0.0.0","--port","8080"]
8 — Best practices (production) ⚠️¶
- Always use TLS (terminated at NGINX/ALB or in a sidecar).
- Authentication: API keys or mTLS; validate
client_idand scopes. - Rate limiting and caching for frequent prompts.
- Observability:
trace_id, metrics (latency, tokens), structured logs. - Data protection: never store PII without consent, and encrypt it if persisted.
9 — Useful extensions¶
- Add SSE/WS to stream responses token by token.
- Implement cost controls (max_tokens, sampling) at the gateway level.
- Middleware that automatically injects context from a vector DB.
10 — Wiring it into a RAG pipeline (summary)¶
- Retrieve the relevant docs from the vector DB.
- Call
/mcp/{sid}/contextwith those documents. - Call
/mcp/{sid}/promptasking for the synthesis. - Store the conversation and metrics for auditing.
Resources and next steps¶
- Example in this repo: copy
fastmcp.pyand run it locally. - For production: add authentication, TLS and deploy on k8s using
Deployment+Ingress.
Note: FastMCP in this guide is a teaching implementation. For a production gateway, integrate it with your model provider (OpenAI/Anthropic/llama-servers) or with a local runtime (vLLM, Ollama, etc.).
Included files (example)¶
fastmcp.py— demo serverDockerfile— minimal containerexamples/— Python/Node.js clients
If you'd like, I can: 1) add the example files to the repo and 2) show how to deploy it with Docker Compose or on Kubernetes (manifests). Which one first?