Model Context Protocol Template
A production-ready MCP server template that connects LLMs and AI agents to external data, tools, and services with built-in OAuth 2.1 authentication, Redis-backed session management, and a modular tools engine.
README
<div align="center">
Model Context Protocol Template
A production-ready template for building Model Context Protocol (MCP) pipelines that connect LLMs and AI agents to external data, tools, and services.
</div>
Table of Contents
- Why MCP?
- Architecture Overview
- Key Components
- Tech Stack
- Project Structure
- Getting Started
- Client Integration
- Available Tools
- Configuration Reference
- Session & Auth Deep Dive
- Contributing
- License
Why MCP?
Large Language Models are powerful but isolated β they can't natively access live databases, trigger workflows, or call APIs. The Model Context Protocol (MCP) solves this by providing a standardized bridge between AI and the real world.
| Problem | MCP Solution |
|---|---|
| LLMs can't access live data | Connects to databases, APIs, and services in real-time |
| Every integration requires custom code | One universal protocol for all tool integrations |
| No session awareness across requests | Redis-backed stateful sessions over stateless HTTP/SSE |
| Security is an afterthought | Built-in OAuth 2.1 + PKCE, encrypted credentials, JWT tokens |
| Hard to scale AI tool servers | Stateless server design, horizontal scaling via externalized state |
This template gives you a batteries-included starting point β fork it, add your tools, and deploy.
Architecture Overview

