FastMCP Production Server

FastMCP Production Server

Provides secure filesystem operations, HTTP fetching with SSRF protection, JSON validation, artifact logging, and optional Redis key-value storage through both stdio and HTTP transports. Features production-ready security controls including sandbox enforcement, allowlist validation, and comprehensive input validation.

Category
Visit Server

README

<!-- README.md -->

MCP FastMCP Server (stdio + HTTP) — Production‑minded PoC

Purpose
This repository implements a Model Context Protocol (MCP) server in Python, with both stdio and Streamable HTTP transports. It exposes a practical set of tools (filesystem, HTTP fetch with SSRF guards, JSON Schema validation, append‑only artifacts, and optional Redis KV) using a production‑minded architecture: clean separation of concerns, strong input validation, explicit security controls, and a single tool registry powering both transports.


Contents

  • What is MCP? Why this server?
  • Architecture Overview
  • Transports
    • stdio (local)
    • Streamable HTTP (remote)
  • Security Model
  • Tools Exposed
  • Configuration
  • Quick Start
    • Run stdio transport
    • Run HTTP transport
  • How Agents Use This Server
  • Add a New Tool (Contributor Guide)- Testing, Linting, CI
  • Observability & Auditing
  • Design Rationale
  • Folder Structure
  • FAQ
  • References

What is MCP? Why this server?

Model Context Protocol (MCP) is an open, JSON‑RPC‑based protocol that lets AI clients/hosts discover and invoke tools and read resources from servers in a standard way. MCP defines how to list tools (names, descriptions, input schemas) and call them over a transport (stdio for local or Streamable HTTP for remote).

This server demonstrates a production‑minded Python implementation that:

  • Keeps LLM reasoning in your agent while the server executes safe, deterministic tools.
  • Provides stdio (easy local dev) and HTTP (remote/multi‑tenant) with a shared tool registry.
  • Emphasizes security: filesystem sandbox, SSRF guards+allowlist, Origin validation, Bearer token.

Architecture Overview

mcp-fastmcp-server/
├─ server/
│  ├─ main.py                 # stdio transport entrypoint (FastMCP host)
│  ├─ http_app.py             # Streamable HTTP (FastAPI + Bearer + Origin checks)
│  └─ registry.py             # SINGLE source of truth: tools metadata + handlers
├─ server/tools/              # Only Pydantic input models live here (thin)
│  ├─ files.py                # FsWriteIn, FsReadIn models
│  ├─ http_fetch.py           # FetchIn model
│  ├─ json_validate.py        # JsonValidateIn model
│  ├─ artifacts.py            # ArtifactLogIn, ArtifactListIn models
│  └─ kv.py                   # KvPutIn, KvGetIn models (optional)
├─ app/
│  ├─ config.py               # Settings (env-driven)
│  ├─ di.py                   # Dependency wiring (services from settings)
│  ├─ logging.py              # Redaction helpers & log config
│  └─ services/
│     ├─ filesystem.py        # sandboxed FS
│     ├─ httpclient.py        # Safe HTTP (allowlist, DNS/IP checks, timeouts, caps)
│     ├─ validator.py         # JSON Schema validator
│     ├─ artifacts.py         # append/list NDJSON, monthly rotation
│     └─ kvstore.py           # Redis KV (optional)
├─ tests/                     # Unit tests (services + tools)
├─ scripts/                   # Dev scripts (setup, run, test, http run)
├─ .github/workflows/ci.yml   # GitHub Actions: make test on push/PR
├─ Makefile                   # setup, run, run-http, test, lint, typecheck
├─ pyproject.toml / requirements.txt
└─ .env.example / README.md

Key idea: the tool registry (server/registry.py) centralizes:

Tool metadata (name, description, Pydantic input model → JSON Schema). Named handlers that call into services. Helpers to emit list payloads and dispatch tool calls. A hook to register every tool into the FastMCP stdio host.

Both transports import the same registry, guaranteeing consistent tools/schemas everywhere.

Transports

1-stdio (local)

The host (agent/IDE like VS Code) launches the server as a subprocess and exchanges JSON‑RPC over stdin/stdout. Great for local dev and IDE integration. Spec: stdio framing & rules (pure JSON‑RPC, newline delimited). See Transports (concepts/spec) in references.

Entrypoint:

python -m server.main
VS Code can launch stdio MCP servers; see its MCP docs: <https://code.visualstudio.com/docs/copilot/customization/mcp-servers>

2-Streamable HTTP (remote)

The server exposes a single MCP endpoint (e.g., /mcp) that accepts JSON‑RPC 2.0 via HTTP POST (one request per message). Optional SSE GET allows server‑initiated messages and streaming. Security: you must validate Origin and should require authentication to mitigate DNS rebinding risks. This server enforces Bearer token and Origin allowlist. See Transports (concepts/spec) in references.

Entrypoint:

uvicorn server.http_app:app --host 127.0.0.1 --port 8080

HTTP client flow (JSON‑RPC):

  1. initialize
  2. tools/list
  3. tools/call with { "name": "tool", "arguments": { ... } }

Transport details (single endpoint, POST per message, Origin validation, optional SSE) follow the MCP spec:

Security Model

  1. Filesystem sandbox

All fs tools operate under SANDBOX_ROOT; path traversal escapes are rejected in app/services/filesystem.py.

  1. HTTP client safety
  • http_fetch: allowlisted domains only; rejects private/loopback/link‑local/reserved IPs after DNS resolution; enforces timeouts and response size caps (prevents SSRF, resource abuse).
  1. HTTP transport controls
  • Origin validation and Bearer token are enforced on each HTTP request, per MCP HTTP transport guidance (see spec links above).
  1. Strict input validation
  • Each tool uses a Pydantic model; MCP tools/list publishes JSON Schemas so clients can validate before calling (see Tools spec).
  1. No secrets in logs
  • Basic email redaction is included in app/logging.py; extend redactors as needed.

Tools Exposed

All tools are non‑LLM deterministic capabilities. Keep your LLM planning inside your agent.

  • fs_write(path, content) / fs_read(path)

Sandbox‑enforced text file I/O under SANDBOX_ROOT.

  • http_fetch(url, method='GET', headers?, body?) Safe HTTP client with allowlist, DNS/IP checks (blocks private/loopback), timeout, size caps.

  • json_validate(instance, schema, draft?) Validate a JSON payload against a JSON Schema (draft 2020‑12 by default). Returns { "valid": bool, "errors": [...] }. Useful for preflight (validate before side‑effects) and auto‑repair loops.

    • JSON Schema in MCP flows is common to enforce shape & types (see Tools spec).
  • artifact_log(tag, content, meta?, corr?, actor?, tool?) Append a redacted, immutable NDJSON record under .sandbox/artifacts/<yyyy-mm>/<tag>-NNNN.ndjson. Monthly rotation & size‑based file rolling.

  • artifact_list(tag, limit=50, order='desc', months_back=12) Read back the latest N artifacts for review/summarization/auditing.

  • kv_put(key, value, ttlSec?) / kv_get(key) (optional; Redis) Ephemeral cross‑step scratchpad & idempotency keys with TTL auto‑cleanup—handy for retries, rate limits, and multi‑turn handoffs.

TTL behavior & commands are a natural fit for ephemeral state (see Redis TTL docs).

Configuration

Copy .env.example → .env and adjust:

# Filesystem sandbox
SANDBOX_ROOT=./.sandbox

# Optional Redis for kv_* tools
REDIS_URL=redis://127.0.0.1:6379/0

# HTTP fetch safety
HTTP_ALLOWLIST=example.com, api.github.com
HTTP_TIMEOUT_SEC=10.0
HTTP_MAX_BYTES=2000000
LOG_LEVEL=INFO

# Streamable HTTP transport
MCP_HTTP_ENABLED=true
MCP_HTTP_HOST=127.0.0.1
MCP_HTTP_PORT=8080
MCP_HTTP_PATH=/mcp
MCP_HTTP_BEARER_TOKEN=change-me
MCP_HTTP_ALLOWED_ORIGINS=http://localhost, http://127.0.0.1
MCP_HTTP_ALLOW_NO_ORIGIN=true

Quick Start

Run stdio transport

make setup
cp .env.example .env
make run

Your agent (or an IDE like VS Code Agent Mode) can now launch this server as a subprocess and speak MCP over stdio. VS Code MCP docs: https://code.visualstudio.com/docs/copilot/customization/mcp-servers

Run HTTP transport

make setup
cp .env.example .env
# set a strong MCP_HTTP_BEARER_TOKEN in .env
make run-http

Client usage (JSON‑RPC 2.0, Authorization: Bearer <token>):

POST /mcp HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>
Origin: http://localhost

{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {} }

Then:

JSON{ "jsonrpc":"2.0","id":2,"method":"tools/list","params":{} }{ "jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"fs_write","arguments":{"path":"file.txt","content":"Hello"}} }

How Agents Use This Server

Discover tools via tools/list. Each tool includes an inputSchema (JSON Schema) that tells the agent how to validate arguments (see Tools spec). Plan (in the agent): break down the user goal into tool calls. Call tools via tools/call with {name, arguments} (validated JSON per schema). Assemble responses to produce the final answer.

Example pattern: validate → side‑effect → log

json_validate the payload → if invalid, auto‑repair and re‑validate. Perform side‑effect (http_fetch or fs_write). artifact_log outcome with a correlation ID (corr) for traceability.

Add a New Tool (Contributor Guide)

Your goal: add a tool once in the registry, and have it automatically appear in both transports.

  1. Choose a meaningful name Pick a short, snake_case identifier (e.g., csv_preview).
  2. Define the input model Create or update a file under server/tools/ with a Pydantic model containing only the input parameters and their validation constraints. Keep it thin—no business logic here.
# server/tools/csv_preview.py
from pydantic import BaseModel, Field

class CsvPreviewIn(BaseModel):
    path: str = Field(..., description="Relative path under sandbox root")
    max_rows: int = Field(20, ge=1, le=1000, description="Rows to preview")

  1. Implement the service logic Put business logic in app/services/…. For example, app/services/csv.py reading from the sandbox and returning the preview (rows & headers).
  2. Add a handler method Add a named method to ToolHandlers (in server/registry.py) that accepts the Pydantic input model and calls your service:
from server.tools.csv_preview import CsvPreviewIn
from app.services.csv import CsvService

class ToolHandlers:
    def __init__(self):
        self.container = build_container()
        self.csv_service = CsvService(self.container.fs_service)

    def csv_preview(self, args: CsvPreviewIn) -> dict:
        return self.csv_service.preview(args.path, args.max_rows)

  1. Register the tool Add a ToolSpec in build_tool_registry():
reg["csv_preview"] = ToolSpec(
    name="csv_preview",
    description="Preview a CSV file under sandbox root",
    input_model=CsvPreviewIn,
    handler=handlers.csv_preview,
)

  1. Tests

Add unit tests under tests/ to cover the service and handler behavior. For simple verification, test the service directly (no transport needed). Optionally add an HTTP integration test that POSTs tools/call with your tool.

  1. Docs

Update README “Tools Exposed” with your tool. Document any new env variables.

  1. Submit a PR

Run make test locally (ruff, black, pytest). Our GitHub Actions workflow runs the same on push/PR.

Testing, Linting, CI

Unit tests: pytest in tests/. Linters/formatters: ruff, black. Type checking: mypy. CI: .github/workflows/ci.yml runs make test on push/PR.

make test      # ruff + black --check + pytest
make format    # black
make typecheck # mypy

Observability & Auditing

Structured logs: you can wrap handler calls (in ToolHandlers) to log duration, errors, and arguments (with redaction). Artifacts: artifact_log / artifact_list provide a simple append‑only audit trail for outcomes and important events. Use semantic tags (orders:create, errors, plan) and correlation IDs (corr) to reconstruct runs.

Design Rationale

Single tool registry as the source of truth prevents drift between transports and aligns with MCP’s discover → call model (see Tools spec). Named handlers (not lambdas) improve readability, testability, and logging. Strict validation (Pydantic input models) surfaces accurate tool schemas to clients. HTTP safety follows MCP transport advice: Origin checks and auth mitigate DNS‑rebinding and unauthorized access (see Transports spec). KV optionality keeps the PoC lightweight but allows ephemeral idempotency, rate limiting, and multi‑turn scratchpad when needed.

Folder Structure

server/            # transports + registry (no business logic)
  main.py          # stdio entry (FastMCP)
  http_app.py      # Streamable HTTP entry (FastAPI)
  registry.py      # tool specs + handlers + dispatch/list helpers

server/tools/      # Pydantic input models only (thin)
  files.py, http_fetch.py, json_validate.py, artifacts.py, kv.py

app/               # "application" layer: config + services + DI
  config.py        # env settings
  di.py            # container wiring (services)
  logging.py       # redaction helpers
  services/        # business logic backing the tools
    filesystem.py, httpclient.py, validator.py, artifacts.py, kvstore.py

tests/             # pytest unit tests
scripts/           # setup/run/test scripts
.github/workflows/ # ci.yml (make test on push/PR)

FAQ

Q: Can I use this server directly from VS Code / Copilot Agent Mode? A: Yes. For stdio, VS Code can launch it as a subprocess. For HTTP, configure the URL and auth header; VS Code + other hosts can connect to remote MCP servers. See: https://code.visualstudio.com/docs/copilot/customization/mcp-servers Q: Does HTTP support streaming? A: The spec allows Streamable HTTP and optional SSE for streaming/server‑initiated messages. This PoC implements POST (non‑streaming) first; SSE can be added if you need server‑pushed updates. See Transports references. Q: Where should I put complex business rules? A: In services (e.g., app/services/...). Keep tool handlers thin and transport‑agnostic. Q: How do I disable Redis and KV tools? A: Leave REDIS_URL blank in .env. The registry registers kv_* only if Redis is configured.

References

MCP Transports (stdio, Streamable HTTP, SSE) Concepts: https://modelcontextprotocol.io/docs/concepts/transports Spec: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports

MCP Tools (list/call, schemas, content blocks) Spec: https://modelcontextprotocol.io/specification/2025-06-18/server/tools

JSON‑RPC used by MCP Guide: https://mcpcat.io/guides/understanding-json-rpc-protocol-mcp/

VS Code MCP Clients Docs: https://code.visualstudio.com/docs/copilot/customization/mcp-servers

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
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

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