Skip to main content
Glama
dhaanish597

Security-Hardened MCP Server

by dhaanish597

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 inputSchema is 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.)

Related MCP server: MCP Server TypeScript

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 — withGuards steps 1–3 are TODO(M2)/TODO(M3); per-tool authorization (scope enforcement) lands in M2.

  • The per-tool arg byte-cap control (withGuards step 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.

Related MCP Connectors

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A production-ready TypeScript MCP server providing basic tools (add, echo, timestamp), resources (server info, greetings, data access), and prompt templates (analyze, code-review, summarize). Serves as a foundation for building custom MCP servers with extensible architecture.
    205 npm
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    A boilerplate project for quickly developing MCP servers using TypeScript, featuring example implementations of tools (calculator, greetings) and resources (server info) with Zod schema validation.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    An extensible TypeScript-based MCP server designed for Claude Code with a modular architecture for easily adding custom tools. It includes built-in examples like a calculator and echo tool, utilizing Zod for robust input validation and error handling.
    25 npm
    -