High-Level Pipeline Flow
The MCP server acts as a middleware pipeline that translates between AI clients and external services. Below is the end-to-end data flow:
flowchart LR
subgraph CLIENTS["π€ Client Layer"]
LLM["π€ LLM / AI Agent"]
Browser["π User Browser"]
end
subgraph MCP_SERVER["βοΈ MCP Server Pipeline"]
direction TB
Transport["Transport Layer<br/>/mcp Β· /sse Β· /http"]
Middleware["Custom Middleware<br/>Session Injection Β· SSE Streams"]
Core["FastMCP Core<br/>Protocol Handler Β· Tool Registry"]
Tools["Tools Engine<br/>Modular Tool Execution"]
end
subgraph STATE["πΎ State Layer"]
Redis[("Redis<br/>Sessions Β· Auth Β· Tokens")]
end
subgraph EXTERNAL["π External Services"]
IDP["Identity Provider"]
API["Upstream APIs"]
end
LLM -->|"MCP Request"| Transport
Transport --> Middleware
Middleware -->|"Read / Write"| Redis
Middleware --> Core
Core --> Tools
Tools -->|"API Call"| API
API -->|"Response"| Tools
Tools -->|"Masked Data"| LLM
Browser -->|"OAuth Login"| IDP
IDP -->|"Callback + Token"| Middleware
Middleware -->|"Store Credentials"| Redis
style CLIENTS fill:#0d1b2a,stroke:#00b4d8,color:#e0e0e0
style MCP_SERVER fill:#1a1a2e,stroke:#7b2ff7,color:#e0e0e0
style STATE fill:#0d1b2a,stroke:#00c853,color:#e0e0e0
style EXTERNAL fill:#0d1b2a,stroke:#ff6d00,color:#e0e0e0
[!TIP] The server is fully stateless β all session data lives in Redis, making horizontal scaling trivial.
Detailed Component Architecture
This diagram zooms into the internal layering of the MCP server, showing how each module connects:
flowchart TB
subgraph ENTRY["πͺ Entry Points"]
MCP_EP["/mcp<br/>Standard MCP Protocol"]
SSE_EP["/sse<br/>Server-Sent Events"]
HTTP_EP["/http<br/>Direct HTTP"]
end
subgraph MIDDLEWARE_LAYER["π‘οΈ Custom Middleware"]
direction TB
SessionInject["Session Context Injector<br/>Injects mcp_session_id into headers"]
StreamTransport["StreamableHTTPServerTransport<br/>HTTP β MCP message bridge"]
SSEHandler["SSE Handler<br/>anyio memory streams for<br/>non-blocking read/write channels"]
end
subgraph CORE_LAYER["βοΈ FastMCP Core"]
direction TB
ProtocolHandler["Protocol Handler<br/>MCP message parsing & routing"]
ToolRegistry["Tool Registry<br/>Dynamic tool discovery & dispatch"]
TaskGroups["anyio Task Groups<br/>Bidirectional stream management"]
end
subgraph AUTH_LAYER["π Security Layer"]
direction TB
OAuth["OAuth 2.1 Provider<br/>Authorization & Token endpoints"]
PKCE["PKCE Enforcer<br/>S256 code challenge verification"]
JWT["JWT Manager<br/>HS256 signed Bearer tokens"]
Encryption["AES-CBC Encryption<br/>Sensitive config protection"]
end
subgraph TOOLS_LAYER["π§° Tools Engine"]
direction TB
ServiceTool["Service Tool<br/>Generic modular tool"]
Helpers["Helpers<br/>Context validation & utilities"]
end
subgraph STATE_LAYER["πΎ Redis State"]
direction TB
SessionStore[("Session Store<br/>JSON objects via RedisJSON<br/>1-hour TTL")]
AuthCodes[("Auth Codes<br/>Short-lived, 10-min TTL")]
TokenMeta[("Token Metadata<br/>JTI for revocation checks")]
end
MCP_EP & SSE_EP & HTTP_EP --> SessionInject
SessionInject --> StreamTransport
StreamTransport --> SSEHandler
SSEHandler --> ProtocolHandler
ProtocolHandler --> ToolRegistry
ToolRegistry --> TaskGroups
TaskGroups --> ServiceTool
ServiceTool --> Helpers
SessionInject -.->|"Read/Write"| SessionStore
OAuth -.->|"Store"| AuthCodes
JWT -.->|"Store JTI"| TokenMeta
StreamTransport -.-> OAuth
OAuth --> PKCE
PKCE --> JWT
style ENTRY fill:#112240,stroke:#64ffda,color:#ccd6f6
style MIDDLEWARE_LAYER fill:#112240,stroke:#7b2ff7,color:#ccd6f6
style CORE_LAYER fill:#112240,stroke:#00b4d8,color:#ccd6f6
style AUTH_LAYER fill:#112240,stroke:#f44336,color:#ccd6f6
style TOOLS_LAYER fill:#112240,stroke:#ff9800,color:#ccd6f6
style STATE_LAYER fill:#112240,stroke:#00c853,color:#ccd6f6
Authentication & Session Sequence
The following sequence diagram illustrates the complete lifecycle β from initial connection to authenticated tool execution:
sequenceDiagram
participant LLM as π€ LLM / AI Agent
participant MCP as βοΈ MCP Server
participant Redis as πΎ Redis
participant Browser as π User Browser
participant IDP as π Identity Provider
participant API as π Upstream API
Note over LLM,API: Phase 1 β Session Establishment
LLM->>MCP: Connect via /mcp, /sse, or /http
MCP->>Redis: Create session (JSON, 1hr TTL)
Redis-->>MCP: session_id
MCP-->>LLM: Connection established
Note over LLM,API: Phase 2 β Authentication
LLM->>MCP: Call "login" tool
MCP-->>LLM: Return Auth URL
LLM-->>Browser: Display Auth URL to user
Browser->>IDP: User authenticates
IDP->>MCP: Redirect callback with token
MCP->>Redis: Store credentials β session_id
Redis-->>MCP: OK
MCP-->>Browser: "Login successful" page
Note over LLM,API: Phase 3 β Authenticated Tool Execution
LLM->>MCP: Call tool (e.g., "service")
MCP->>Redis: Validate session + load credentials
Redis-->>MCP: Session data + credentials
MCP->>API: Authenticated API request
API-->>MCP: Response data
MCP-->>LLM: Masked / formatted result
Key Components
| Component | Description |
|---|---|
| FastMCP Core | High-level MCP protocol implementation β tool registration, message routing, context management |
| Starlette (ASGI) | Underlying async web framework β handles HTTP routing, middleware stack, and request lifecycle |
| Custom Middleware | Session-aware request handler β injects mcp_session_id, manages SSE streams via anyio memory channels, bridges HTTP β MCP |
| OAuth 2.1 + PKCE | Lightweight built-in authorization server β issues JWT Bearer tokens, enforces S256 PKCE for public clients |
| Redis State Store | Externalized session & auth storage β RedisJSON objects with TTL, auth codes, and token metadata |
| AES-CBC Encryption | Protects sensitive configuration values (e.g., Redis passwords) using the cryptography library |
| Tools Engine | Modular tool definitions β validates context via Helpers and SessionManager before executing business logic |
| Structured Logging | Uses structlog for JSON-formatted structured logs with configurable log levels |
Tech Stack
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Python 3.13 | Core language |
| MCP Protocol | FastMCP | Protocol implementation & tool registry |
| Web Framework | Starlette (ASGI) | HTTP/SSE routing & middleware |
| ASGI Server | Uvicorn | High-performance async server |
| State Store | Redis (RedisJSON) | Sessions, auth codes, token metadata |
| Authentication | Custom OAuth 2.1 | PKCE, JWT, Bearer tokens |
| Encryption | cryptography (AES-CBC) |
Config & credential protection |
| Logging | structlog |
Structured JSON logging |
| Containerization | Docker (Alpine) | Lightweight deployment |
| Async | anyio |
Task groups & memory streams |
π Project Structure
model-context-protocol/
βββ src/
β βββ main.py # Application entry point & tool registration
β βββ config.py # Environment loading & configuration constants
β βββ auth/
β β βββ oauth.py # OAuth 2.1 authorization server (PKCE)
β β βββ token.py # JWT token issuance & validation
β βββ conn/
β β βββ redis_config.py # Redis client initialization
β βββ encryptdecrypt/
β β βββ encrypt.py # AES-CBC encryption / decryption utilities
β βββ exception/
β β βββ handler.py # Global exception handling
β βββ log/
β β βββ logger.py # Structured logging configuration
β βββ middleware/
β β βββ middleware.py # Custom middleware (session injection, SSE, transport)
β βββ server/
β β βββ server.py # Starlette app factory & route definitions
β βββ session/
β β βββ manager.py # Session lifecycle management (Redis)
β β βββ session.py # Session model & validation
β βββ tools/
β β βββ service.py # Modular tool definitions
β βββ utils/
β βββ helpers.py # Context validation & utility functions
βββ docs/
β βββ architecture_diagram.png
βββ test/ # Unit & integration tests
βββ .env # Environment variables (not committed)
βββ Dockerfile # Container image definition
βββ pyproject.toml # Pytest & coverage configuration
βββ requirements.txt # Python dependencies
βββ LICENSE # MIT License
Getting Started
Prerequisites
| Requirement | Version |
|---|---|
| Python | β₯ 3.13 |
| Redis | β₯ 7.0 (with RedisJSON module) |
| Docker | β₯ 20.10 (optional, for containerized deployment) |
Local Setup
1. Clone the repository
git clone https://github.com/shubhamauti9/model-context-protocol.git
cd model-context-protocol
2. Create a virtual environment
python -m venv .venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windows
3. Install dependencies
pip install -r requirements.txt
4. Configure environment variables
Create a .env file in the project root:
# ββ App ββββββββββββββββββββββββββββββββββ
MASK_MCP_HOST=0.0.0.0
MASK_MCP_PORT=6901
APP_VERSION=1.0.0
# ββ Redis ββββββββββββββββββββββββββββββββ
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_P= # Redis password (leave blank for local)
REDIS_DB=0
# ββ Encryption βββββββββββββββββββββββββββ
ENCRYPTION_KEY=your-32-byte-key
ENCRYPTION_IV=your-16-byte-iv
# ββ Logging ββββββββββββββββββββββββββββββ
LOG_FILE=logs/mcp.log
5. Start Redis
# Using Docker
docker run -d --name redis -p 6379:6379 redis:7-alpine
# Or install natively
visit https://redis.io/docs/getting-started/
6. Run the server
python src/main.py
The server will start at http://0.0.0.0:6901. You can verify it's running:
curl http://localhost:6901/mcp
Docker Deployment
Build the image
docker build -t mcp:1.0.0 .
Run the container
docker run -d \
--name mcp-server \
-p 6901:6901 \
--env-file .env \
mcp:1.0.0
Docker Compose (recommended for production)
version: "3.9"
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
mcp:
build: .
ports:
- "6901:6901"
depends_on:
- redis
env_file:
- .env
π Client Integration
Claude Desktop
Add the following to your Claude Desktop configuration file:
| OS | Config Path |
|---|---|
| macOS | ~/.config/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
{
"mcpServers": {
"mcp": {
"command": "python",
"args": ["/path/to/model-context-protocol/src/main.py"]
}
}
}
Direct HTTP
# Connect over HTTP
curl -X POST http://localhost:6901/http \
-H "Content-Type: application/json" \
-d '{"method": "tools/call", "params": {"name": "service"}}'
SSE (Server-Sent Events)
# Open an SSE stream
curl -N http://localhost:6901/sse?session_id=<your-session-id>
Available Tools
| Tool | Description |
|---|---|
service |
Generic, modular service tool β designed to be extended for your specific use case. Validates session context before execution. |
[!NOTE] To add custom tools, create a new module in
src/tools/, define your tool function, and register it insrc/main.pyusing the@mcp.tool()decorator. Seesrc/tools/service.pyfor a reference implementation.
βοΈ Configuration Reference
| Variable | Required | Default | Description |
|---|---|---|---|
MASK_MCP_HOST |
Yes | β | Server bind address |
MASK_MCP_PORT |
No | 6901 |
Server port |
APP_VERSION |
No | β | Application version string |
REDIS_HOST |
Yes | 127.0.0.1 |
Redis server hostname |
REDIS_PORT |
No | 6379 |
Redis server port |
REDIS_P |
No | "" |
Redis password |
REDIS_DB |
No | 0 |
Redis database index |
ENCRYPTION_KEY |
Yes | β | 32-byte AES encryption key |
ENCRYPTION_IV |
Yes | β | 16-byte AES initialization vector |
LOG_FILE |
No | β | Log file output path |
π Session & Auth Deep Dive
Session Lifecycle
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ βββββββββββββββ
β CONNECT ββββββΆβ ANONYMOUS ββββββΆβ AUTHENTICATEDββββββΆβ EXPIRED β
β β β Session in β β Credentials β β TTL reachedβ
β /mcp /sse β β Redis (1hr) β β stored in β β or manual β
β /http β β β β Redis β β logout β
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ βββββββββββββββ
OAuth 2.1 + PKCE Flow (for /http & /sse)
- Authorization β Client sends
code_challenge+redirect_urito/authorize. Server creates a temporaryauth_codein Redis (10-min TTL). - Token Exchange β Client presents
auth_code+code_verifierto/token. Server validatesSHA256(verifier) == challenge, then issues a signed JWT containing thesession_id. - Authenticated Requests:
- HTTP:
Authorization: Bearer <jwt>β Middleware decodes JWT, extractssession_id, validates against Redis. - SSE:
/sse?session_id=...β Session validated, async message pipeline established.
- HTTP:
Transport Protocols
| Protocol | Endpoint | Use Case | Session |
|---|---|---|---|
| MCP | /mcp |
Standard MCP clients (Claude, etc.) | Auto-managed |
| SSE | /sse |
Real-time streaming responses | Query param |
| HTTP | /http |
REST-style direct calls | Bearer JWT |
π€ Contributing
Contributions are welcome! Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-tool - Commit your changes:
git commit -m "feat: add my-tool integration" - Push to the branch:
git push origin feature/my-tool - Open a Pull Request
[!IMPORTANT] Please ensure your code passes the existing test suite before submitting a PR:
pytest --cov=src --cov-report=term-missing
π License
This project is licensed under the MIT License β see the LICENSE file for details.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.