mcp-server-prod

mcp-server-prod

A hardened MCP server exposing read-only orders tools to AI agents, with rigorous input validation and parameterized queries to prevent injection attacks.

Category
Visit Server

README

mcp-server-prod

A hardened MCP server — because MCP tool arguments are written by an LLM, from untrusted user text. Exposes read-only "orders" tools to an AI agent, and treats every argument as hostile: validated, parameterized, and served over a read-only connection.

Runs offline. docker compose up runs the security battery with no API key and no network — the standard library only. (The MCP server itself needs pip install mcp.)


The problem

An MCP tool signature like search_orders(status: str) looks safe. But status doesn't come from your code — it comes from a model, interpreting whatever a user typed. That's a network boundary wearing a function signature. The naive server everyone writes first concatenates that string into SQL and calls it a day:

sql = f"SELECT * FROM orders WHERE status = '{status}'"   # ← LLM-controlled

One status = "paid' OR '1'='1" and the agent just dumped your whole table.

Quickstart

docker compose up        # security battery: naive vs prod scorecard (offline)
make demo                # same, without Docker
make test                # the security contract tests (pytest)
make serve               # run the actual MCP server over stdio (needs: pip install mcp)

The scorecard (before → after)

The same five hostile tool-calls, run against the naive server and this one:

attack naive prod
filter bypass — status = paid' OR '1'='1 🔴 LEAK 🟢 SAFE
table exfil — customer = zzz' OR '1'='1 🔴 LEAK 🟢 SAFE
numeric injection — min_total = "0 OR 1=1" 🔴 LEAK 🟢 SAFE
id injection — get_order("1 OR 1=1") 🔴 LEAK 🟢 SAFE
write reaches the DB (read-only?) 🔴 LEAK 🟢 SAFE
safely handled 0 / 5 5 / 5

Meanwhile legitimate queries are unaffected — search_orders(status="paid") returns the 12 paid orders, revenue_summary("paid") returns {count: 12, total: 25451.24}. Hardening didn't cost functionality.

The three defenses

  1. Validate every argument (validation.py) — status must be an enum member, order_id must be an integer, limit is clamped to 100. An agent asking for a million rows gets 100; a bad enum is a structured error, not a silent mis-query.
  2. Parameterize every query (tools.py) — user values are bound, never concatenated. customer = "zzz' OR '1'='1" becomes a literal name that matches nobody, not a bypass.
  3. Open the database read-only — file:...?mode=ro. Defense in depth: even a query that slips through cannot mutate data. The write test raises at the driver.

Wire it into a desktop MCP client

{
  "mcpServers": {
    "orders": { "command": "python", "args": ["-m", "mcp_server_prod.server"] }
  }
}

Drop that into Claude Desktop's MCP config and the search_orders / get_order / revenue_summary tools appear to the agent. (A short screen recording of that flow makes a good demo GIF — the server code and config here are what it records.)

How it's verified

Security is a contract test suite, not a claim: the production tools must reject or safely handle each hostile input, and the naive implementation must demonstrably leak (so the threat is real, not hypothetical). CI also builds the server against the official mcp SDK. All checks run offline; the battery scorecard is computed from real behavior.

9 passed        # pytest
0/5 → 5/5       # security battery
mcp server ok   # builds with the official SDK

Honest limitations

· Synthetic 20-row SQLite dataset — a demonstrator of the access pattern, not a product.
· Scope is read-only retrieval. A write-capable server needs authЗ, per-tool authorization,
  and audit logging (authn/authz) — explicitly out of scope here and called out, not faked.
· The "naive vs prod" contrast is illustrative; it doesn't enumerate every injection class
  (no second-order, stored, or ORM-specific vectors).
· Parameterization + read-only defends the data layer; it is not a full threat model
  (rate limiting, secrets handling, and prompt-injection of the agent itself are separate).

Layout

mcp_server_prod/  db.py · validation.py · tools.py (prod) · naive.py · server.py · demo.py
tests/            test_security.py       # the security contract
Dockerfile · docker-compose.yml · .github/workflows/ci.yml

MIT © 2026 Jigon Yoo

Recommended Servers

playwright-mcp

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured