Securing Your MCP Server: Auth, Rate Limiting, and Input Validation

🧠 Why Secure an MCP Server?

An MCP Server exposes tools, APIs, and automation workflows that could trigger external calls, invoke LLMs, or perform sensitive operations.

Without proper security, your server can be vulnerable to:

  • 🚨 Unauthorized access to internal tools
  • 🧨 Prompt injection attacks or malformed input
  • 🌊 API abuse through spamming
  • πŸ”„ Infinite loops in workflows

This guide walks you through securing an MCP server using:

  • βœ… API key or token-based authentication
  • 🚦 Per-IP or per-user rate limiting
  • βœ… Schema and type-based input validation
  • 🚧 Guardrails for safe tool/plugin exposure

βš™οΈ Tech Stack

  • FastAPI: Framework to run the MCP server
  • slowapi: Lightweight rate limiting plugin
  • pydantic: Input validation (built-in with FastAPI)
  • uuid, secrets: For API key/token generation

πŸ”§ Setting Up a Secure MCP Server

Step 1: Basic MCP Server with FastAPI

# mcp_server.py
from fastapi import FastAPI
from mcp.server.fastmcp import FastMCP

app = FastAPI()
mcp = FastMCP("Secure Server")

@app.on_event("startup")
async def load_tools():
    # Register plugins here
    @mcp.tool()
    def echo(text: str) -> str:
        return f"You said: {text}"

    mcp.mount(app)

πŸ”‘ Step 2: Add API Key Authentication

Generate and Store API Keys (simplified example)

# key_storage.py
from uuid import uuid4

API_KEYS = {
    "user1": str(uuid4()),  # securely store this in a DB or vault
}

Auth Dependency for FastAPI

# auth.py
from fastapi import Depends, Header, HTTPException

from key_storage import API_KEYS

def api_key_auth(x_api_key: str = Header(...)):
    if x_api_key not in API_KEYS.values():
        raise HTTPException(status_code=403, detail="Invalid API Key")

Apply Auth to Routes

from fastapi import Depends
from auth import api_key_auth

@app.get("/ping", dependencies=[Depends(api_key_auth)])
def ping():
    return {"message": "pong"}

🚦 Step 3: Rate Limiting with slowapi

pip install slowapi

Configure and Apply Rate Limiter

from slowapi import Limiter
from slowapi.util import get_remote_address
from fastapi import Request
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.middleware("http")
async def add_rate_limit_headers(request: Request, call_next):
    response = await call_next(request)
    return limiter.inject_headers(response, request)

@app.exception_handler(RateLimitExceeded)
def rate_limit_handler(request: Request, exc: RateLimitExceeded):
    return JSONResponse(
        status_code=429,
        content={"detail": "Rate limit exceeded"}
    )

Apply to Route or Globally

@app.get("/secure-echo", dependencies=[Depends(api_key_auth)])
@limiter.limit("10/minute")
def secure_echo():
    return {"message": "ok"}

βœ… Step 4: Input Validation with Pydantic

Let’s restrict tool/plugin inputs to well-defined schemas.

from pydantic import BaseModel

class SumInput(BaseModel):
    a: int
    b: int

@mcp.tool()
def add_numbers(input: SumInput) -> int:
    return input.a + input.b

If the input doesn’t match the schema (e.g., a string instead of int), FastAPI will return a 422 validation error.


πŸ” Optional: Scoped Tool Access

Restrict sensitive tools based on user identity or API key.

SENSITIVE_TOOLS = {"delete_data", "modify_config"}

def is_allowed(api_key: str, tool_name: str):
    if tool_name in SENSITIVE_TOOLS and api_key != ADMIN_API_KEY:
        raise HTTPException(status_code=403, detail="Access Denied")

Use this inside the plugin or within middleware before tool dispatch.


🚨 Security Edge Cases to Guard Against

Attack Vector Guardrail to Apply
πŸ§‘β€πŸ’» Prompt Injection Sanitize input; never echo raw prompts
🌊 Abuse via LLM Calls Add rate limits, usage quotas
πŸš€ Workflow Loops Add execution step counter per context
⚑ DoS via Large Payloads Enforce max payload size in FastAPI config
πŸ“‘ Unauthorized Tools Filter exposed tools by API key/user roles

πŸ” Real-World Use Case: AI Agent for Internal Tools

Context

Your company builds an internal AI agent with plugins for: * run_sql_query * delete_customer_account * summarize_logs

Security Strategy

Tool Protection
run_sql_query Input validation, SQL injection sanitizer
delete_customer_account Only admin API keys allowed
summarize_logs Rate limited (e.g., 5 req/min per IP)

Conclusion

Securing your MCP server is essential as you expose more powerful tools to LLMs. Treat your server like a production-grade API β€” not a toy playground.

With authentication, rate limiting, and input validation, you can:

  • Prevent abuse and unauthorized access
  • Enforce usage fairness
  • Ensure plugin execution safety

🧰 Tools Used * FastAPI * slowapi * mcp


Keywords: MCP server security, MCP FastAPI, secure AI workflows, rate limiting Python, API key FastAPI, prompt injection prevention, MCP tool access control, model context protocol authentication


Explore More AI Posts

  • AI
  • 3 min read
Understanding ChatGPT Models: GPT-3.5, GPT-4, GPT-4-turbo, and Beyond

Explore the different ChatGPT models offered by OpenAI, including GPT-3.5, GPT-4, GPT-4-turbo, GPT-4.1, GPT-4.5, and GPT-4o. Learn how they differ in…

Read More
  • AI
  • 4 min read
How to Build and Register Plugins in an MCP Server (OpenAI & YouTube API Examples)

Learn how to build modular, context-aware plugins for your Model Context Protocol (MCP) server. Includes step-by-step examples for OpenAI GPT-based s…

Read More
  • AI
  • 6 min read
What is an MCP (Model Context Protocol) Server? A Complete Guide for AI Engineers

Discover the power of the Model Context Protocol (MCP) Server β€” an innovative way to orchestrate AI models and tools with context-awareness. Learn ho…

Read More