MCPShield is a secure gateway that enforces policies, permissions, and auditing between AI agents (via MCP) and real systems.
MCPShield - Complete Project Documentation
Table of Contents
- Project Overview
- Architecture
- Project Structure
- Technology Stack
- Core Components
- Database Schema
- API Endpoints
- Authentication & Authorization
- Frontend Pages & Routes
- Infrastructure & Deployment
- Key Features
- Data Flow
- Environment Configuration
Project Overview
MCPShield is a comprehensive security gateway and control plane for AI systems accessing real infrastructure. It provides deterministic policy enforcement, AI-powered policy generation, comprehensive auditing, and secure access to databases, APIs, cloud platforms, and more.
The platform enables users to:
- Secure Infrastructure Access: Protect PostgreSQL, MySQL, SQLite, MongoDB, Redis, and more with unified policies
- AI-Powered Policy Generation: Natural language to YAML policies using self-hosted AI (Ollama)
- Multi-Project Management: Create isolated environments with independent policies and API keys
- Comprehensive Auditing: Every policy decision logged with complete visibility
- Usage Analytics: Track AI usage, infrastructure queries, and enforce plan limits
- Developer-Friendly Tools: Easy CLI setup, MCP integration, and real-time policy updates
Architecture
MCPShield follows a modern microservices architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└──────────────────┬──────────────────────────────────────────┘
│
┌─────────▼─────────┐
│ Caddy (Port 80/443) │ Reverse Proxy + Auto HTTPS
│ - mcpshield.xyz │
│ - app.mcpshield.xyz │
│ - api.mcpshield.xyz │
└─────────┬─────────────┘
│
┌─────────┴──────────────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ Web │ │ API │
│ Next.js │ │ FastAPI │
│ (3000) │ │ (8000) │
└────┬────┘ └────┬────┘
│ │
│ ┌─────────────────────┼───────────────┐
│ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌─────▼─────┐
│ │ Redis │ │Postgres │ │ Ollama │
│ │ Cache │ │Database │ │ phi3:mini │
│ └─────────┘ └─────────┘ │ (AI) │
│ └───────────┘
└─────────► API Client (HTTP)
Component Communication:
- Client Browser → Caddy → Web (Next.js) for UI
- Web App → Caddy → API (FastAPI) for data/auth
- API → PostgreSQL for persistent data
- API → Redis for caching, sessions, rate limiting, OTPs
- API → Ollama (internal network) for AI policy generation and security analysis
Project Structure
mcpshield/
├── apps/
│ ├── web/ # Next.js Frontend
│ │ ├── src/
│ │ │ ├── app/ # App Router pages
│ │ │ │ ├── app/ # Protected dashboard routes
│ │ │ │ │ ├── audits/ # Audit logs page
│ │ │ │ │ ├── billing/ # Billing & subscription
│ │ │ │ │ ├── profile/ # User profile
│ │ │ │ │ ├── projects/ # Projects management
│ │ │ │ │ │ └── [projectId]/
│ │ │ │ │ │ ├── keys/ # API keys management
│ │ │ │ │ │ └── policy/ # Policy editor
│ │ │ │ │ ├── settings/ # Account settings
│ │ │ │ │ ├── usage/ # Usage statistics
│ │ │ │ │ └── layout.tsx # Dashboard layout
│ │ │ │ ├── auth/ # Authentication pages
│ │ │ │ │ ├── sign-in/ # Login page
│ │ │ │ │ ├── sign-up/ # Registration page
│ │ │ │ │ ├── verify-otp/ # OTP verification
│ │ │ │ │ ├── forgot-password/
│ │ │ │ │ ├── reset-password/
│ │ │ │ │ └── layout.tsx # Auth layout
│ │ │ │ ├── docs/ # Documentation
│ │ │ │ ├── layout.tsx # Root layout
│ │ │ │ └── page.tsx # Landing page
│ │ │ ├── components/ # React components
│ │ │ │ ├── ui/ # UI components
│ │ │ │ │ ├── AuthCard.tsx
│ │ │ │ │ ├── Button.tsx
│ │ │ │ │ ├── TextField.tsx
│ │ │ │ │ ├── PasswordField.tsx
│ │ │ │ │ └── OTPInput.tsx
│ │ │ │ ├── Navbar.tsx
│ │ │ │ ├── Footer.tsx
│ │ │ │ ├── AppSidebar.tsx
│ │ │ │ ├── Card.tsx
│ │ │ │ ├── Badge.tsx
│ │ │ │ ├── CodeBlock.tsx
│ │ │ │ ├── SectionTitle.tsx
│ │ │ │ └── Simulation.tsx
│ │ │ ├── contexts/ # React contexts
│ │ │ │ └── AuthContext.tsx # Global auth state
│ │ │ ├── lib/ # Utility libraries
│ │ │ │ ├── api-client.ts # API client wrapper
│ │ │ │ ├── auth.ts # Auth utilities
│ │ │ │ └── token-refresh.ts # Token refresh logic
│ │ │ ├── types/ # TypeScript types
│ │ │ │ └── index.ts
│ │ │ ├── middleware.ts # Next.js middleware
│ │ │ └── styles/
│ │ │ └── globals.css # Global styles
│ │ ├── public/ # Static assets
│ │ ├── Dockerfile # Web container
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── tailwind.config.ts
│ │ └── next.config.js
│ │
│ ├── api/ # FastAPI Backend
│ │ ├── app/
│ │ │ ├── routers/ # API route handlers
│ │ │ │ ├── auth.py # Authentication endpoints
│ │ │ │ ├── user.py # User profile endpoints
│ │ │ │ ├── billing.py # Billing & subscriptions
│ │ │ │ ├── usage.py # Usage tracking
│ │ │ │ ├── audits.py # Audit logs
│ │ │ │ ├── projects.py # Project management
│ │ │ │ ├── api_keys.py # API key management
│ │ │ │ └── events.py # Event ingestion
│ │ │ ├── models/ # SQLAlchemy ORM models
│ │ │ │ ├── user.py # User model
│ │ │ │ ├── profile.py # User profile
│ │ │ │ ├── organization.py # Organization
│ │ │ │ ├── project.py # Project
│ │ │ │ ├── api_key.py # API keys
│ │ │ │ ├── plan.py # Subscription plans
│ │ │ │ ├── subscription.py # User subscriptions
│ │ │ │ ├── usage_event.py # Usage events
│ │ │ │ ├── usage_monthly.py # Monthly usage aggregates
│ │ │ │ └── audit_event.py # Audit trail
│ │ │ ├── schemas/ # Pydantic schemas
│ │ │ ├── services/ # Business logic
│ │ │ ├── dependencies/ # FastAPI dependencies
│ │ │ │ ├── auth.py # Auth dependency
│ │ │ │ └── api_key_auth.py # API key auth
│ │ │ ├── utils/ # Utilities
│ │ │ │ ├── password.py # Password hashing
│ │ │ │ ├── jwt.py # JWT utilities
│ │ │ │ └── redis_client.py # Redis client
│ │ │ ├── config.py # Configuration
│ │ │ ├── database.py # Database setup
│ │ │ └── database_seed.py # Database seeding
│ │ ├── alembic/ # Database migrations
│ │ │ ├── versions/
│ │ │ │ ├── 001_initial_schema.py
│ │ │ │ ├── 002_add_plans_subscriptions_usage_audit.py
│ │ │ │ └── 003_add_org_project_apikeys.py
│ │ │ └── env.py
│ │ ├── main.py # FastAPI app entry
│ │ ├── requirements.txt # Python dependencies
│ │ ├── Dockerfile # API container
│ │ └── alembic.ini # Alembic config
│ │
│ └── worker/ # Background worker (empty/future)
│
├── infra/
│ └── caddy/
│ └── Caddyfile # Reverse proxy config
│
├── docker compose.yml # Docker orchestration
├── .env # Environment variables
├── .dockerignore
├── .gitignore
├── QUICKSTART.md # Quick start guide
├── setup_production.sh # Production setup script
└── verify_setup.sh # Setup verification script
Technology Stack
Frontend (Web)
- Framework: Next.js 16 (App Router)
- Language: TypeScript 5
- Styling: Tailwind CSS 4
- UI Library: Custom components with Framer Motion
- Fonts: Crimson Text (serif), Inter (sans-serif)
- State Management: React Context (AuthContext)
- HTTP Client: Native Fetch API
Backend (API)
- Framework: FastAPI 0.109.0
- Language: Python 3.11+
- ASGI Server: Uvicorn 0.27.0
- ORM: SQLAlchemy 2.0
- Migrations: Alembic 1.13
- Validation: Pydantic 2.5
- Password Hashing: Argon2-CFFI + Bcrypt
- JWT: PyJWT 2.8.0
- Email: aiosmtplib 3.0.1
Databases & Caching
- Database: PostgreSQL 16 (Alpine)
- Cache/Sessions: Redis 7 (Alpine)
Infrastructure
- Reverse Proxy: Caddy 2 (Alpine) with automatic HTTPS
- Containerization: Docker & Docker Compose
- SSL/TLS: Let's Encrypt (via Caddy)
Core Components
1. Authentication System
Location: apps/api/app/routers/auth.py, apps/web/src/contexts/AuthContext.tsx
Features:
- Email/password registration and login
- Email verification via OTP (One-Time Password)
- Password reset flow with OTP
- JWT-based authentication (access + refresh tokens)
- Rate limiting on login attempts
- Session management in Redis
- Token refresh mechanism
Flow:
- User registers → OTP sent to email
- User verifies email with OTP
- User logs in → receives access token (15min) + refresh token (30 days)
- Access token stored in localStorage, refresh token in httpOnly cookie
- Frontend automatically refreshes tokens before expiry
- User makes authenticated requests with Bearer token
2. Project Management
Location: apps/api/app/routers/projects.py, apps/api/app/models/project.py
Hierarchy:
User → Organization → Projects → API Keys
- Each user gets one organization (billing boundary)
- Each organization can have multiple projects
- Each project represents one MCP integration context
- Each project has:
- Name and environment (dev/staging/prod)
- Policy YAML (security rules)
- Multiple API keys
- Isolated audit logs and usage tracking
3. API Key Authentication
Location: apps/api/app/dependencies/api_key_auth.py, apps/api/app/models/api_key.py
Purpose: Secure access for MCP clients
Features:
- SHA-256 hashed keys stored in database
- Key format:
mcps_<random_string> - Keys linked to specific projects
- Can be revoked at any time
- Used for event ingestion and policy queries
4. Usage Tracking
Location: apps/api/app/routers/usage.py, apps/api/app/models/usage_event.py
Purpose: Monitor API usage and enforce plan limits
Features:
- Real-time event ingestion
- Monthly aggregation (UsageMonthly table)
- Usage summary by day/week/month
- Plan-based limits (Free: 10k events/month, Pro: 100k, Enterprise: unlimited)
5. Audit Logging
Location: apps/api/app/routers/audits.py, apps/api/app/models/audit_event.py
Purpose: Complete audit trail of all policy decisions
Features:
- Logs every policy evaluation
- Captures: tool name, decision (allow/deny), timestamp, project
- Filterable by date range, decision type, project
- Searchable interface in dashboard
- Retention based on subscription plan
6. Billing & Subscriptions
Location: apps/api/app/routers/billing.py, apps/api/app/models/subscription.py
Plans:
- Free: 10k events/month, 1 project, 30-day audit retention
- Pro ($29/month): 100k events/month, unlimited projects, 90-day retention
- Enterprise (custom): Unlimited events, unlimited projects, unlimited retention
Features:
- Plan upgrade/downgrade
- Usage-based billing
- Subscription status tracking
Database Schema
Core Tables
users
- id (UUID, PK)
- email (unique, indexed)
- password_hash (Argon2)
- first_name
- last_name
- is_email_verified (boolean)
- created_at, updated_at
profiles
- id (UUID, PK)
- user_id (UUID, FK → users)
- company, job_title, bio, location, website_url
- status (active/suspended/deleted)
- created_at, updated_at
organizations
- id (UUID, PK)
- name
- owner_user_id (UUID, FK → users, unique)
- created_at, updated_at
projects
- id (UUID, PK)
- org_id (UUID, FK → organizations)
- name
- environment (dev/staging/prod)
- policy_yaml (text)
- created_at, updated_at
api_keys
- id (UUID, PK)
- project_id (UUID, FK → projects)
- key_hash (SHA-256)
- key_prefix (mcps_...)
- name (optional)
- last_used_at
- created_at, revoked_at
plans
- id (UUID, PK)
- code (free/pro/enterprise)
- name, description
- price_monthly, price_yearly
- limits (JSON: max_events, max_projects, audit_retention_days)
- is_active
subscriptions
- id (UUID, PK)
- user_id (UUID, FK → users)
- plan_id (UUID, FK → plans)
- status (active/canceled/expired)
- current_period_start, current_period_end
- created_at, canceled_at
usage_events
- id (UUID, PK)
- project_id (UUID, FK → projects)
- event_type (policy_check/api_call)
- tool_name, decision
- timestamp
- metadata (JSON)
usage_monthly
- id (UUID, PK)
- user_id (UUID, FK → users)
- month, year
- event_count
- created_at, updated_at
audit_events
- id (UUID, PK)
- org_id (UUID, FK → organizations)
- project_id (UUID, FK → projects)
- timestamp
- tool_name, decision (allow/deny)
- policy_rule_matched
- request_metadata (JSON)
- created_at
Relationships
- User 1:1 Organization (owner)
- Organization 1:N Projects
- Project 1:N API Keys
- Project 1:N Audit Events
- Project 1:N Usage Events
- User 1:N Subscriptions
API Endpoints
Authentication (/auth)
POST /auth/register - Register new user
POST /auth/login - Login with email/password
POST /auth/refresh - Refresh access token
POST /auth/otp/request - Request OTP for verification/reset
POST /auth/otp/verify - Verify OTP code
POST /auth/password/reset - Reset password with reset token
User Management (/me)
GET /me - Get current user profile
PATCH /me - Update profile
DELETE /me - Delete account
Projects (/projects)
GET /projects - List all projects
POST /projects - Create new project
GET /projects/{id} - Get project details
PATCH /projects/{id} - Update project
DELETE /projects/{id} - Delete project
GET /projects/{id}/policy - Get project policy YAML
PUT /projects/{id}/policy - Update policy YAML
GET /projects/{id}/keys - List API keys
POST /projects/{id}/keys - Create API key
DELETE /projects/{id}/keys/{key_id} - Revoke API key
Usage (/usage)
GET /usage/monthly - Get monthly usage summary
GET /usage/summary - Get usage summary (last N days)
Audits (/audits)
GET /audits - List audit events (filterable)
Billing (/billing)
GET /billing/subscription - Get current subscription
POST /billing/subscribe - Subscribe to plan
Events (/events)
POST /events/ingest - Ingest usage/policy events (API key auth)
Health
GET / - API version info
GET /health - Health check
GET /docs - API documentation (Scalar UI)
GET /openapi.json - OpenAPI schema
Authentication & Authorization
Two Authentication Methods
1. JWT Bearer Token (User Authentication)
Used by: Web frontend for dashboard access
Headers:
Authorization: Bearer <access_token>
Flow:
- User logs in → receives
access_tokenandrefresh_token - Access token expires after 15 minutes
- Frontend checks token expiry before each request
- If expiring soon, automatically calls
/auth/refresh - New access token obtained and used for subsequent requests
Implementation: apps/api/app/dependencies/auth.py::get_current_user
2. API Key Authentication (Machine-to-Machine)
Used by: MCP clients/servers for event ingestion
Headers:
X-API-Key: mcps_<random_string>
Flow:
- User creates API key in dashboard
- Key is hashed (SHA-256) and stored in database
- Client includes key in X-API-Key header
- API validates hash and loads associated project
- Request is authorized for that project's scope
Implementation: apps/api/app/dependencies/api_key_auth.py::verify_api_key
Rate Limiting
Login Rate Limit:
- 5 attempts per 15 minutes per email+IP
- Implemented in Redis with TTL
- Location:
apps/api/app/services/rate_limit_service.py
OTP Rate Limit:
- 3 OTP requests per 5 minutes per email
- Prevents spam/abuse
- Redis-based with TTL
CORS Configuration
Allowed Origins:
http://localhost:3000(development)https://mcpshield.xyz(production)https://app.mcpshield.xyz(production)https://www.mcpshield.xyz(production)
Settings:
- Credentials: Allowed
- Methods: All
- Headers: All
Location: apps/api/main.py
Frontend Pages & Routes
Public Routes
Landing Page (/)
- Hero section with value proposition
- Feature showcase
- Pricing information
- Call-to-action buttons
Documentation (/docs)
- API documentation
- Integration guides
- Policy syntax reference
Authentication Routes (/auth)
Sign Up (/auth/sign-up)
- Email, password, name fields
- Password confirmation
- Triggers OTP email
Verify OTP (/auth/verify-otp)
- 6-digit OTP input
- Email verification
- Resend OTP option
Sign In (/auth/sign-in)
- Email/password login
- Remember me option
- Forgot password link
Forgot Password (/auth/forgot-password)
- Email input
- Triggers password reset OTP
Reset Password (/auth/reset-password)
- New password input
- Confirmation field
- Uses reset token from OTP
Protected Routes (/app/*)
Layout: Sidebar navigation + main content area
Projects (/app/projects)
- List all projects
- Create new project
- Quick actions (view, edit, delete)
Project Keys (/app/projects/[projectId]/keys)
- List API keys for project
- Create new key (shows once)
- Revoke keys
- Copy to clipboard
Project Policy (/app/projects/[projectId]/policy)
- YAML policy editor
- Syntax highlighting
- Save/validate policy
- Policy documentation
Usage (/app/usage)
- Usage charts (daily/weekly/monthly)
- Event count by project
- Current plan limits
- Upgrade prompts
Audits (/app/audits)
- Filterable audit log table
- Date range picker
- Decision filter (allow/deny)
- Project filter
- Pagination
Billing (/app/billing)
- Current plan details
- Usage statistics
- Plan comparison
- Upgrade/downgrade options
- Billing history
Profile (/app/profile)
- Edit name, company, bio
- Profile picture upload (future)
- Account status
Settings (/app/settings)
- Email notifications
- Security settings
- API preferences
- Danger zone (delete account)
Infrastructure & Deployment
Docker Compose Services
1. Caddy (Reverse Proxy)
Image: caddy:2-alpine
Ports: 80, 443, 443/udp (HTTP/3)
Purpose:
- Automatic HTTPS with Let's Encrypt
- Reverse proxy to web and API
- Security headers
- Gzip/Zstd compression
Domains:
mcpshield.xyz→ web:3000 (landing/marketing)app.mcpshield.xyz→ web:3000 (dashboard)api.mcpshield.xyz→ api:8000 (backend)
2. PostgreSQL
Image: postgres:16-alpine
Purpose: Primary database
Volumes: postgres_data:/var/lib/postgresql/data
Health Check: pg_isready
Note: Not exposed externally (internal network only)
3. Redis
Image: redis:7-alpine
Purpose:
- Session storage
- Rate limiting
- OTP storage
- Token blacklist
Volumes:
redis_data:/dataHealth Check:redis-cli pingNote: Not exposed externally
4. API (FastAPI)
Build: apps/api/Dockerfile
Port: 8000 (internal)
Depends On: PostgreSQL (healthy), Redis (healthy)
Purpose: Backend API server
Health Check: curl -f http://localhost:8000/health
5. Web (Next.js)
Build: apps/web/Dockerfile
Port: 3000 (internal)
Purpose: Frontend application
Build Args: NEXT_PUBLIC_API_BASE
Memory Limit: 4GB
Health Check: wget http://localhost:3000
Network Architecture
All services run on mcpshield_network (bridge driver):
- Services communicate via container names (e.g.,
api:8000,postgres:5432) - Only Caddy exposes ports to external network (80, 443)
- PostgreSQL and Redis are internal-only
- Web and API are accessed via Caddy reverse proxy
Persistent Volumes
postgres_data: # Database files
redis_data: # Redis persistence
caddy_data: # SSL certificates
caddy_config: # Caddy configuration
Security Measures
- No Direct Database Access: PostgreSQL/Redis not exposed externally
- HTTPS Everywhere: Automatic SSL via Let's Encrypt
- Security Headers: HSTS, X-Frame-Options, CSP, etc.
- Password Hashing: Argon2 (industry standard)
- Rate Limiting: Prevents brute force attacks
- JWT Expiry: Short-lived access tokens (15min)
- API Key Hashing: SHA-256 hashed before storage
- Input Validation: Pydantic schemas validate all inputs
- SQL Injection Prevention: SQLAlchemy ORM with parameterized queries
- CORS Restrictions: Limited to whitelisted origins
Key Features
1. AI-Powered Policy Generation (NEW!)
Natural language to security policies using self-hosted Ollama:
- Chat-based policy creation: "Allow read-only access to analytics tables"
- Security analysis: Analyzes policies and queries for vulnerabilities
- Infrastructure advice: Best practices for securing complex systems
- Token-tracked usage with plan limits (Free: 3 AI/month, Pro: 30 AI/month)
- Supports PostgreSQL, MySQL, SQLite, MongoDB, Redis policies
2. Multi-Infrastructure Support
Secure access to diverse systems with unified policies:
- Databases: PostgreSQL, MySQL, SQLite, MongoDB, Redis
- Future: APIs, cloud platforms, file systems, and custom adapters
- Consistent policy syntax across all infrastructure types
- Per-project infrastructure configuration
3. Policy Engine (YAML-Based)
Users define security policies in YAML format for each project. Policies control:
- Which MCP tools are allowed/denied
- Parameter validation rules
- Rate limits per tool
- Allowed/blocked domains
- Sensitive data filters
Example policy:
version: 1
default: deny
rules:
- tool: "filesystem.read"
decision: allow
conditions:
path_prefix: "/home/safe/"
- tool: "network.request"
decision: allow
conditions:
allowed_domains:
- "api.example.com"
4. Real-Time Audit Trail
Every policy decision is logged:
- Tool name and parameters
- Allow/deny decision
- Matched policy rule
- Timestamp and project
- Request metadata
5. Usage Analytics
Track and visualize:
- Daily/weekly/monthly event counts
- AI generation usage (with token counts)
- Events by project and decision type
- Plan limit enforcement (AI generations + infrastructure queries)
6. Multi-Project Isolation
Each project has:
- Independent API keys
- Separate policy configuration
- Infrastructure type selection (PostgreSQL, MySQL, etc.)
- Isolated audit logs
- Independent usage tracking
7. Email-Based OTP System
Secure verification without SMS:
- 6-digit numeric code
- 10-minute expiry
- Max 5 verification attempts
- Rate limited (3 requests per 5 min)
- Used for email verification and password reset
Data Flow
User Registration Flow
1. User submits registration form
2. API validates data
3. API creates User + Profile records
4. API generates 6-digit OTP
5. API stores OTP in Redis (10min TTL)
6. API sends OTP via SMTP
7. User enters OTP on verification page
8. API validates OTP from Redis
9. API marks email as verified
10. User can now log in
Authentication Flow
1. User submits login credentials
2. API checks rate limit (Redis)
3. API verifies password (Argon2)
4. API creates access token (15min) + refresh token (30 days)
5. API stores session in Redis
6. API returns both tokens
7. Frontend stores access in localStorage, refresh in httpOnly cookie
8. Frontend includes access token in Authorization header
9. When access token expires, frontend calls /auth/refresh
10. API validates refresh token and issues new tokens
Event Ingestion Flow
1. MCP client makes policy decision
2. Client calls POST /events/ingest with X-API-Key header
3. API validates API key (SHA-256 hash check)
4. API loads associated project
5. API creates UsageEvent record
6. API increments UsageMonthly counter
7. API creates AuditEvent record (if policy decision)
8. API checks plan limits
9. API returns 202 Accepted
Policy Evaluation Flow
1. MCP client requests policy check
2. Client includes tool name and parameters
3. API loads project's policy YAML
4. API parses YAML and evaluates rules
5. API finds first matching rule (top-to-bottom)
6. API applies conditions (path_prefix, allowed_domains, etc.)
7. API returns decision (allow/deny) with matched rule
8. API logs decision to audit_events table
9. Client enforces decision (blocks or allows tool execution)
Token Refresh Flow
1. Frontend detects access token expiring soon
2. Frontend calls POST /auth/refresh with refresh_token
3. API validates refresh token signature and expiry
4. API checks if token is blacklisted (Redis)
5. API extends session in Redis
6. API issues new access token + new refresh token
7. API returns tokens to frontend
8. Frontend updates localStorage and continues
Environment Configuration
Required Environment Variables
Database (.env):
DB_USER=mcpshield
DB_PASSWORD=<secure_random_password>
DB_HOST=postgres
DB_PORT=5432
DB_NAME=mcpshield_db
Redis:
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=<secure_random_password>
JWT:
JWT_SECRET=<secure_random_secret_256bit>
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=15
JWT_REFRESH_TOKEN_EXPIRE_DAYS=30
SMTP (Email):
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USE_STARTTLS=true
SMTP_USERNAME=noreply@mcpshield.xyz
SMTP_PASSWORD=<app_password>
SMTP_FROM_NAME=MCPShield
SMTP_FROM_EMAIL=noreply@mcpshield.xyz
Application:
API_URL=https://api.mcpshield.xyz
WEB_URL=https://app.mcpshield.xyz
NEXT_PUBLIC_API_BASE=https://api.mcpshield.xyz
ENVIRONMENT=production
OTP Configuration:
OTP_LENGTH=6
OTP_EXPIRE_MINUTES=10
OTP_MAX_ATTEMPTS=5
Rate Limiting:
LOGIN_RATE_LIMIT_ATTEMPTS=5
LOGIN_RATE_LIMIT_WINDOW_MINUTES=15
OTP_RATE_LIMIT_REQUESTS=3
OTP_RATE_LIMIT_WINDOW_MINUTES=5
Development vs Production
Development (ENVIRONMENT=development):
- API:
http://localhost:8000 - Web:
http://localhost:3000 - No HTTPS required
- Hot reload enabled
- Debug logging
Production (ENVIRONMENT=production):
- API:
https://api.mcpshield.xyz - Web:
https://app.mcpshield.xyz - HTTPS enforced (Caddy)
- Optimized builds
- Error logging only
How Everything Works Together
Complete Request Flow Example: User Creates a Project
-
User Action: Clicks "New Project" button in
/app/projects -
Frontend (
apps/web/src/app/app/projects/page.tsx):- Collects project name and environment
- Calls
projectsAPI.create()fromapi-client.ts
-
API Client (
apps/web/src/lib/api-client.ts):- Checks if access token needs refresh
- Adds
Authorization: Bearer <token>header - Sends
POST /projectsrequest
-
API Router (
apps/api/app/routers/projects.py):@router.post("/projects")receives request- Dependency
get_current_uservalidates JWT - Extracts user from token payload
-
Business Logic:
- Loads user's organization (1:1 relationship)
- Validates project name uniqueness
- Creates new
Projectrecord with org_id - Generates default policy YAML
-
Database (PostgreSQL):
- Inserts record into
projectstable - Returns generated UUID and timestamps
- Inserts record into
-
Response:
- API returns project object as JSON
- Frontend receives new project data
- UI updates with new project in list
-
Side Effects:
- Organization's
updated_atfield updated - Audit log created (future feature)
- Organization's
Complete Authentication Flow Example
-
User Logs In:
- Enters email/password on
/auth/sign-in - Frontend calls
authAPI.login()
- Enters email/password on
-
Rate Limit Check (Redis):
- Key:
login:{email}:{ip} - Check attempts < 5 in last 15 minutes
- Key:
-
Password Verification:
- Load user by email from
userstable - Verify password with Argon2
- Hash comparison (constant-time)
- Load user by email from
-
Token Generation:
- Create access token (JWT) with user_id, email, expiry (15min)
- Create refresh token (JWT) with user_id, expiry (30 days)
- Sign both with
JWT_SECRET
-
Session Creation (Redis):
- Key:
session:{user_id} - Store: user data, login time, IP
- TTL: 30 days
- Key:
refresh_token:{token_hash} - Store: user_id
- TTL: 30 days
- Key:
-
Response:
- Return
{ access_token, refresh_token } - Frontend stores access token in localStorage
- Frontend stores refresh token in memory (and httpOnly cookie in production)
- Return
-
Authenticated Requests:
- Every request includes
Authorization: Bearer <access_token> - API validates token signature and expiry
- Extracts user_id from payload
- Loads user from database
- Proceeds with request
- Every request includes
-
Token Refresh (Before Expiry):
- Frontend detects token expiring soon (< 5min left)
- Calls
POST /auth/refreshwith refresh_token - API validates refresh token
- Issues new access + refresh tokens
- Frontend updates stored tokens
- User remains logged in seamlessly
Complete Event Ingestion Example
-
MCP Client Decision:
- User's AI agent wants to read a file
- MCP client checks local policy (if cached)
- Client needs to report event to MCPShield
-
API Call:
- Client calls
POST /events/ingest - Headers:
X-API-Key: mcps_abc123... - Body:
{ tool: "filesystem.read", decision: "allow", timestamp: "..." }
- Client calls
-
API Key Authentication:
- API extracts key from
X-API-Keyheader - Hashes key with SHA-256
- Looks up hash in
api_keystable - Validates key not revoked
- Loads associated project
- Updates
last_used_atfield
- API extracts key from
-
Event Recording:
- Create
UsageEventrecord:- project_id, event_type, tool_name, decision, timestamp, metadata
- Create/update
UsageMonthlyrecord:- Increment event_count for current month
- Create
-
Audit Logging:
- Create
AuditEventrecord:- org_id, project_id, tool_name, decision, timestamp, policy_rule_matched
- Create
-
Plan Limit Check:
- Load user's subscription
- Load plan limits (max_events)
- Check if monthly usage exceeds limit
- If exceeded, return warning in response
-
Response:
- Return
202 Accepted(event recorded) - Include usage summary in body
- Client continues operation
- Return
-
Dashboard Update:
- User visits
/app/usage - Frontend calls
GET /usage/summary - API aggregates
UsageEventrecords by day - Returns chart data
- Frontend renders usage graphs
- User visits
Summary
MCPShield is a comprehensive full-stack application providing:
- Secure Authentication: JWT-based with email verification and OTP
- Multi-Tenancy: Organizations → Projects → API Keys hierarchy
- Policy Enforcement: YAML-based security rules for MCP tools
- Complete Auditing: Every decision logged and searchable
- Usage Tracking: Real-time event ingestion with plan limits
- Modern Stack: Next.js + FastAPI + PostgreSQL + Redis
- Production-Ready: Docker Compose with Caddy for HTTPS
- Developer-Friendly: Clear API docs, type safety, migrations
The application is designed for AI safety and security, providing deterministic policy enforcement and comprehensive audit trails for MCP server integrations.