Security-Hardened MCP Server
A TypeScript MCP server with strict schema validation and security guards, currently implementing echo, get_time, hash_text, uuid_generate, and json_validate tools.
README
Security-Hardened MCP Server
A TypeScript Model Context Protocol server built to be defensible in an interview:
every security control is backed by an adversarial test or a committed artifact, or
it is listed as an open finding. Built on the official @modelcontextprotocol/sdk
(Streamable HTTP + stdio), Express 5, and Zod.
Status: M1 (schema validation) — strict input rejection and output validation are proven (T05 CLOSED): every registered tool's
inputSchemais a.strict()Zod object fed directly to the SDK, so unknown/extra keys, wrong types, and out-of-range values are rejected against the raw JSON-RPC arguments, and output is strict-validated before it leaves the server. Authentication, scopes, rate limiting, and the remaining eight tools are still open — all other threat-model rows remain OPEN.
Architecture
requestId → originCheck → bodyLimit → auth → httpRateLimit → concurrencyCap
→ StreamableHTTPServerTransport → McpServer dispatch
→ withGuards: authz → rate limit → arg cap → timeout
→ output validate → sanitize → audit
(As of M1, withGuards steps 4/6/7/9 — arg byte cap, output validate, sanitize, and
structured error mapping — are live. The Express-layer middleware chain above
McpServer dispatch is still ordered stubs beyond requestId and body parsing.)
Tools (12 planned)
| Tool | Scope | Demonstrates | Status |
|---|---|---|---|
echo |
echo:call |
connectivity / baseline | Implemented |
get_time |
time:read |
— | Implemented |
hash_text |
hash:compute |
— | Implemented |
uuid_generate |
uuid:generate |
— | Implemented |
json_validate |
json:validate |
hostile-schema handling (schema-of-death) | Implemented |
text_summarize_stats |
text:analyze |
— | Not yet implemented |
unit_convert |
unit:convert |
— | Not yet implemented |
url_metadata |
url:read |
SSRF defense (T06/T07) | Not yet implemented |
math_eval |
math:eval |
AST sandbox (T09) | Not yet implemented |
password_strength |
password:analyze |
— | Not yet implemented |
regex_test |
regex:test |
ReDoS defense (T08) | Not yet implemented |
kv_store |
kv:read / kv:write |
per-principal isolation (T10) | Not yet implemented |
Threat model
See docs/THREAT-MODEL.md. T05 is CLOSED as of M1; all other rows remain OPEN.
How to run
Prerequisites: Node 22 (nvm use), Docker.
npm ci
# HTTP (Streamable HTTP on :3000)
MODE=http PORT=3000 npm run dev
curl -s localhost:3000/healthz # -> {"status":"ok"}
# stdio (JSON-RPC over stdin/stdout; logs go to stderr)
npm run build
MODE=stdio node dist/index.js
# Docker
docker build -t security-hardened-mcp-server:latest .
docker run --rm -e MODE=http -p 3000:3000 security-hardened-mcp-server:latest
# or: docker compose up --build
Inspect with MCP Inspector:
# HTTP: run the server, then open the Inspector and connect Streamable HTTP to
# http://localhost:3000/mcp
npx @modelcontextprotocol/inspector
# stdio: Inspector launches the server itself
MODE=stdio npx @modelcontextprotocol/inspector node dist/index.js
Known limitations (M1)
- Still no authentication, no scopes, no rate limiting —
withGuardssteps 1–3 areTODO(M2)/TODO(M3); per-tool authorization (scope enforcement) lands in M2. - The per-tool arg byte-cap control (
withGuardsstep 4) exists and is unit-tested, but its dedicated adversarial proof, T04, lands in M3. - 5 of 12 tools implemented (
echo,get_time,hash_text,uuid_generate,json_validate); the remaining seven, and threat-model rows T06–T15, land in M2–M4. - Not deployed; single-host only.
M1 Claim Audit
| Resume phrase | Artifact | Verdict |
|---|---|---|
| "12 authenticated tools" | 5 of 12 tools exist (echo, get_time, hash_text, uuid_generate, json_validate); no auth yet — withGuards steps 1–2 are TODO(M2), calls run with principal: null |
NOT YET |
| "schema validation" | Strict input rejection is genuine and server-side: register() feeds the SDK .strict() objects, so unknown/extra keys, wrong types, missing required fields, out-of-range values, and deeply-nested payloads are rejected against the RAW arguments; output is strict-validated (step 6); json_validate caps a hostile schema's depth/size; errors are internal-detail-free (step 9). T05_schema_rejection.test.ts is green and fails when strict registration or the complexity guard is removed (delete-the-control drill recorded). |
PROVEN |
| "rate limiting" | none yet (M3); withGuards step 3 + rateLimit.ts do not exist |
NOT YET |
| "load-tested to 50+ concurrent" | none yet (M5) | NOT YET |
"Schema validation" is now the one PROVEN phrase; the other three remain NOT YET as scoped. The per-tool arg byte-cap control (step 4) is implemented and unit-tested but its full adversarial proof is T04 (M3), so it is not yet claimed as an independently-proven line.
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.